Battleship Full Game?


#1

Okay, so I think I almost have everything I need to make a full battleship game. If I can just figure out how to check for the win condition, how to make sure the random generated numbers for the different coordinates don’t overlap, and how to line up multiple points for a full ship then I’ll be set. Here’s what I’ve got so far:

from random import randint

board = []

for x in range(5):
    board.append(["_"] * 5)

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

print "Let's play Battleship!"
print_board(board)

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

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

def random_row2(board):
    return randint(0, len(board[0]) - 1)
    
def random_col2(baord):
    return randint(0, len(board[0]) - 1)
    
battleship_row1 = random_row1(board)
battleship_col1 = random_col1(board)
battleship_row2 = random_row2(board)
battleship_col2 = random_col2(board)
battleship_aft = (battleship_row1, battleship_col1)
battleship_fore = (battleship_row2, battleship_col2)

print battleship_row1
print battleship_col1
print battleship_row2
print battleship_col2

# Everything from here on should go in your for loop!
# Be sure to indent four spaces!

class battleship(object):
    for turn in range(6):
        print "Turn", turn + 1
        
        guess_row = int(raw_input("Guess Row:"))
        guess_col = int(raw_input("Guess Col:"))
        
        if (guess_row == battleship_row1) and (guess_col == battleship_col1):
            print "That's a hit!"
            board[guess_row][guess_col] = "X"
            print_board(board)
                        
        elif (guess_row == battleship_row2) and (guess_col == battleship_col2):
            print "That's a hit!"
            board[guess_row][guess_col] = "X"
            print_board(board)
                        
        else:
            if (guess_row < 0 or guess_row > 4) or (guess_col < 0 or guess_col > 4):
                print "Oops, that's not even in the ocean."
            elif(board[guess_row][guess_col] == "X") or (board[guess_row][guess_col] == "O"):
                print "You guessed that one already."
            else:
                print "You missed my battleship!"
                board[guess_row][guess_col] = "O"
                print_board(board)
        
 
         
        if turn == 5:
            print "Game Over"
            break
        

Any advice, hints, or ideas of where I can look to figure it out would be appreciated. Thanks.


#2

tricky isn’t it?

we can simple generate ship coordinates:

battleship_row1 = random_row1(board)
battleship_col1 = random_col1(board)

then pick a direction we want to extend the ship in, simple proof of concept:

from operator import sub
from random import randint

# extension order: n, e, s, w
extend_direction = {0: (-1,0), 1: (0,1), 2: (1,0), 3: (0,-1)}

battleship_row1 = 3
battleship_col1 = 3

battlship1 = [[battleship_row1,battleship_col1]]

extend_ship = extend_direction[randint(0, len(extend_direction) - 1)]
battlship1.append(list(map(sub, battlship1[0], extend_ship)))
print battlship1

so, we create a dictionary to which we add the directions in which we can extend the ship (you could add nw, sw and so on if you want to allow for diagonal ships, but this makes validation even more difficult, n=north, s=south and so on)

i made the ship a 2d array, so it can hold multiply coordinates

then we get a random direction to extend the ship in:

extend_ship = extend_direction[randint(0, len(extend_direction) - 1)]

then we subtract this from the coordinates:

battlship1.append(list(map(sub, battlship1[0], extend_ship)))

to get second coordinate of ship

still to do: verifying second ship coordinate is on board

verifying ships don’t intervene.

simple loop over battleship2 to verify the lists are not in battleship1


#3

This is a really big help. However, for whatever reason, when I add in the battleship1.append I get an error that says the ‘tuple’ object has no attribute ‘append’. what am I doing wrong?


#4

please include your code, otherwise i have to guess, i would guess here:

battleship_aft = (battleship_row1, battleship_col1)
battleship_fore = (battleship_row2, battleship_col2)

they are tuples, while i clearly use lists:

battlship1 = [[battleship_row1,battleship_col1]]

#5

Okay, so you were right. Sorry I didn’t put the code. Uh, I fixed the tuple bit, but now it’s saying "argument 2 to map( ) must support iteration.

admittedly, I don’t even understand what this is talking about. I don’t think it was covered in the python section.


from random import randint
from operator import sub

board = []

for x in range(5):
    board.append(["_"] * 5)

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

print "Let's play Battleship!"
print_board(board)
  
extend_direction = {0: (-1,0), 1: (0,1), 2: (1,0), 3: (0,-1)}
    
battleship_row1 = 3
battleship_col1 = 3
 
battleship1 = [battleship_row1, battleship_col1]


extend_ship = extend_direction[randint(0, len(extend_direction) - 1)]
battleship1.append(list(map(sub, battleship1[0], extend_ship)))
print battleship1

#6

here:

battleship1 = [battleship_row1, battleship_col1]

why did you make battleship1 a 1d array? if the ship has a length of 2 (or 3) a 2d array would be more useful to remember all the coordinates

the error indicates that here:

battleship1.append(list(map(sub, battleship1[0], extend_ship)))

the second argument of map (battleship1[0]) should be an iterable (list are iterable), because you changed changed battleship from 2d to 1d array battleships1[0] is no longer iterable

1d and 2d is the amount of dimensions an array has


#7

So to make it 2d, it needs two sets of brackets surrounding it? Yeah, that did it! Thanks!


#8

yes, given this allows us to store both coordinates of the ship, which we will need (to validate ships are not overlapping and so on)


#9

So I began moving the expand_ship to the battleship2 I had before. Unfortunately, i keep getting an error every time I try to run it now. It works fine if battleship1 and battleship2 are integers to begin with, but if I try to have these beginning integers randomized the error pops up. What am I doing wrong?

from random import randint
from operator import sub

board = []

for x in range(5):
board.append(["_"] * 5)

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

print "Let’s play Battleship!"
print_board(board)

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

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

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

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

extend_direction = {0: (-1,0), 1: (0,1), 2: (1,0), 3: (0,-1)}

battleship_row1 = random_row1
battleship_col1 = random_col1
battleship_row2 = random_row2
battleship_col2 = random_col2

battleship1 = [[battleship_row1, battleship_col1]]
battleship2 = [[battleship_row2, battleship_col2]]

extend_ship = extend_direction[randint(0, len(extend_direction) - 1)]

battleship1.append(list(map(sub, battleship1[0], extend_ship)))
print battleship1

battleship2.append(list(map(sub, battlehip2[1], extend_ship)))
print battleship2

Traceback (most recent call last):
File “python”, line 40, in
TypeError: unsupported operand type(s) for -: ‘function’ and ‘int’


#10

From a different angle, what if you give each ship a number, say the number of points in the ship. If only 1 per ship, then give them each a number 1 in a hidden map of the board.

[0,0,0,0,0, ..., 0,0,0,0,0]  >>> 25 elements

An empty board will have a sum of zero. A board with no overlaps will have a sum of 2.

Refer to the following topic from last year…

19. Track hits across different ships without using classes?

It is as yet still incomplete but the ideas are there to build upon.