1

我正在开发一款 2048 游戏并尝试构建一个停止条件。但是面临两个变量的一些问题。我尝试的想法很简单——当两个矩阵值(一个保存当前 4x4 板值,另一个保存上一步的值)彼此相等时停止执行。

所以基本上代码是这样的。

import numpy as np
import random

class Board():
    def __init__(self):
        self.board = np.zeros((4,4), dtype = np.int)
        self.prev_board = np.zeros((4,4), dtype = np.int)
        self.new_game()
        print("New Board Created")
        self.newgame = False

    def new_game(self):
        for cnt in range(2):
            i = random.randint(0,3)
            j = random.randint(0,3)
            self.board[i][j] = random.choice([2,4])

    def populate(self):
        empty = []
        for i in range(4):
            for j in range(4):
                if self.board[i][j] == 0:
                    empty.append([i,j])

        i,j = random.choice(empty)
        self.board[i][j] = random.choice([2,4])

    def move(self,board):
        k = 0
        for row in board:
            new_col = np.zeros(len(row), dtype=row.dtype)
            j = 0
            previous = None
            for i in range(row.size):
                if row[i] != 0:
                    if previous == None:
                        previous = row[i]
                    else:
                        if previous == row[i]:
                            new_col[j] = 2 * row[i]
                            j += 1
                            previous = None
                        else:
                            new_col[j] = previous
                            j += 1
                            previous = row[i]
            if previous != None:
                new_col[j] = previous  

            board[k] = new_col
            k += 1
        return board

    def next_move(self,direction):
        rotated_board = np.rot90(self.board, direction)
        rotated_board = self.move(rotated_board)
        self.board = np.rot90(rotated_board, -direction)

    def play_game(self,direction):
        self.next_move(direction)
        self.prev_board = self.board
        print("Before populate")
        print(self.prev_board)
        self.populate()
        print("After populate")
        print(self.prev_board)

game = Board()
for i in range(2):
    game.play_game(0)

这是执行游戏的一个步骤的方法,并且该方法被重复调用,直到获得上面提到的停止标准。问题是当我尝试这种方式时, self.prev_board 值在调用 self.populate() 之前和之后发生变化。只是不明白发生了什么。

输出是,

Before populate
[[0 0 0 0]
 [2 0 0 0]
 [0 0 0 0]
 [2 0 0 0]]
After populate
[[0 0 0 0]
 [2 0 0 0]
 [0 0 0 0]
 [2 0 4 0]]
Before populate
[[0 0 0 0]
 [2 0 0 0]
 [0 0 0 0]
 [2 4 0 0]]
After populate
[[0 0 0 0]
 [2 0 2 0]
 [0 0 0 0]
 [2 4 0 0]]

PS:self.next_move(direction) - 进行下一步移动,self.populate() - 在矩阵中填充一个新的随机值。

4

2 回答 2

0

如果我理解正确,当您尝试将self.board变量复制到self.prev_board. Python 在两个变量之间传递时默认使用“按引用传递”模式。所以任何改变self.board也会改变self.prev_board。它并没有真正复制价值,而只是链接

[:]您可以通过 put或 use copyordeepcopy来避免它。

 def play_game(self,direction):
        self.next_move(direction)
        self.prev_board = self.board[:]
        print(self.prev_board)
        self.populate()

        print(self.prev_board)

使用深拷贝:

from copy import deepcopy

def play_game(self,direction):
        self.next_move(direction)
        self.prev_board = deepcopy(self.board)
        print(self.prev_board)
        self.populate()

        print(self.prev_board)
于 2018-03-02T02:21:49.153 回答
0

https://docs.python.org/2/library/copy.html

Python 中的赋值语句不复制对象,它们在目标和对象之间创建绑定。对于可变或包含可变项的集合,有时需要一个副本,以便可以更改一个副本而不更改另一个副本。这个模块提供了通用的浅拷贝和深拷贝操作(解释如下)。

接口总结:

copy.copy(x) 返回 x 的浅拷贝。

copy.deepcopy(x) 返回 x 的深层副本。

请仔细阅读上面的链接,这应该有助于解决您的问题

于 2018-03-02T02:20:51.203 回答