Добавление значений в переменную-член Python - PullRequest
2 голосов
/ 20 марта 2020

Я новичок в Python и ОО-программировании в целом, и, пожалуйста, простите, вероятно, очень плохо разработанный код (любые советы будут с благодарностью).

В этом изобретенном MWE, который должен проиллюстрировать аналогичную проблему в моем более крупном проекте. Я хочу перебрать сетку 3x3 и заполнить ее так, чтобы она содержала все цифры 1-9, единственные значения, которые я могу изменить, - это значения, для которых в настоящий момент установлено значение 0, т. Е. Если сетка в настоящее время имеет цифры 1-7 и две позиции равны 0, тогда одна из этих 0 становится 8, а другая становится 9, в этом случае есть два решения, поскольку порядок 8 и 9 также можно поменять местами.

Я разработал решатель обратного отслеживания (runSolver ()), и это решает эту проблему, но я пытаюсь сохранить решения, когда достигну их. Я добавил оператор печати, когда решение достигнуто, и это распечатывает решение, как и ожидалось, затем я пытаюсь добавить это решение в список и вместо добавления только что найденного решения вместо этого добавляется исходное, нерешенное, grid.

class Grid:

    def __init__(self):
        self.grid = np.zeros((3, 3))

    def writeGrid(self, grid):
        self.grid = grid

    def printGrid(self):
        print(self.grid)

    def getValue(self, col, row):
        return self.grid[row][col]

    def setValue(self, col, row, num):
        self.grid[row][col] = num


class Solver:

    def __init__(self, grid):
        self.grid = grid
        self.solutions = []
        self.n_solutions = 0

    def isValid(self, num):
        for i in range(3):
            for j in range(3):
                if self.grid.getValue(i, j) == num:
                    return False
        return True

    def runSolver(self):
        for row in range(3):
            for col in range(3):
                if (self.grid.getValue(col, row)) == 0:
                    for num in range(1,10):
                        if self.isValid(num):
                            self.grid.setValue(col, row, num)
                            self.runSolver()
                            self.grid.setValue(col, row, 0)
                    return
        self.grid.printGrid()             # this line prints the actual solutions when reached (it works)
        self.solutions.append(self.grid)  # this should append the solution to 'solutions'
        self.n_solutions += 1             # keeps track of how many solutions there are

Основная функция, которая фактически показывает проблему, заключается в следующем:

# Set up game
gameGrid = Grid()
gameGrid.writeGrid([[1, 4, 5],
                    [0, 6, 0],
                    [7, 8, 9]])
solverGrid = Solver(gameGrid)

# Run the solver
solverGrid.runSolver()

# This should print out the found solutions, 
# It actually prints out the initial, unsolved, grid twice
for i in range(solverGrid.n_solutions):
    solverGrid.solutions[i].printGrid()

Из некоторых поисков в Интернете я думаю, что я могу запутаться между атрибутами экземпляра и атрибутами класса и область, с которой они доступны, однако я действительно не уверен.

1 Ответ

1 голос
/ 20 марта 2020

Когда вы запускаете self.solutions.append(self.grid), вы просто добавляете ссылку к self.grid к self.solutions. Таким образом, в конце вашего runSolver у вас есть список ссылок в self.solutions, которые все указывают на один и тот же объект.

Это связано с тем фактом, что ваш Grid объект и Numpy массивы изменяемые объекты. В отличие от строк Python, например, когда вы изменяете их (например, с self.grid.setValue(col, row, num)), один и тот же объект изменяется на месте вместо создания нового объекта.

Здесь та же проблема иллюстрируется списком списков:

>>> l = []
>>> x = [1]
>>> l.append(x)
>>> l
[[1]]
>>> x.append(2)
>>> l.append(x)
>>> l
[[1, 2], [1, 2]]

Вам нужно будет создавать копию сетки каждый раз, когда вы добавляете ее в self.solutions, чтобы вы могли иметь «снимок» сетки в ее виде был в тот момент.

Вы могли бы сделать что-то вроде этого:

class Grid:

    def __init__(self, grid=None):
        if grid == None:
            self.grid = np.zeros((3, 3))
        else:
             # Copy the array, otherwise we'll have the same mutability issue as above.
            self.grid = np.copy(grid)

В runSolver:

        grid_copy = Grid(self.grid.grid)
        self.solutions.append(grid_copy) # this should append the solution to 'solutions'
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...