Multiple Ships Troubleshooting

python
battleship

#1

I’m trying to start slow and build just one extra ship. the error I am getting is Traceback (most recent call last):
File “python”, line 46, in
NameError: name ‘shipa_row’ is not defined

I am trying to go step-by-step, so I would like to just solve for this particular issue. I’ve attached a screengrab of the code. Can someone help me understand why shipa_row is not defined?


How to add labels in battleship
Adding multiple ships
#2

Screenshots are okay for showing output, and perhaps error messages, but nothing can replace raw code when it comes to reading and testing. For best response, please post code, and even a lesson link for testing purposes. Thanks.

One problem we can see you attempting to overcome is duplication of ship position. When generating random numbers between 0 and 4 it’s very expected that duplication could occur. But what about two random numbers between 0 and 24? The probability of two random numbers in that range being the same when generated back to back is very low.

a = randint(0, 24)
while True:
    b = randint(0, 24)
    if b != a: break

shipa_row = int(a / 5)
shipa_col = a % 5
shipb_row = int(b / 5)
shipb_col = b % 5

We can further simplify this by storing coordinates in tuples.

shipa = (int(a / 5), a %5)
shipb = (int(b / 5), b %5)

ship_status = [True, True]

while True in ship_status:

    while True:
        guess = (int(raw_input('row: ')), int(raw_input('col: '))
        if guess[0] in range(5) and guess[1] in range(5): break

    # Now for testing...

    if guess == shipa:
        print "You have sunk Ship A"
        ship_status[0] = False
    else if guess == shipb:
        print "You have sunk Ship B"
        ship_status[1] = False

print "You have won the game!"

These are untested ideas, mind, but in theory they should work.


#3

Hi – thanks for the reply! I’ll try to block the code in from now on.

I started this exercise before I learned the “while”/loops, so I updated to be a while statement. The code I wrote was successfully generating non-conflicting coordinates, and printing them for my QA, but was falling flat when I put in place an if condition to test if the guess was equal to the coordinates. I understand what you did in your generation…and realize that the way I’ve defined it they can never be on the same row or column, but I’m still not sure I understand all of the syntax used for the tuples yet.

Is the fact that I had the code redefine the variables in order to avoid duplicate positions the issue? I feel like because they are defined and printing, it should know what the variable was?

Thanks again!

from random import randint
board = [] 

# here is where I build my board

for x in range(0, 5):
  board.append(["O"] * 5)

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

print_board(board)

# here is where I build my ships

def random_row(board):
  return randint(0, len(board) - 1)

def random_col(board):
  return randint(0, len(board[0]) - 1)

# i have two ships, A and B

def ships(board):
  shipa_row = random_row(board)
  shipa_col = random_col(board)
  shipb_row = random_row(board)
  shipb_col = random_col(board)
  while shipa_row == shipb_row:
    shipb_row = random_col(board)
  while shipa_col == shipb_col:
    shipb_col = random_col(board)
  print "Ship A: ",shipa_row,", ",shipa_col
  print "Ship B: ",shipb_row,", ",shipb_col

ships(board)
  
# the game loop
for turn in range(4):
  print
  print "Turn", turn + 1
  guess_row = int(raw_input("Guess Row: "))
  guess_col = int(raw_input("Guess Col: "))

  if (guess_row == shipa_row and guess_col == shipa_col) or \ # getting an error message for this line that says shipa_row is not defined
    (guess_row == shipb_row and guess_col == shipb_col):
    print "Congratulations! You sank my battleship!" 
    break


#4

Nevermind! I figured it out. I did not define my rows and columns as global variables. :slight_smile:


#5
tuples version test run
================ RESTART: D:/cc/discuss/battleship_tuples.py ================
Let's play Battleship!
O O O O O
O O O O O
O O O O O
O O O O O
O O O O O
row: 3
col: 3
O O O O O
O O O O O
O O O O O
O O O X O
O O O O O
row: 2
col: 2
O O O O O
O O O O O
O O X O O
O O O X O
O O O O O
row: 1
col: 1
O O O O O
O X O O O
O O X O O
O O O X O
O O O O O
row: 0
col: 0
X O O O O
O X O O O
O O X O O
O O O X O
O O O O O
row: 4
col: 4
X O O O O
O X O O O
O O X O O
O O O X O
O O O O X
row: 0
col: 4
X O O O X
O X O O O
O O X O O
O O O X O
O O O O X
row: 1
col: 3
X O O O X
O X O X O
O O X O O
O O O X O
O O O O X
row: 3
col: 1
X O O O X
O X O X O
O O X O O
O X O X O
O O O O X
row: 4
col: 0
X O O O X
O X O X O
O O X O O
O X O X O
X O O O X
row: 0
col: 0
You guessed that one already
row: 0
col: 1
X X O O X
O X O X O
O O X O O
O X O X O
X O O O X
row: 0
col: 2
X X X O X
O X O X O
O O X O O
O X O X O
X O O O X
row: 0
col: 3
X X X X X
O X O X O
O O X O O
O X O X O
X O O O X
row: 1
col: 1
You guessed that one already
row: 4
col: 1
X X X X X
O X O X O
O O X O O
O X O X O
X X O O X
row: 4
col: 2
X X X X X
O X O X O
O O X O O
O X O X O
X X X O X
row: 4
col: 3
X X X X X
O X O X O
O O X O O
O X O X O
X X X X X
row: 1
col: 0
X X X X X
X X O X O
O O X O O
O X O X O
X X X X X
row: 1
col: 2
X X X X X
X X X X O
O O X O O
O X O X O
X X X X X
row: 1
col: 4
X X X X X
X X X X X
O O X O O
O X O X O
X X X X X
row: 2
col: 0
X X X X X
X X X X X
X O X O O
O X O X O
X X X X X
row: 2
col: 1
X X X X X
X X X X X
X X X O O
O X O X O
X X X X X
row: 2
col: 3
You have sunk Ship A
X X X X X
X X X X X
X X X A O
O X O X O
X X X X X
row: 2
col: 4
X X X X X
X X X X X
X X X A X
O X O X O
X X X X X
row: 3
col: 0
X X X X X
X X X X X
X X X A X
X X O X O
X X X X X
row: 3
col: 2
X X X X X
X X X X X
X X X A X
X X X X O
X X X X X
row: 3
col: 4
You have sunk Ship B
X X X X X
X X X X X
X X X A X
X X X X B
X X X X X
You have won the game!
>>> 

The code is written without a turns limit for testing purposes.

tuples test code

from random import randint

board = []

for x in range(5):
board.append([“O”] * 5)

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

print (“Let’s play Battleship!”)

a = randint(0, 24)
while True:
b = randint(0, 24)
if b != a: break

shipa = (int(a / 5), a % 5)
shipb = (int(b / 5), b % 5)
ship_status = [True, True]

while True in ship_status:
print_board(board)
while True:
#guess = (int(raw_input('row: ')), int(raw_input('col: ')))
guess = (int(input('row: ')), int(input('col: ')))
if guess[0] in range(5) and guess[1] in range(5):
if board[guess[0]][guess[1]] == ‘X’:
print (“You guessed that one already”)
else: break

# Now for testing...

if guess == shipa:
    print ("You have sunk Ship A")
    board[guess[0]][guess[1]] = 'A'
    ship_status[0] = False
elif guess == shipb:
    print ("You have sunk Ship B")
    board[guess[0]][guess[1]] = 'B'
    ship_status[1] = False
else:
    board[guess[0]][guess[1]] = 'X'

print_board(board)
print (“You have won the game!”)

The above is written in Python 3 but will run in Python 2 if you swap the input lines. It should still run regardless, but in Python 2 we should not use input() since it runs eval().

Tuples

Tuples are like ordered lists but they are immutable. In the above code we do not see the unpacking that is done in the background when comparing the tuples. When we compare tuples, the corresponding elements are unpacked and compared.

Eg.

a = (3, 4)
b = (3, 4)
print a == b    # <-  True

Unpacking a tuple looks something like this…

>>> t = (4, 2)
>>> u, v = t
>>> u
4
>>> v
2
>>> 

while statements are very powerful control flow constructs, as we can witness above. They are open ended so can be infinite, which is why we need a break condition on the inner loop.

"Another test run
============= RESTART: D:/cc/discuss/battleship_tuples_count.py =============
Let's play Battleship!
O O O O O
O O O O O
O O O O O
O O O O O
O O O O O
row: 0
col: 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
row: 2
col: 2
You have sunk Ship A
X O O O O
O O O O O
O O A O O
O O O O O
O O O O O
row: 4
col: 4
X O O O O
O O O O O
O O A O O
O O O O O
O O O O X
row: 3
col: 4
X O O O O
O O O O O
O O A O O
O O O O X
O O O O X
row: 3
col: 1
You have sunk Ship B
You have won the game!
X O O O O
O O O O O
O O A O O
O B O O X
O O O O X
>>> 

Off to add a turns limit…

turns limit test run
Let's play Battleship!
O O O O O
O O O O O
O O O O O
O O O O O
O O O O O
row: 0
col: 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
row: 1
col: 1
X O O O O
O X O O O
O O O O O
O O O O O
O O O O O
row: 2
col: 2
X O O O O
O X O O O
O O X O O
O O O O O
O O O O O
row: 3
col: 3
X O O O O
O X O O O
O O X O O
O O O X O
O O O O O
row: 4
col: 4
X O O O O
O X O O O
O O X O O
O O O X O
O O O O X
row: 0
col: 4
X O O O X
O X O O O
O O X O O
O O O X O
O O O O X
row: 1
col: 3
X O O O X
O X O X O
O O X O O
O O O X O
O O O O X
row: 3
col: 1
X O O O X
O X O X O
O O X O O
O X O X O
O O O O X
row: 4
col: 0
X O O O X
O X O X O
O O X O O
O X O X O
X O O O X
row: 0
col: 2
Sorry, you lose!
X O X O X
O X O X O
O O X O O
O X O X O
X O O O X
>>> 

Python 3 code

battleship_tuples_count.py
from random import randint
board = []
for x in range(5):
    board.append(["O"] * 5)
def print_board(board):
    for row in board:
        print (" ".join(row))
print ("Let's play Battleship!")
a = randint(0, 24)
while True:
    b = randint(0, 24)
    if b != a: break      
shipa = (int(a / 5), a % 5)
shipb = (int(b / 5), b % 5)
ship_status = [True, True]; count = 0
while True in ship_status:
    print_board(board)
    while True:
        guess = (int(input('row: ')), int(input('col: ')))
        if guess[0] in range(5) and guess[1] in range(5): 
            if board[guess[0]][guess[1]] == 'X':
                print ("You guessed that one already")
            else: break
        else: print ("That's not in the ocean!"); count -= 1
    if guess == shipa:
        print ("You have sunk Ship A")
        board[guess[0]][guess[1]] = 'A'
        ship_status[0] = False
    elif guess == shipb:
        print ("You have sunk Ship B")
        board[guess[0]][guess[1]] = 'B'
        ship_status[1] = False
    else:
        board[guess[0]][guess[1]] = 'X'
    count += 1
    if count > 9:
        print ("Sorry, you lose!")
        break
else:
    print ("You have won the game!")
print_board(board)

One last test run

test run with win
============= RESTART: D:/cc/discuss/battleship_tuples_count.py =============
Let's play Battleship!
O O O O O
O O O O O
O O O O O
O O O O O
O O O O O
row: 1
col: 1
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
row: 2
col: 2
O O O O O
O X O O O
O O X O O
O O O O O
O O O O O
row: 3
col: 3
O O O O O
O X O O O
O O X O O
O O O X O
O O O O O
row: 4
col: 4
O O O O O
O X O O O
O O X O O
O O O X O
O O O O X
row: 0
col: 0
X O O O O
O X O O O
O O X O O
O O O X O
O O O O X
row: 4
col: 0
X O O O O
O X O O O
O O X O O
O O O X O
X O O O X
row: 3
col: 1
X O O O O
O X O O O
O O X O O
O X O X O
X O O O X
row: 1
col: 3
You have sunk Ship B
X O O O O
O X O B O
O O X O O
O X O X O
X O O O X
row: 0
col: 4
You have sunk Ship A
You have won the game!
X O O O A
O X O B O
O O X O O
O X O X O
X O O O X
>>> 

#6

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