st4rgut st4rgut - 2 months ago 10
Python Question

Python Battleship Game, Recursive Malfunction

apologies in advance for the data dump. I'm recreating the Battleship game with Python. I'm having trouble with the

def battleship
function where the computer and user try to guess each other's coordinates. The computer has a
e/x
probability of guessing the user's coordinates correctly, where e is the number of ships left, and x is the number of unknown coordinates. The problem is, in the case that the user misses, how can I access local variable
x
, which is assigned a value when the user scores a hit? Since this is a recursive function,
x
is not defined if the user misses. I would still like the computer to guess the player's battleship location when the user misses. However, the error message I get reads:
local variable 'x' referenced before assignment


Thanks for your patience. Seems like there should be a simple solution out there.

import random
import sys

globalValue=0 #for length of hitlist
loopcondition=True
compdestruction=0 #keep track of number of destroyed ships
userdestruction=0
destroyedships=[];
hitlist=[]; #a global variable
#to end the program
you=[];
youhitship=[];

class Battleship(object):
""" Ship object container. A game where the user tries to destroy the enemy's ships User tries to guess computer's position x and y """
def __init__(self, size, numberships,position_x,position_y):
self.position_x=position_x
self.position_y=position_y
self.numberships=numberships
self.size = size

def plotships(self,numberships):
"""input is integer coordinates for ships and output is an array of arrays with battleship locations CREATES THE HITLIST DONT REPEAT"""
while len(hitlist)<numberships:
r=Battleship.randomness(self)
if r not in hitlist:
hitlist.append(r)
originalhitlist=len(hitlist)
global globalValue
globalValue+=originalhitlist


def destroy(self):
""" Destroys the ship's point supplied if it contains it """
compChoose=Battleship.randomness(self) #computer's attak pair
print('computer choice is '+str(compChoose))
ship=[self.position_x,self.position_y]
print('Your Turn...')
if ship in hitlist:
print('Direct hit Captain')
global userdestruction
hitlist.remove(ship)
userdestruction+=1
CompWreck=GameBoard(self.size)
CompWreck.update(ship,self.size, destroyedships) #empty (at first) lists with coordinates of up-to-date list of destroyed ships
else:
print('Drat! missed!')
print('\nComps Turn')
if compChoose in you:
print('Kabloom. Your ships sunk.')
global compdestruction
you.remove(compChoose)
compdestruction+=1
YourWreck=GameBoard(self.size) #create an instance of GameBoard
YourWreck.update(ship,self.size,youhitship)
else:
print('Yay! The computer missed!\n')


def randomness(self):
"""random coordinates for computer firing and computer ship location"""
rand_x=random.choice(range(self.size))
rand_y=random.choice(range(self.size))
randcoord=[rand_x,rand_y]
return randcoord

class GameBoard(object):
""" The container for the ships """
def __init__(self, size):
"""Initialize clean GameBoard depending on size, etc """
self.size=size
self.destroyed = 'x' # representation for destroyed area
self.clear = '-' # representation for clear water

def printBoard(self,destroytheseships):
""" Print the current gameboard state"""
global compdestruction
global userdestruction
global globalValue
global loopcondition
graf='' #printed board
x=-1 #so the first row is 0, within the range of hitlist coordinates defined in Battleship.plotships(self)
for row in range(self.size): #for every row inside the first set of brackets
x+=1 #x,y pairs mark the possible ship locations
graf+='\n'
y=-1 #so the first column is 0
for column in range(self.size):
y+=1
if [x,y] in destroytheseships:
graf+=self.destroyed
else:
graf+=self.clear
print(graf)

if userdestruction == globalValue:
print('You Win!')
sys.exit('Game Over')

if compdestruction>=originalyou:
print('You Lose' )
sys.exit('Game Over')

def update(self,ship,size,witchlist):#It matter whether it's computer or user's turn. WITCHLIST defines which list you're choosing from
""" Updates the gameboard according to updated ship """
witchlist.append(ship)
newboard=GameBoard(size) #create a new instance with the same sized board
newboard.printBoard(witchlist)

#Game Interface do it once
size=int(input('Gameboard size'))
numberships=int(input('Waiting for Number of enemy ships'))
b=Battleship(size,numberships,0,0)
b.plotships(numberships) #create a hitlist and returns the original length of hitlist array

for i in range(numberships): #create list of your ships
you_x=int(input('Please enter a X coordinate for your ship'))
you_y=int(input('Please enter a Y coordinate for your ship'))
if ((you_x not in range(0,size)) or (you_y not in range(0,size))):
print('please chooose a different pair of coordinates within board boundaries\n')
continue
your_xy=[you_x,you_y]
you.append(your_xy)
originalyou=len(you)
while loopcondition==True: #take another turn as long as all the ships are not destroyed
ex=int(input('Waiting for attack X coordinate'))
why=int(input('Waiting for attack Y coordinate'))
if ((ex not in range(0,size)) or (why not in range(0,size))):
print('please chooose a different pair of coordinates within board boundaries\n')
continue
b=Battleship(size,numberships,ex,why)
b.destroy()

Answer

Your if statement means that x isn't calculated on a miss. You will have to add some more logic inside the else statement to work out what x should be. A starting point would be to duplicate the block of code that draws a graph but just keep the lines that modify the value of x (also initialize x as 0).