2013-07-23 40 views
0

我正在改造我的战列舰游戏,我有一个名为SEA的常量变量,它包含一个空板。然而,变量正在被修改,我不知道为什么(或在哪里)。我怀疑它是通过引用传递给player_board的,当player_board被修改时,SEA也是如此。我如何阻止这种情况发生?这是我的代码。你会在底部看到我打印出SEA,并且它已被修改。恒定变量正在改变

from random import randint 
#Constants and globals 
OCEAN = "O" 
FIRE = "X" 
HIT = "*" 
SIZE = 10 
SHIPS = [5, 4, 3, 3, 2] 
player_radar = [] 
player_board = [] 
player_ships = [] 
ai_radar = [] 
ai_board = [] 
ai_ships = [] 

#Classes 
class Ship(object): 
    def set_board(self, b): 
     self.ship_board = b 
    def edit(self, row, col, x): 
     self.ship_board[row][col] = x 
    def __repre__(self): 
     return self.ship_board 

#Set up variables 
last_ship = Ship() #Holds the last ship made in make_ship() 
SEA = [] # Blank Board 
for x in range(SIZE): 
    SEA.append([OCEAN] * SIZE) 

#Functions 
def print_board(): 
    for row in range(SIZE): 
     print " ".join(player_radar[row]), "||" , " ".join(player_board[row]) 

def random_row(is_vertical, size): 
    if is_vertical: 
     return randint(0, SIZE - size) 
    else: 
     return randint(0, SIZE -1) 

def random_col(is_vertical, size): 
    if is_vertical: 
     return randint(0, SIZE - 1) 
    else: 
     return randint(size-1, SIZE -1) 

def exists(row, col, b): # true if ocean 
    if row < 0 or row >= SIZE: 
     return 0 
    elif col < 0 or col >= SIZE: 
     return 0 
    if b[row][col] == OCEAN: 
     return 1 
    else: 
     return 0 

def make_ship(size, board): 
    #Find an unoccupied spot, then place ship on board 
    #Also put ship in last_ship 
    temp = [] 
    temp = board 
    is_vertical = randint(0, 1) # vertical ship if true 
    occupied = True 
    while(occupied): 
     occupied = False 
     ship_row = random_row(is_vertical, size) 
     ship_col = random_col(is_vertical, size) 
     if is_vertical: 
      for p in range(size): 
       if not exists(ship_row+p, ship_col, temp): 
        occupied = True 
     else: 
      for p in range(size): 
       if not exists(ship_row, ship_col-p, temp): 
        occupied = True 
    #Place ship on boards 
    last_ship.set_board(SEA) 
    if is_vertical: 
     last_ship.edit(ship_row, ship_col, "^") 
     last_ship.edit(ship_row+size-1, ship_col, "v") 
     temp[ship_row][ship_col] = "^" 
     temp[ship_row+size-1][ship_col] = "v" 
     for p in range(size -2): 
      last_ship.edit(ship_row+p+1, ship_col, "+") 
      temp[ship_row+p+1][ship_col] = "+" 
    else: 
     last_ship.edit(ship_row, ship_col, ">") 
     last_ship.edit(ship_row, ship_col-size+1, "<") 
     temp[ship_row][ship_col] = ">" 
     temp[ship_row][ship_col-size+1] = "<" 
     for p in range(size -2): 
      last_ship.edit(ship_row, ship_col-p-1, "+") 
      temp[ship_row][ship_col-p-1] = "+" 
    return temp 

# Make the boards 
player_radar = SEA 
player_board = SEA 
ai_radar = SEA 
ai_board = SEA 
print_board() 
for x in SHIPS: 
    player_board = make_ship(x, player_board) 
    #player_ships.append(last_ship) 
    #ai_board = make_ship(x, ai_board) 
    #ai_ships.append(last_ship) 

print "Let's play Battleship!" 
for row in range(SIZE): 
    print " ".join(SEA[row]) 
+4

http://docs.python.org/2/library/copy.html http://stackoverflow.com/questions/9935372/copying-list-in-python-deep-vs-shallow-copy-疑难杂症换我 - 在 - python的 http://stackoverflow.com/questions/14028164/python-lists-copying-is-it-deep-copy-or-shallow-copy-and-how-is-it -done – seth

回答

4

SEA及其成员名单,并在Python列表是可变的。当你说player_radar = SEA等,你没有复制SEA;你正在对它做一个新的参考。您对player_radar所做的任何更改都将反映在SEA中。

copy.deepcopy经常用于递归复制嵌套可变数据结构。但个人而言,我更喜欢复制我知道我需要的图层数量。例如,为了使名单及其所有成员名单的副本,你可以这样做:

player_radar = [sublist[:] for sublist in SEA] 

这是一个list comprehension。每个子列表都使用[:]进行复制,这会对每个列表进行浅度复制。

+0

如果你想要列表等的副本,请使用['copy.deepcopy'](http://docs.python.org/2/library/copy.html)来确保你真的已经复制了所有级别。 – 9000

+0

@ 9000:不一定。如果您将列表列表视为二维列表,则您经常需要制作子列表的副本,但不是子列表的元素的副本。 – user2357112

+0

详细阐述了这一点。 – Taymon

1

SEA是一个列表,所以做它的一个副本:它

player_radar = SEA[:] 
player_board = SEA[:] 
ai_radar = SEA[:] 
ai_board = SEA[:] 

或更深的副本,如果你需要。编辑:通过“更深的副本”,我的意思是,如果你的列表包含,例如,其他列表,然后只是做一个顶级副本将创建一个新的列表,但其成员将引用相同的成员您的原始列表已经存在,因此要创建一个深层副本,您还需要制作这些成员的副本。

举例说明:

>>> list1 = [[1,2,3]] 
>>> list2 = list1[:] # Make a shallow copy 
>>> print(list1) 
[[1,2,3]] 
>>> print(list2) 
[[1,2,3]] 
>>> list2[0][0] = 4  # Also changing list1's first member, here 
>>> print(list2) 
[[4,2,3]] 
>>> print(list1) 
[[4,2,3]]    # So list1 has also changed. 
+0

你能解释一份副本和一份更深的副本之间的区别吗? – Dbz

+1

我觉得'[:]'在这里是不够的,请使用'copy.deepcopy'。 –

+0

@Dbz http://stackoverflow.com/questions/17599175/python-list-and/17599215#17599215 –

0

Python变量是事物的名称,而不是放置东西的地方。

player_radar = SEA 

不作player_radar副本SEA,像它会在,比方说,C++。相反,player_radarSEA都是同一个列表对象的名称。如果更改player_radar,您将看到SEA上的更改以及引用同一对象的所有其他变量。

+0

在C++中,'player_radar'和'SEA'都只是指针。 – 9000

+0

@ 9000:只有当你将它们声明为“指针”而“新”时,才会使用它们而不是像'vector >'这样的东西。 – user2357112

+0

此外,无论何时您使用指针成员变量为C++类编写复制构造函数或赋值运算符,都有非常类似的问题需要处理,即是否只是复制指针(通常不是,但有时候是这样)或者你想制作它指向的东西的副本,并指出这一点。 –