0

I am currently trying to program a game called Pah Tum. The game involves a board that is 7x7. For the board I just created a list with 7 lists containing 7 elements each, basically I just made each row into a list and merged them into a big list:

board = [[0, 0, 0, 0, 0, 0, 0],
         [0, 0, 0, 0, 0, 0, 0],
         [0, 0, 0, 0, 0, 0, 0],
         [0, 0, 0, 0, 0, 0, 0],
         [0, 0, 0, 0, 0, 0, 0],
         [0, 0, 0, 0, 0, 0, 0],
         [0, 0, 0, 0, 0, 0, 0]]

The game should have an undo function, which enables the player to go back one step. I thought I could just append the whole board into a seperate list and use that to go back a step.

        if input == 'u' or input == 'U':
            board = board_list[-1]
            del board_list[-1]

until here it works, but for some reason the board_list (the list I'm appending the current board to) always updates as a whole, meaning each element changes and becomes the new board.

eg. if I have

#board = [[0, 'B'], [0, 0]]
board_list.append(board)
.
.
.
#board = [[0, 'B'], [0, 'B']]
board_list.append(board)

after the first append I'd get

board_list = [[[0, 'B'], [0, 0]]]

and the second one leaves me with

board_list = [[[0, 'B'], [0, 'B']], [[0, 'B'], [0, 'B']]]

I have no idea why this happens. I searched for similar questions but I only see undo functions for canvases and I'm not sure if I can use them for this scenario.

No7Ex Q
  • 25
  • 3

2 Answers2

5

When you append board to board_list you're adding a reference to the original board. Perhaps a better option would be to add the previous state for the changed cell when you make a move:

moves.append([x, y, board[x][y]])

And then when you undo you reapply that state:

undo_move = moves[-1]
board[undo_move[0]][undo_move[1]] = undo_move[2]
del moves[-1]

Or more pythonically:

x, y, board[x][y] = moves.pop()

Alternatively, you could make a copy of the entire board and store that in the list instead.

Nick is tired
  • 6,860
  • 20
  • 39
  • 51
  • Ok I'll try to implement that. It shouldn't be a problem and thank you for the fast answer! – No7Ex Q Dec 16 '17 at 02:16
  • Ok, I tried using deepcopy and it did work, but i thought it would be better to implement your method, since that would make the 'moves' list not as big and it works. Thank you very much again. – No7Ex Q Dec 16 '17 at 02:31
  • 1
    Instead of those three undo lines you can simply do `x, y, board[x][y] = moves.pop()`. – Stefan Pochmann Dec 16 '17 at 03:03
  • @StefanPochmann Bah, of course you can, good point, I was thinking that all of the changes when performing operations like that occurred simultaneously, and so `x` and `y` would be undefined during the `board[x][y]` part when doing that, although after testing they are indeed set before `board[x][y]` is set to the last value – Nick is tired Dec 16 '17 at 03:04
  • @NickA Yeah, and I think this one is a particularly nice usage of that "trick". I'm glad you chose the right storage order :-) – Stefan Pochmann Dec 16 '17 at 03:22
0

In order to create a list of board copies you need to implement a deep copying method for your board class. Otherwise, all you're doing is copying the same pointer over and over. Python passes by reference and that's the source of your problem. Implement a new method which creates a new board with the same fields as your current board and return a pointer to that board from that method. I'd recommend reading some about shallow and deep copies. You can find more details here.

oBit91
  • 398
  • 1
  • 12
  • Unless the board class is doing something unusual, they don't need to implement a method at all; `copy.deepcopy` will "just work". – ShadowRanger Dec 16 '17 at 02:19
  • Indeed it should ^^ – oBit91 Dec 16 '17 at 02:22
  • Thank you as well for the quick answer, I tried implementing it and it worked I appreciate it! – No7Ex Q Dec 16 '17 at 02:33
  • My pleasure :) keep in mind that deep/shallow copying objects should always be thought of when giving copies of your objects to external users. Otherwise they can use the pointer you've given them to modify your objects without using your API. – oBit91 Dec 16 '17 at 02:44