 ## # Student Name:# Collaborate with: # #############showing page 1-13 out of 13

# Student Name:
# Collaborate with:
#
#########################################################################
####
# An Breif Introduction:
# The computer will first hunt around ramdonly untill it finds a target.
# Then, the computer will fire at the cells which are around the
target(FYI, the order would be down -> up -> left -> right), we call this
"scanning".
# After that, the computer will choose the '#'s in the target's
surroundings to fire at one unit forward, untill it misses or there is no
room to shoot at.
# If the four directions are being processed, it will go back to hunt
phase.
# Generally, the computer will win at around round 60.
#
#########################################################################
####
# First Part
# ----------------------------------------------------------------------
import random
# Instead of using our spaghetti code of
assginment4,
class BattleshipGame: # This class is mainly copyied from the solotion of
assignment4, thanks to professor Osmar Zaiane
def __init__(self):
self.__shipsNames = {'A': 'Aircraft Carrier', 'B': 'Battleship',
'S':'Submarine', 'D':'Destroyer', 'P':'Patrol Boat'}
self.__rounds = 0
self.computerShips = {"A":5,
"B":4,
"S":3,
"D":3,
"P":2}
self.userShips = {"A":5,
"B":4,
"S":3,
"D":3,
"P":2}
#setup blank 10x10 board
self.userBoard=[[" " for i in range(10)] for j in range(10)]
self.computerBoard=[[" " for i in range(10)] for j in range(10)]
#
-------------------------------------------------------------------------
--
# Amendments of method(drawBoards) are improved and designed by Yimin Yan
def drawBoards(self,hide):
sunk_ComputerShip = self.getEnemyFleet(False)
sunk_UserShip = self.getEnemyFleet(True)
print ("
Computer's board:
User's board:
at
round: %d"%(self.__rounds))
print ("
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
Computer Status:
User Status:")
labels=['A','B','C','D','E','F','G','H','I','J']
for i in range(10):
print (" %c |" % (labels[i]), end="")
# Computer's board
#print the board values, and cell dividers
for j in range(10):
if self.computerBoard[i][j] == "*" or
self.computerBoard[i][j] == "#" or not hide:
print (self.computerBoard[i][j]+"|", end="")
else:
print (' |', end="")
print ("
%c |" % (labels[i]), end="") # User's board
#print the board values, and cell dividers
for j in range(10):
print (self.userBoard[i][j]+"|", end="")
#print the extra information
if i == 0:
# line A
print ('
Nbr. of hits
:
{:<18}
{}'.format(self.getHits(True), self.getHits(False)), end = '')
elif i == 1:
# line B
print ('
Nbr. of misses:
{:<18}
{}'.format(self.getMisses(True), self.getMisses(False)), end = '')
elif i == 2:
# line C
print ('
Ships sunk
:
0{:<17}0{}'.format(len(sunk_ComputerShip), len(sunk_UserShip)), end = '')
elif i in range(3, 8):
idx = i - 3
# -----To find the actual index of the Sunk
list
if idx < len(sunk_ComputerShip): # --------To prevent the
scenario that the index is out of bound.
print('{:<19}{:<18}'.format(' ',
self.__shipsNames[sunk_ComputerShip[idx]]), end = '')
else:
print('{:<19}{:<18}'.format(' ', ' '), end = '')
if idx < len(sunk_UserShip):
print(self.__shipsNames[sunk_UserShip[idx]], end =
'')
else:
print('', end = '')
print ("")
#
-------------------------------------------------------------------------
--
def validatePlacement(self,computer,ship,size,x,y,ori):
#validate the ship can be placed at the given coordinates
# and places it if acceptable
if ori == "v" and x+size > 10:
return False
elif ori == "h" and y+size > 10:
return False
else:
if computer:
board=self.computerBoard
else:
board=self.userBoard
if ori == "v":
for i in range(size):
if board[x+i][y] != " ":
return False
elif ori == "h":
for i in range(size):
if board[x][y+i] != " ":
return False
# announce the ship to be placed
if computer:
print ("Computer placing a " + ship)
else:
print ("You placed a " + ship)
#place the ship based on valid orientation and coordinates
if ori == "v":
for i in range(size):
board[x+i][y] = ship
else: # ori=="h"
for i in range(size):
board[x][y+i] = ship
return True
#
-------------------------------------------------------------------------
--
def getEnemyFleet(self, computer):
# returns a list of two lists. The first one has the sunken ships
and the second the ships to sink
if computer:
fleet=self.userShips
else:
fleet=self.computerShips
toSink=[]
sunk=[]
# check all ships in the armada of ennemy in the game instance
for ship in fleet.keys():
if fleet[ship]==0:
sunk.append(ship)
else:
toSink.append(ship)
return [toSink,sunk]
#
-------------------------------------------------------------------------
--
def checkWinning(self, computer):
# Check if there are still any pieces of ships left to hit on the
board
# board refers to either the board of the computer (if user is
playing) or the user (if computer is playing)
if computer:
board=self.userBoard
else:
board=self.computerBoard
# Loop to check all cells in the board
# if any cell contains a char that is not empty, a miss or a hit
return false
for i in range(10):
for j in range(10):
if board[i][j] != ' ' and board[i][j] != '*' and board[i]
[j] != '#':
return False
return True
#
-------------------------------------------------------------------------
--
def makeA_Move(self, computer, x,y):
if computer:
board=self.userBoard
else:
board=self.computerBoard
old=board[x][y]
if old==" ":
board[x][y]="*"
elif old=="*" or old=="#":
return old
else:
board[x][y]="#"
return old
#
-------------------------------------------------------------------------
--
def checkIfSunk(self, computer,symbol):
if computer:
else:
# reduce size left of hit ship and check if sunk
return True
return False
#
-------------------------------------------------------------------------
--
# Implements of methods(incrementRounds, getHits, getMisses) are designed
by Lingyu Chen
def incrementRounds(self):
self.__rounds += 1
#
-------------------------------------------------------------------------
--
def getHits(self, computer):
count = 0
if computer:
board=self.userBoard
else:
board=self.computerBoard
# Loop to count all '#' in the board
for i in range(10):
for j in range(10):
if board[i][j] == '#':
count += 1
if count < 10:
count = '0' + str(count)
return str(count)
#
-------------------------------------------------------------------------
--
def getMisses(self, computer):
count = 0
if computer:
board=self.userBoard
else:
board=self.computerBoard
# Loop to count all '*' in the board
for i in range(10):
for j in range(10):
if board[i][j] == '*':
count += 1
if count < 10:
count = '0' + str(count)
return str(count)
#
-------------------------------------------------------------------------
--
# This method is to check what simbol the coordinate is.
def checkCoordinate(self, computer, x, y):
if computer:
board=self.userBoard
else:
board=self.computerBoard
content = board[x][y]
return content
#
-------------------------------------------------------------------------
--
def is_DarkCellsFull(self, computer):
# Check if there are still any dark cell left to hit on the board
# board refers to either the board of the computer (if user is
playing) or the user (if computer is playing)
if computer:
board=self.userBoard
else:
board=self.computerBoard
# Loop to check all dark cells in the board
# if any cell contains a char that is empty, return false
for i in range(10):
if i % 2 == 0:
for j in range(0, 10, 2):
if board[i][j] != '*' and board[i][j] != '#':
return False
else:
for j in range(1, 10, 2):
if board[i][j] != '*' and board[i][j] != '#':
return False
return True
#
#########################################################################
####
# Second Part
# Again, these global functions are mainly copyied from the solotion of
assignment4, thanks to professor Osmar Zaiane
# ----------------------------------------------------------------------
def whatShip(symbol):
# converting the symbol of a ship to the full name and returning it
if symbol == "A":
ship = "Aircraft Carrier"
elif symbol == "B":
ship = "Battleship"
elif symbol == "S":
ship = "Submarine"
elif symbol == "D":
ship = "Destroyer"
elif symbol == "P":
ship = "Patrol Boat"
return ship
#
-------------------------------------------------------------------------
--
def computerPlaceShips(game,ships):
# Placing the computer ships in random positions
for ship in ships.keys():
#generate random coordinates and validate the postion
valid = False
while(not valid):
x = random.randint(1,10)-1
y = random.randint(1,10)-1
o = random.randint(0,1)
if o == 0:
ori = "v"
else:
ori = "h"
valid = game.validatePlacement(True,ship,ships[ship],x,y,ori)
#
-------------------------------------------------------------------------
--
def userPlaceShips(game,ships):
# Placing the user ships after asking the coordinates and the
orientation of each
# Coordinates are for the bow
for ship in ships.keys():
#get coordinates from user and vlidate the postion
valid = False
while(not valid):
game.drawBoards(True)
print ("Placing a", ship, "of size", ships[ship])
# reading coordinates x y of new ship
x=shipCoordinates
y=shipCoordinates
# reading orientation of new ship
validOrientation=False
while not validOrientation:
orientation=input("This ship is vertical or horizontal
(v,h)? ").lower()
if orientation == "v" or orientation == "h":
validOrientation=True
valid =
game.validatePlacement(False,ship,ships[ship],x,y,orientation)
if not valid:
print ("Cannot place a", ship, "there. Stern is out of
the board or collides with other ship.\nPlease take a look at the board
and try again.")
input("Hit ENTER to continue")
game.drawBoards(True)
# DEBUGGING: Cheating to see where the
computer ships are
input("Done placing user ships. Hit ENTER to continue")
#
-------------------------------------------------------------------------
--
# read coordinates x y on board from user and validate
validCoordinates=False
while not validCoordinates:
cell=input("Enter coordinates x y (x in [A..J] and y in
[1..10]):")
cell=cell.split()
if len(cell)==2:
if cell.upper() in
['A','B','C','D','E','F','G','H','I','J'] and cell.isdigit():
x=['A','B','C','D','E','F','G','H','I','J'].index(cell.upper())
y=int(cell)-1
if x>=0 and x<=9 and y>=0 and y<=9:
validCoordinates=True
return [x,y]
#
-------------------------------------------------------------------------
--
# We rearranged the order of displaying boards and result statements to
make the code run more smoothly
def userMakesMove(game):
# ask for coordinates for a move by user and try to make move
# if move is a hit, check ship sunk and win condition
# return if user won
moveLigit=False
while(not moveLigit):
x=move
y=move
beforeDropped = game.makeA_Move(False,x,y)
labels=['A','B','C','D','E','F','G','H','I','J']
if beforeDropped=="*" or beforeDropped == "#":
game.drawBoards(True)
print ("Sorry, " + labels[x] + " " + str(y+1) + " was already
played. Try again.")
elif beforeDropped == " ":
game.drawBoards(True)
print ("Sorry, " + labels[x] + " " + str(y+1) + " is a
miss.")
moveLigit=True
else:
sunk_status = game.checkIfSunk(False,beforeDropped)
game.drawBoards(True)
print ("Hit at " + labels[x] + " " + str(y+1))
if sunk_status:
print (whatShip(beforeDropped) + " sunk")
moveLigit=True
#
return game.checkWinning(False)
# ----------------------------------------------------------------------
# Computer's Moves -- Designed by Yimin Yan
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~Hunt Phase~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def computer_Hunt(game):
# This function returns a tuple which contains True/False and possibly a
coordinate to determine which phase the computer is in.
DarkCells_isFull = game.is_DarkCellsFull(True)
moveLigit=False
while(not moveLigit):
# Hunt Phase: We created an imaginery dark and light
checkerboard; and only let the computer fire only at the dark squares.
chance = random.randint(0, 1)
if DarkCells_isFull: # If it is True, then start randomly select
white cells, else keep hitting dark cells.
if chance == 1: # if chance is odd
x = random.randrange(1,10,2) # We let x be odd, whereas y
as even.
y = random.randrange(0,10,2)
else: # if chance is even
x = random.randrange(0,10,2)
# We let x be eveh, whereas
y as odd.
y = random.randrange(1,10,2)
else:
if chance == 1: # if chance is odd
x = random.randrange(1,10,2) # We let x and y randomly be
selected from odd intergers 0 to 9.
y = random.randrange(1,10,2)
else: # if chance is even
x = random.randrange(0,10,2) # We let x and y randomly be
selected from even intergers 0 to 9.
y = random.randrange(0,10,2)
beforeDropped = game.makeA_Move(True,x,y)
labels=['A','B','C','D','E','F','G','H','I','J']
if beforeDropped=="*" or beforeDropped == "#":
moveLigit=False
elif beforeDropped == " ":
game.drawBoards(True)
print ("Sorry computer, " + labels[x] + " " + str(y+1) + " is
a miss.")
moveLigit=True
else: # Found a target, time to proceed to Target phase
sunk_status =
game.checkIfSunk(True,beforeDropped)
game.drawBoards(True)
print ("Computer did a Hit at " + labels[x] + " " + str(y+1))
if sunk_status:
print (whatShip(beforeDropped) + " sunk")
coordinate = (x, y)
moveLigit=True
return (True, coordinate) # means proceed to Target Phase
return (False, None)
# Phase remain the same
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~Target
Phase~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def orientation_Move(game, x, y, orientation):
# The function
returns the result of theMove and what the next move is (and its
viablity).
if orientation == 0:
# Move 1 unit down
if x + 1 in range(0, 10):
# To check if the
next move is inbound.
theMove = game.makeA_Move(True, x+1, y)
else:
return False
if theMove == '*':
return False
elif theMove == '#':
return (theMove, (x+1, y, orientation))
return (theMove, (x+1, y, orientation))
elif orientation == 1:
# Move 1 unit up
if x - 1 in range(0, 10):
theMove = game.makeA_Move(True, x-1, y)
else:
return False
if theMove == '*':
return False
elif theMove == '#':
return (theMove, (x-1, y, orientation))
return (theMove, (x-1, y, orientation))
elif orientation == 2:
# Move 1 unit to the
left
if y - 1 in range(0, 10):
theMove = game.makeA_Move(True, x, y-1)
else:
return False
if theMove == '*':
return False
elif theMove == '#':
return (theMove, (x, y-1, orientation))
return (theMove, (x, y-1, orientation))
elif orientation == 3:
# Move 1 unit to the
right
if y + 1 in range(0, 10):
theMove = game.makeA_Move(True, x, y+1)
else:
return False
if theMove == '*':
return False
elif theMove == '#':
return (theMove, (x, y+1, orientation))
return (theMove, (x, y+1, orientation))
def computer_Target(game, coordinate, previousCoordinate,
currentOrientation):
# Step 1, scan the surroundings.
# Step 2, fire at the ships.
list_Surroundings = [(coordinate+1, coordinate), # index 0:
Down
(coordinate-1, coordinate), # index 1: up
(coordinate, coordinate-1), # index 2:
Left
(coordinate, coordinate+1)] # index 3:
Right
valid_Neighbours = []
for neighbour in list_Surroundings:
if neighbour
in range(0, 10) and neighbour in range(0,
10):
orientation_Num = list_Surroundings.index(neighbour)
valid_Neighbours.append((neighbour, neighbour,
orientation_Num))
step = 2 # If it goes through the first check and finds some
unchecked surrouding, it will be changed to 1.
moveLigit=False
beforeDropped = 'initiation'
while(not moveLigit):
uncheckedMembers = [] # It stores the unchecked surroundings(' ',
'Ships' symbol')
Orientations = []
# it stores the possible ship's
locations('#')
for member in valid_Neighbours:
# member will be like (x, y, orientation_Num)
result = game.checkCoordinate(True, member, member)
if not result in '*#':
# This conditions means that not all of the surrouding
have already been scanned, and it is time to move to step 2.
step = 1
uncheckedMembers.append(member)
elif result == '#':
Orientations.append(member)
# ~~~~~~Excuting Step 1~~~~~~~~~
if step == 1:
square = uncheckedMembers
x = square
y = square
beforeDropped = game.makeA_Move(True, x, y)
else:
# ~~~~~~Excuting Step 2~~~~~~~~~
if currentOrientation == (-1, -1, -1): # Check if it is the
initiation of a target phase
currentOrientation = Orientations
else:
currentOrientation_index =
Orientations.index(currentOrientation)
if game.checkCoordinate(True, previousCoordinate,
previousCoordinate) == '*' or ahead == 'wall':
# It means the lastShot was a miss and swich to other
possible orienteation and fire.
if currentOrientation_index + 1 < len(Orientations):
currentOrientation =
Orientations[currentOrientation_index + 1]
previousCoordinate = currentOrientation
else: # It means Orientations list has been traversed
and time to go back to hunt Mode.
return (True, None, None)
if previousCoordinate == (-1 ,-1, -1): # Check if it is the
initiation of a target phase
square = Orientations
x = square
y = square
orientation = square
testMove = orientation_Move(game, x, y, orientation) #
The function returns the result of theMove and what the next move is.
#
e.g. (' ', (x+1, y, 2))
else:
square = previousCoordinate
x = square
y = square
orientation = square
testMove = orientation_Move(game, x, y, orientation)
if testMove == False: # The scenario is that the next move is
out of bound or is already '*'.
ahead = 'wall' # In ths scenario, change it to a 'wall'
moveLigit = False
elif testMove == '#': # This scenario is that the next
move is already been hit and represented as '#'.
previousCoordinate = testMove # update the
previousCoordinate, and it's like skipping the '#' and firing one unit
forward.
movelight = False
else: # This secnario is that the next move is legit to move
beforeDropped = testMove
nextCoordinate = testMove
x = nextCoordinate
y = nextCoordinate
# ~~~~~~Post-move check~~~~~~~~~
labels=['A','B','C','D','E','F','G','H','I','J']
if beforeDropped == " ":
game.drawBoards(True)
print ("Sorry computer, " + labels[x] + " " + str(y+1) + " is
a miss.")
moveLigit=True
elif beforeDropped in 'ABSDP': # Found a target, time to proceed
to Target phase
sunk_status =
game.checkIfSunk(True,beforeDropped)
game.drawBoards(True)
print ("Computer did a Hit at " + labels[x] + " " + str(y+1))
if sunk_status:
print (whatShip(beforeDropped) + " sunk")
moveLigit=True
if step == 2:
return (False, nextCoordinate, currentOrientation)
else:
return (False, (-1, -1, -1), (-1, -1, -1))
#
#########################################################################
####
def main():
ships = {"Aircraft Carrier":5,
"Battleship":4,
"Submarine":3,
"Destroyer":3,
"Patrol Boat":2}
game=BattleshipGame()
# create instance of the game
computerPlaceShips(game,ships)
userPlaceShips(game,ships)
phase = 'hunt'
# 'hunt'/'target'
# ---initiate Values---
coordinate = (-1 ,-1)
previousCoordinate = (-1, -1, -1)
currentOrientation = (-1, -1, -1)
gameOver=False
# game main loop
while(not gameOver):
game.incrementRounds() # -----We added this line to count the
rounds.
#user move
winning=userMakesMove(game)
#check if user won
if winning:
print ("Congratulations! User WON!")
gameOver=True
else:
# display what remains of the fleet
# We improved the visual display of both toSink and Sunk
list. (Designed by Lingyu Chen)
print ("Ships to sink:[", end="")
print (whatShip(ship)+", ", end="")
else:
print (whatShip(ship), end="")
print ("]
Ships sunk:[",end="")
print (whatShip(ship)+", ", end="")
else:
print (whatShip(ship), end="")
print("]")
#computer move, Hunt Phase gose first
if phase == 'hunt':
Hunt_move = computer_Hunt(game) # returns: (True/False,
(x, y) / None)
if Hunt_move:
coordinate = Hunt_move
phase = 'target'
else:
Target_move = computer_Target(game, coordinate,
previousCoordinate, currentOrientation) # returns: (True/False, None,
None)
if Target_move:
# or:
(False, nextCoordinate, currentOrientation))
# If it is true, then reset the values and go back to
hunt phase
Hunt_move = computer_Hunt(game) # returns:
(True/False, (x, y) / None)
if Hunt_move:
coordinate = Hunt_move
phase = 'target'
else:
phase = 'hunt'
previousCoordinate = (-1, -1, -1)
currentOrientation = (-1, -1, -1)
else:
previousCoordinate = Target_move
currentOrientation = Target_move
#check if computer won
if game.checkWinning(True):
print ("Sorry! Computer WON! Here is what the board
looked like:")
# display boards without hiding the computer ships
game.drawBoards(False)
input("Press ENTER to continue")
gameOver=True
#
#########################################################################
####
if __name__=="__main__":
main() 