2015-07-26 3 views
5

Я понимаю, что обычно работает доступ к элементам в списке списков. Я знаю, что если у вас есть список L = [['a', 'b'], ['c', d'],['e', 'f']], вы можете получить доступ к 'a', используя L[0][0]. Тем не менее, я не знаю, почему то же самое не работают в следующем коде линкора игры:Не удается выяснить, как переназначить элемент в списке списков в этом коде Python

from random import randint 
from random import choice 

# make a 5x5 board 
board = [] 
row = ['O']*5 
for x in range(5): 
    board.append(row) 

def print_board(): 
    for item in board: 
     print ' '.join(item) 

#check if input falls within 5x5 grid 
def check_valid(guess_row, guess_column): 
    return guess_row in range(5) and guess_column in range(5) 
#return True- is valid choice, return False- not valid choice 

#check that the input hasn't been guessed previously 
def check_repeat(guess_row, guess_column): 
    return board[guess_row][guess_column] != 'O' 
#return True- repeat, reurn False- new 

#check if input is a correct answer 
def check_correct(guess_row, guess_column): 
    return (guess_row, guess_column) == (row1, col1) or (guess_row, guess_column) == (row2, col2) 
#return True- is correct, return False- is not correct 

#place a 2-position ship 
while True: 
    #pick random place to start 
    row1 = randint(0,4) 
    col1 = randint(0,4) 
    #choose adjacent second position 
    move_direction = choice(['north', 'south', 'east', 'west']) 
    if move_direction == 'north': 
     row2 = row1 - 1 
     col2 = col1 
    elif move_direction == 'south': 
     row2 = row1 + 1 
     col2 = col1 
    elif move_direction == 'east': 
     row2 = row1 
     col2 = col1 + 1 
    else: # must be west 
     row2 = row1 
     col2 = col1 - 1 
    #check that the second position is valid, else pick new values 
    if row2 in range(5) and col2 in range(5): 
     break 
positions_left = 2 #how many points player needs to hit 
#you now have a ship at coordinates (row1, col1), (row2, col2) 

turns = 5 

#the gameflow itself: 
print 'let\'s play battleship!' 
while turns > 0: 
    print 'You have %i turns remaining.' % turns 
    print_board() 
    guess_row = int(raw_input('Guess a row: ')) - 1 #-1 to account for python 0-indexing 
    guess_column = int(raw_input('Guess a column: ')) - 1 

    if check_valid(guess_row, guess_column) == False: 
     print 'Sorry, those aren\'t valid coordinates' 
    else: #continue game if valid 
     turns -= 1 
     if check_repeat(guess_row, guess_column): #old guess 
      print 'You seem to have guessed that already.' 
      turns += 1 #don't count this turn 
     elif check_correct(guess_row, guess_column): 
      print 'Hit!' 
      board[guess_row][guess_column] = '!' 
      positions_left -= 1 
      if positions_left == 0: 
       'You sunk the battleship!' 
       turns = 0 #stops game 
      else: 
       print 'You can sink this ship in %i more hits!' % positions_left 
     else: 
      board[guess_row][guess_column] = 'X' 
      print 'Sorry, you missed!' 

Проблема возникает, когда после оценки догадки игрока, я пытаюсь переназначить «O» либо ' !» (с указанием удара) или «X» (с указанием промаха). Это должно произойти в:

elif check_correct(guess_row, guess_column): 
       print 'Hit!' 
       board[guess_row][guess_column] = '!' 

и на сайте:

else: 
     board[guess_row][guess_column] = 'X' 
     print 'Sorry, you missed!' 

Вместо того, что происходит, вся колонна заканчивается переподчиняемых к этому значению. Поэтому, когда игрок угадывает строку 1, столбец 1, эта догадка интерпретируется как guess_row = 0, guess_column = 0. Я ожидаю, что новое значение поля, то, чтобы превратиться в:

[['X', 'O', 'O', 'O', 'O'], ['O', 'O', 'O', 'O', 'O'],['O', 'O', 'O', 'O', 
'O'],['O', 'O', 'O', 'O', 'O'],['O', 'O', 'O', 'O', 'O']] 

Вместо этого он становится:

[['X', 'O', 'O', 'O', 'O'],['X', 'O', 'O', 'O', 'O'],['X', 'O', 'O', 'O', 
'O'],['X', 'O', 'O', 'O', 'O'],['X', 'O', 'O', 'O', 'O']] 

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

ответ

2

Проблема в том, что вы добавляете такую ​​же переменную row на каждой итерации в свою доску. Вы должны добавить новую строку вместо следующим образом:

board = [] 
for _ in range(5): 
    board.append(['O'] * 5) 
+0

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

+0

Поскольку вы создали в основном список из 5 ссылок, указывающих на одну и ту же переменную с именем 'row', * другими словами, у вас нет 5 разных строк, у вас есть одна строка, добавленная 5 раз в доску *, поэтому, когда вы внести изменения в один из них, все остальные будут затронуты, поскольку все они ссылаются на одно и то же. – ozgur

1

Ваша проблема здесь:

row = ['O']*5 
for x in range(5): 
    board.append(row) 

В результате вышеуказанной платы будет содержать 5 ссылок грести, то есть тот же список. Таким образом, измените одно существо, измените весь файл. Вам нужно сделать копии строки, например.

for x in range(5): 
    board.append(row[:]) 

Надеюсь, что это поможет.