1
votes

I have this problem while making a simple battleship game. Here is my code:

board = []
row = ['O'] * 5 #<<<<determine the board size here 
joined_O = '  '.join(row)


for i in range(5): #<<<<determine the board size here
    board.append(joined_O)
    print(joined_O)

from random import randint #<<<< this code is to determine where the ship is. It is placed randomly.
ship_row = randint(1,len(board))
ship_col = randint(1,len(board))

print(ship_row,', ',ship_col,'\n')

print('Shoot missile to the ship')
missile_row = int(input('row   : '))
missile_col = int(input('column: '))

#I really don't know where you're supposed to put the int() thingy so i put it everywhere
if int(missile_row) == int(ship_row) and int(missile_col) == int(ship_col):
    print("Congratulation! You've hit the ship.")
    break
elif int(missile_row) >= len(board) or int(missile_col) >= len(board):
    print('Sorry! Area is out of range.')
    break
else:
    print('Missile missed the target')
    board[int(missile_row)][int(missile_col)] = 'X'
    print(board)

I tried to reassign the 'O's where the missile hit with an 'X' but then it says

TypeError: 'str' object does not support item assignment.

2

2 Answers

3
votes
for i in range(5): #<<<<determine the board size here
    board.append(joined_O)

This doesn't look right to me. You should be appending lists to board, not strings. I'm guessing that you previously had something like:

for i in range(5):
    board.append(row)

Which would at least be the right type. But then you'd have weird bugs where five Xes appear instead of one whenever you miss a ship. This is because each row is the same row; making a change to one makes a change to all of them. You can avoid this by making a copy of the row each time using the slicing trick.

for i in range(5): #<<<<determine the board size here
    board.append(row[:])

Now your Xes should assign properly. But print(board) in your else block will be a bit ugly. You can format it nicely without brackets and quote marks using a couple quick joins:

else:
    print('Missile missed the target')
    board[int(missile_row)][int(missile_col)] = 'X'
    print("\n".join("  ".join(row) for row in board))

Now you've got some pretty nice output.

Shoot missile to the ship
row   : 1
column: 1
Missile missed the target
O  O  O  O  O
O  X  O  O  O
O  O  O  O  O
O  O  O  O  O
O  O  O  O  O
1
votes

Look at:

board = []
row = ['O'] * 5 #<<<<determine the board size here 
joined_O = '  '.join(row)
  • board is a list.
  • row is a list.
  • joined_O is a string formed by concatenating the elements of row.

AND:

for i in range(5):  #<<<<determine the board size here
    board.append(joined_O)
    print(joined_O)

board is now a list of strings

So

board[int(missile_row)][int(missile_col)] = 'X'

is not a valid command because it is trying to modify the string in board list instead of an element in a 2D list. In Python, strings are immutable, so you can't change their characters in-place.

In short, board is not a 2D list in your code, but a list of strings.