Return all possible placements of buildings in a city grid using backtracking

Question:

I have two inputs

An NxM city grid where empty spaces represent vacant lots, and X’s represent filled lots

e.g

X XXX 
 X  X
XXXX 
 XX X

This is in the format List[List[str]]

And an integer that represents the number of buildings required.

Return a list of all possible placements, i.e. List[List[List[str]]]

for example, a possible result using the map above and number of buildings required = 3

XBXXX
BXB X
XXXX 
 XX X

another would be

X XXX 
 X  X
XXXXB
BXXBX

If the number of buildings required > vacant lot count, return an appropriate error

I’ve tried backtracking. Below is my attempt at a solution, but the ‘current_city_map’ can’t keep track of the state one level up, as in when the ‘find_permutations’ returns when building_count = 0, the current city map still has the maximum building count already on it


`def can_place_building(xPos, yPos, city_map, building_code):
    return city_map[yPos][xPos] == ' ':


def find_permutations(initial_city_map, current_city_map, building_code, required_building_count, possible_combinations):
    if required_building_count == 0:
        possible_combinations.append(current_city_map)
        return
    for x in range(len(current_city_map[0])):
        for y in range(len(current_city_map)):
            if can_place_building(x, y, current_city_map, building_code):
                current_city_map[y][x] = building_code
                find_permutations(initial_city_map, current_city_map, building_code, required_building_count - 1, possible_combinations)


def find_possible_combinations(initial_city_map, required_building_count: int) -> List:
    building_code = 'B'
    possible_combinations = []
    current_city_map = copy.deepcopy(initial_city_map)
    find_permutations(initial_city_map, current_city_map, building_code, required_building_count, possible_combinations)
    return possible_combinations`

Asked By: Baeby

||

Answers:

find_permutations doesn’t take in required_building_count where it’s defined.

def find_permutations(initial_city_map, current_city_map, building_code, possible_combinations):

ought to be

def find_permutations(initial_city_map, current_city_map, building_code, required_building_count, possible_combinations):

Unless python is magic and my inexperience is showing 🙂

Edit: This probably should have been a comment, not an answer. My bad.

Answered By: lckcorsi

Instead of having current and initial city maps, I would suggest having just the initial one, and passing a copy to the recursive function. So, instead of:

current_city_map[y][x] = building_code

find_permutations(initial_city_map, current_city_map, building_code, required_building_count – 1, possible_combinations)

you’d do something like:

temp_map = copy.deepcopy(initial_city_map)
temp_map[y][x] = building_code
find_permutations(temp_map, building_code, required_building_count – 1, possible_combinations)

Edit: The way you’re doing it currently just keeps editing the same current_city_map, so it never removes the buildings you add to it in the first run. You could maybe try just reverting it to initial_city_map somewhere along the way, as was your initial intention as far as I can tell, but that seems needlessly complicated. This should be cleaner.

Answered By: lckcorsi