2015-07-26 16 views
5

Capisco che di solito l'accesso agli elementi in un elenco di elenchi funziona. So che se hai una lista L = [['a', 'b'], ['c', d'],['e', 'f']], puoi accedere a 'a' utilizzando L[0][0]. Eppure, io non sono sicuro perché la stessa cosa non funziona nel seguente codice corazzata gioco:Impossibile capire come riassegnare un elemento in un elenco di elenchi in questo codice 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!' 

Il problema si verifica in cui dopo aver valutato ipotesi del giocatore, cerco di riassegnare la 'O' a uno ' !' (indicando un colpo) o "X" (che indica una mancanza). Questo dovrebbe accadere in:

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

ea:

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

Invece, ciò che accade è l'intera colonna finisce per essere riassegnato a quel valore. Quindi, quando un giocatore indovina la riga 1, colonna 1, tale ipotesi viene interpretata come guess_row = 0, guess_column = 0. Mi aspetto che il nuovo valore di consiglio poi di trasformarsi in:

[['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']] 

Invece diventa:

[['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']] 

E 'davvero strano perché quando tiro fuori piccoli frammenti di codice e cercare di fare proprio questo cosa, funziona bene, ma non vedo cosa mi manca quando provo a farlo come parte dell'intero codice.

risposta

2

Il problema è che si aggiunge la stessa variabile row a ogni iterazione nella scheda. Si dovrebbe aggiungere una nuova riga invece come segue:

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

grazie che sembrava funzionare! Non capisco perché però ... perché è importante quale metodo si usa per creare la tavola originale? Non importa come sia stata costruita la scacchiera, non dovresti cambiare i valori in essa contenuti in seguito allo stesso modo? –

+0

Perché ciò che hai creato è fondamentalmente un elenco di 5 riferimenti che puntano alla stessa variabile chiamata 'row', * in altre parole, non hai 5 righe diverse, hai una riga aggiunta 5 volte in una board *, quindi quando apportare un cambiamento in uno di essi, tutti gli altri saranno interessati dal momento che sono tutti riferimenti alla stessa cosa. – ozgur

1

Il tuo problema è qui:

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

A seguito del consiglio di amministrazione di cui sopra conterrà 5 riferimenti a remare, vale a dire lo stesso elenco. Così cambia uno sussiste, cambierà tutto il file. Devi fare copie della riga, ad es.

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

Spero che questo aiuti.