2013-07-23 3 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에 대한 gotcha http://stackoverflow.com/questions/14028164/python-lists-copying-is-it-deep-copy-or-shallow-copy-and-how-is-it -done – seth

답변

4

SEA을하고 회원 목록이며, 파이썬에서 목록을 변경할 수 있습니다

는 설명합니다. 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 : 꼭 그런 것은 아닙니다. 목록을 2 차원 목록으로 취급하는 경우 하위 목록의 사본은 만들지 만 하위 목록의 요소는 복사하지 않는 것이 좋습니다. – user2357112

+0

이것에 정교합니다. – Taymon

1

SEA는 목록, 그래서 그것의 복사본을 만들 : 당신이 필요로하는 경우, 그것의

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

또는 깊은 사본을.

EDIT : "더 깊은 사본"이란 귀하의 목록에 다른 목록이 포함되어 있다면 최상위 사본을 만들면 새로운 목록이 만들어 지지만 그 구성원은 같은 구성원에 대한 참조가됩니다. 원본 목록이 있었기 때문에 전체 복사본을 만들려면 해당 구성원의 복사본을 만들어야합니다.

>>> 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

파이썬 변수는 물건을 넣을 장소가 아니라 물건의 이름입니다. 그것은 말하자면, C++,에서와 같은

player_radar = SEA 

SEAplayer_radar에게 카피를 작성하지 않습니다. 오히려 player_radarSEA은 모두 같은 목록 개체의 이름입니다. player_radar을 변경하면 SEA 및 동일한 개체를 참조하는 다른 모든 변수에 변경 사항이 표시됩니다.

+0

C++에서'player_radar'와'SEA'는 단지 포인터 일뿐입니다. – 9000

+0

@ 9000 : 포인터로 선언하고'vector '과 같은 것을 사용하는 대신'new'로 지정했을 경우에만. – user2357112

+0

또한 포인터 멤버 변수를 사용하여 C++ 클래스의 복사 생성자 또는 대입 연산자를 작성하면 대처할 때와 비슷한 문제가 발생합니다. 즉 포인터를 복사하려는 경우 (대개는 아니지만 가끔씩) 또는 그것이 가리키는 것의 사본을 만들고 그것을 가리 키기를 원하십니까? –

관련 문제