Extra Credit


I am trying to make a multiple boat battleship. For some reason, the code doesn't stop once you've hit all of the ships? Why is that and what is the solution. The problem is in the if statement at the bottom where it talks about all of the correctness.

from random import randint

board = []

for x in range(2):
board.append(["O"] * 2)

def print_board(board):
for row in board:
print " ".join(row)

print "Let's play Battleship!"

def random_row_a(board):
a = randint(0, len(board) - 1)

def random_col_a(board):
a = randint(0, len(board[0]) - 1)

def random_row_b(board):
b = randint(0, len(board) - 1)

def random_col_b(board):
b = randint(0, len(board[0]) - 1)

ship_row_a = random_row_a(board)
ship_col_a = random_col_a(board)
ship_row_b = random_row_b(board)
ship_col_b = random_col_b(board)
print ship_row_a
print ship_col_a
print ship_row_b
print ship_col_b

for turn in range(15):
guess_row = int(raw_input("Guess Row of a ship:"))
guess_col = int(raw_input("Guess Col of a ship:"))

if guess_row == ship_row_a and guess_col == ship_col_a:
    print "Congratulations! You sunk Ship A!"
    ship_row_a and ship_col_a = guessed
    board[ship_row_a][ship_col_a] = "W"
elif guess_row == ship_row_b and guess_col == ship_col_b:
    print "Comgratulations! You sunk Ship B!"
    ship_row_b and ship_col_b = guessed
    board[ship_row_b][ship_col_b] = "W"
elif ship_row_a and ship_col_a and ship_row_b and ship_col_b == 'W':
    print('Congratulations! You won!')
    if (guess_row < 0 or guess_row > 2) or (guess_col < 0 or guess_col > 2):
        print "Oops, that's not even in the ocean."
    elif(board[guess_row][guess_col] == "X"):
        print "You guessed that one already."
        print "You missed my battleship!"
        board[guess_row][guess_col] = "X"
    if turn == 15:
        print('Game Over')
print(turn + 1)


The above is redundant. Use your random_row as a utility function to generate both cases.

There is a larger concern...

This case should be considered the top of the heap and be tested first. You will need to straighten out the logic pointed out above.


What would you recommend doing for the final win part? I did my best to fix the different functions.


Did you fix the line I pointed out? Study this example for a clue of what is happening:

>>> A = 'w'
>>> B = 'w'
>>> C = 'w'
>>> print (A and B and C == 'w')
>>> A = "x"
>>> print (A and B and C == 'w')

A does not equal 'w' yet the above yields True. That is because A is defined as a non-empty string, so casts to True in a conditional. An empty string will not be cast so the conditional yields None (nothing is printed):

>>> A = ""
>>> print (A and B and C == 'w')


None is not True, so will revert to the next operand in an or expression.

>>> A = "" or False
>>> print (A and B and C == 'w')

The only conclusion we can draw from all this is that each operand in your and expression needs to be a conditional if it is to yield correctly.

    if A == 'w' and B == 'w' and C == 'w':
        # will only be True if all operands are True

I only used capital single letters for clarity and brevity. Normally we only use capitals on Python classes.

But this raises another question, aren't we examining coordinates (sort of) row and column? Since the board is a list,

if board[row_a][col_a] == 'W' and board[row_b][col_b] == 'W':

So this illustrates the syntax, but really not much else when you think of it.

How do we determine a hit and also if the other ship is already gone? If you examine your code you'll see that it takes another turn (iteration) to elif to the above conditional. It should be happening immediately when the second ship is destroyed.

One possible solution is to keep the ships in a list. That would facilitate wrapping up a win in a single conditional.

First, let's segue to the utility function for generating randoms. We only need one function. It can be a pure function which return value is defined by the variable it is assigned to. The following assumes a square board.

ships = [randint(0, len(board) - 1) for k in range(len(board))]

Which generates list,

>>> ships = [randint(0, len(board) - 1) for k in range(4)]
>>> ships
[0, 0, 2, 4]

There is probably a fancier or more sensible way to reduce this, but here is what we're after...

>>> temp = ships[:]
>>> ships = []
>>> for i in range(int(len(temp)/2)):
	ships.append([temp[i*2], temp[i*2+1]])

>>> ships
[[0, 0], [2, 4]]
>>> temp = None

We have not really got anywhere, yet, but may I think you might be getting the picture?


Yeah, I got it.Thanks.


This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.