Skip to main content
Tweeted twitter.com/StackCodeReview/status/800007526716579840
deleted 4 characters in body
Source Link
200_success
  • 144.2k
  • 22
  • 188
  • 473
# Battleships 2K16
# Completed 11/11/16, 13:00
# Developed by Tommy Kong

# This is a Battleships game.
# It allows players to:
#   Play against each other
#   Play against a computer
#   Practice shooting ships



import random, time


# Class for creating a grid

class Grid:

    # Create gird of width and height
    
    def __init__(self,width,height):
        self.grid = []
        self.pieces = [[0],[1],[2],["miss"],["hit"]]
        for y in range(height):
            row = []
            for x in range(width):
                row.append("")
            self.grid.append(row)

    # Add piece to given coordinates
    
    def addPiece(self,piece,side):
        for pieceSet in self.pieces:
            if pieceSet[0] == side:
                pieceSet.append(piece)
                
        for coord in piece:
            self.grid[coord[1]][coord[0]] = side
        
    # Function checks if the grid still has pieces of a certain side
    
    def isDefeated(self,side):
        for row in self.grid:
            for piece in row:
                if piece == side:
                    return False
        return True

    # Display the grid for the user
    
    def show(self):

        # Adding the top coordinates
        
        print("-" * 45)
        line = ""
        for i in range(10):
            line += "| " + str(i) + " "
        print(line + "|   |")
        print("-" * 45)

        # Adding the individual cells
        
        for y in range(len(self.grid)):
            line = ""
            for x in self.grid[y]:
                if x == "":
                    line += "| - "
                elif x == 0:
                    line += "| - "
                elif x == 1:
                    line += "| - "
                elif x == 2:
                    line += "| - "
                elif x == "miss":
                    line += "| X "
                elif x == "hit":
                    line += "| O "

            # Adding side coordinates
            
            line += "| " + str(y) + " |\n"

            for x in self.grid[y]:
                line+="----"
            line += "-----"
            print(line)

    # Returns if a grid is empty
    
    def isEmpty(self,x,y):
        if self.grid[y][x] == "":
            return True
        else:
            return False
    
    # Returns the value inside a coord
    
    def getCoordValue(self,x,y):
        return self.grid[y][x]

# Class which handles the battleships game

class Battleships:

    # Allow the user to choose from 3 options
    
    def __init__(self):
        while True:
            print("Welcome to Battleships!")
            print("You can - ")
            print("[1] PvP\n[2] PvE\n[3]Just Shoot Ships")
            decision = 0

            while decision < 1 or decision > 3:
                try:
                    decision = int(input("What would you like to do: "))
                except:
                    decision = 0

            if decision == 1:
                self.PVP()
            elif decision == 2:
                self.PVE()
            elif decision == 3:
                self.JSS()
       
    # Adds a ship

    def addShip(self,grid,side,length):
        
        orientation = 0
        while orientation < 1 or orientation > 2:
            try:
                orientation = int(input("Would you like the ship to be horizontal [1] or vertical [2]: "))
            except:
                orientation = 0

        if orientation == 1:
            rootCoord = self.inputCoord(10-(length),9)
        elif orientation == 2: 
            rootCoord = self.inputCoord(9,10-(length))
        
        ship = []
        
        # Whilst valid ship has not been added
        
        while True:
            currentShip = []
            # Add coords depending on length
            
            for i in range(length):
                if orientation == 1:
                    currentShip.append([rootCoord[0]+i,rootCoord[1]])
                elif orientation == 2:
                    currentShip.append([rootCoord[0],rootCoord[1]+i])
                    
            # Test that the coords are not filled already
            validShip = True
            for coord in currentShip:
                if grid.isEmpty(coord[0],coord[1]) == False:
                    # If any coords are filled then the ship is invalid
                    
                    validShip = False
                    print("There are already ships existing there!")
                    return self.addShip(grid,side,length)
                    

            # If ship is valid then stop trying and return ship coords
            
            if validShip:
               ship = currentShip
               return ship

    # Function returns list of ship lengths that has been sunk
    
    def getSunkShips(self,grid,side):

        # List of sunk ships
        
        sunkShips = []

        # Go through the pieces array in grid object
        for ship in range(1,len(grid.pieces[side])):
            sunkStatus = []

            # For each ship coordinate in a ship
            
            for shipCoord in grid.pieces[side][ship]:
                
                # If the coordinate can be found in the hit list then that part has been sunk
                
                sunk = False
                for hitCoord in range(1,len(grid.pieces[4])):
                    if shipCoord == grid.pieces[4][hitCoord][0]:
                        sunk = True
                        break
                sunkStatus.append(sunk)

            # Go through the sunk parts and if all of it is sunk then the ship is sunk
            
            sunkShip = True
            for status in sunkStatus:
                if status == False:
                    sunkShip = False
                    break

            if sunkShip == True:
                sunkShips.append(ship+1)
        return sunkShips
                    
    # Method for when the user wants to play against the computer

    def PVE(self):

        # Create grids
        
        grids = [Grid(10,10),Grid(10,10)]

        print("Now you are going to add your ships.")

        # Add ships for player 1
        
        print("Player 1 add ships.")
        print("You input the root coordinate of the ship. They extend to the right or down, depending on orientation.")

        # Add ships of length 2 - 6
        
        for shipLength in range(5):
            print("Add ship of length {}".format(shipLength+2))
            ship = self.addShip(grids[0],1,shipLength+2)
            grids[0].addPiece(ship,1)
            input("Press enter to continue...")
        self.clearScreen()
        print("Okay, the grids are set!")
        self.clearScreen()

        # Add ships for computer
        
        grids[1].grid = self.makeShips(grids[1],0,[1,1,1,1,1])

        
        turn = 1

        # Lists of coords the computer should shoot next
        
        compWaitList = [[]]

        # Coords the computer has tried
        compShotList = []
        compSunkShips = []
        compPreviousHits = []

        # While there are ships on both side
        
        while grids[0].isDefeated(1) == False and grids[1].isDefeated(0) == False:

            # If it is player 1's turn
            
            if turn == 1:
                
                print("Player 1's turn to shoot.")
                grids[1].show()
                validMove = False
                
                while validMove == False:

                    # Get shot input and try to shoot
                    # If shot is not invalid then update the grid
                    
                    shot = self.inputCoord(9,9)
                    potentialGrid = self.shoot(grids[1],0,shot)

                    if potentialGrid != "invalid":
                        grids[1].grid = potentialGrid
                        validMove = True
                    else:
                        continue
                    
                input("Press enter to continue.")
                self.clearScreen()
                print("Current grid for Player 1.")
                grids[1].show()

                # Check game is won or not
                
                if grids[1].isDefeated(0) == True:
                    self.clearScreen()
                    print("Player 1 wins!")
                    input("Press enter to continue...")
                    self.clearScreen()
                    break

                # If game is not won, tell the players of any full ships they have sunk.

                self.sunkShips = self.getSunkShips(grids[1],0)
                if len(self.sunkShips) >= 1:        
                    print("Player 1 has sunk...")
                    for ship in self.sunkShips:
                        print("Ship of length {}.".format(ship))
                else:
                    print("No ships have yet been sunk.")
                    
                input("Press enter for Computer's turn.")
                self.clearScreen()
                turn = 2

            # Computer's turn
            
            if turn == 2:
                
                print("Computer's turn to shoot.")
                
                validShot = False

                # Get a possible x and y coordinate to shoot
                
                while validShot == False:
                    
                    x = -1
                    y = -1
                    
                    if compWaitList == [[]]:
                        while x < 0 or x > 9:
                            x = random.randint(0,9)

                        while y < 0 or y > 9:
                            y = random.randint(0,9)

                    # Else take the first coord from the waiting list
                    
                    else:
                        if compWaitList[0] != []:
                            x = compWaitList[0][0][0]
                            y = compWaitList[0][0][1]
                            compWaitList[0].pop(0)
                        else:
                            x = compWaitList[1][0][0]
                            y = compWaitList[1][0][1]
                            compWaitList[1].pop(0)

                    alreadyShot = False

                    # If proposed x and y coordinate is in shot list then repeat loop
                    for coord in compShotList:
                        if coord == [x,y]:
                            alreadyShot = True
                            break
                        
                    if alreadyShot == False:
                        validShot = True

                print("Computer is deciding...")
                time.sleep(1)
                
                # Shoot with coords and also add them to used coords
                
                compShotList.append([x,y])
                potentialGrid = self.shoot(grids[0],1,[x,y],True)
                print("Computer shot at [{},{}].".format(x,y))

                # If it was a hit then try adding smart coords to wait list
                
                if potentialGrid[1] == "hit":
                    print("The computer hit!")
                    grids[0].show()

                    # If there has been previous hit of importance and there are still possible hit locations
                    if compPreviousHits != [] and compWaitList != []:

                        # If the number of sunk ship increases, get the sunk length then remove the last n-1 possible perpendicular coords
                        
                        if compSunkShips != self.getSunkShips(grids[0],1):
                            sunkShipLength = self.getSunkShips(grids[0],1)
                            print(compSunkShips)
                            print(sunkShipLength)
                            for length in compSunkShips:
                                if sunkShipLength[0] == length:
                                    sunkShipLength.pop(0)

                            compSunkShips = self.getSunkShips(grids[0],1)
                            compWaitList[0] = []

                            # Move the previous hit to last, to be removed
                            
                            compPreviousHits.append(compPreviousHits[0])
                            compPreviousHits.pop(0)
                            compPreviousHits.append([x,y])
                            
                            del compWaitList[len(compWaitList)-sunkShipLength[0]:]

                            if compWaitList == []:
                                compWaitList.append([])
                            del compPreviousHits[len(compPreviousHits)-sunkShipLength[0]:]

                        # Else find relation of the two coords
                        else:
                            
                            # Set limits to relating to whether they're on the edge and tets relation to last hit
                            
                            if compPreviousHits[0][0] == x:

                                # Add next parallel coord (in relation to the hit and previosuly hit coord) to high priority, and perpendicular coords to lowest priority
                                # This is so there is a higher probability of another hit
                                
                                if compPreviousHits[0][1] < y:
                                    compWaitList += [[[[x+1,y],[x-1,y]]]]
                                    if y != 9:
                                        compWaitList[0] = [[[x,y+1]]] + compWaitList[0]
                                else:
                                    compWaitList += [[[[x+1,y],[x-1,y]]]]
                                    if y != 0:
                                        compWaitList[0] = [[x,y-1]] + compWaitList[0]
                                    
                            elif compPreviousHits[0][1] == y:
                                if compPreviousHits[0][0] < x:
                                    compWaitList += [[[x,y-1],[x,y+1]]]
                                    if x != 9:
                                        compWaitList[0] = [[x+1,y]] + compWaitList[0]
                                else:
                                    compWaitList += [[[x,y-1],[x,y+1]]]
                                    if x != 0:
                                        compWaitList[0] = [[x-1,y]] + compWaitList[0]

                            compPreviousHits.append(compPreviousHits[0])
                            compPreviousHits.pop(0)
                            compPreviousHits = [[x,y]] + compPreviousHits
                    else:
                        
                        # Add adjacent coords to the waiting list, depending on position on the grid
                        if x == 0:
                            if y == 0:
                                compWaitList[0] = [[x+1,y]]
                                compWaitList.append([[x,y+1]])
                            elif y == 9:
                                compWaitList[0] = [[x+1,y]]
                                compWaitList.append([[x,y-1]])
                            else:
                                compWaitList[0] = [[x+1,y]]
                                compWaitList.append([[x,y-1],[x,y+1]])
                        elif x == 9:
                            if y == 0:
                                compWaitList[0] = [[x-1,y]]
                                compWaitList.append([[x,y+1]])
                            elif y == 9:
                                compWaitList[0] = [[x-1,y]]
                                compWaitList.append([[x,y-1]])
                            else:
                                compWaitList[0] = [[x-1,y]]
                                compWaitList.append([[x,y-1],[x,y+1]])
                        elif y == 0:
                            compWaitList[0] = [[x-1,y]]
                            compWaitList.append([[x+1,y],[x,y+1]])
                        elif y == 9:
                            compWaitList[0] = [[x-1,y]]
                            compWaitList.append([[x+1,y],[x,y-1]])
                        else:
                            compWaitList[0] = [[x-1,y]]
                            compWaitList.append([[x+1,y],[x,y-1],[x,y+1]])

                        compPreviousHits.append([x,y])
                    
                    grids[0].grid = potentialGrid[0]
                    validMove = True
                else:
                    print("The computer missed!")
                    grids[0].show()
                          
                # Check game is won or not
                
                if grids[0].isDefeated(1) == True:
                    self.clearScreen()
                    grids[0].show()
                    print("Player 2 wins!")
                    input("Press enter to continue...")
                    self.clearScreen()
                    break
                
                self.sunkShips = self.getSunkShips(grids[0],1)
                if len(self.sunkShips) >= 1:        
                    print("Computer has sunk...")
                    for ship in self.sunkShips:
                        print("Ship of length {}.".format(ship))
                else:
                    print("No ships have yet been sunk.")
                    
                input("Press enter for Player 1's turn.")
                self.clearScreen()
                turn = 1

            
        return    

    # Function takes in a grid, the opposing side, and the coordinates for the shot
    
    def shoot(self,grid,oSide,shot,isComputer=False):

        # Get value in the coord to be shot
        coordValue = grid.getCoordValue(shot[0],shot[1])

        # If the opponent is the computer
        
        if oSide == 0:
            
            # If value is miss or hit, it is an invalid move
            
            if coordValue == "miss":
                print("You've already shot there! Was a miss!")
                return "invalid"
            elif coordValue == "hit":
                print("You've already shot there! Was a hit!")
                return "invalid"
            
            # If blank, miss
            
            elif coordValue == "":
                print("Miss!")
                grid.addPiece([shot],"miss")
                return grid.grid

            # If computer piece, hit
            
            elif coordValue == 0:
                print("Hit!")
                grid.addPiece([shot],"hit")
                return grid.grid
            
        elif oSide == 1:
            if isComputer == True:
                if coordValue == "":
                    grid.addPiece([shot],"miss")
                    return [grid.grid,"miss"]
                elif coordValue == 1:
                    grid.addPiece([shot],"hit")
                    return [grid.grid,"hit"]
            else:
                if coordValue == "miss":
                    print("You've already shot there! Was a miss!")
                    return "invalid"
                elif coordValue == "hit":
                    print("You've already shot there! Was a hit!")
                    return "invalid"

                # If shooting at side 2 (own), then it is invalid
                
                elif coordValue == 2:
                    print("You cannot shoot your own ships!")
                    return "invalid"
                elif coordValue == "":
                    print("Miss!")
                    grid.addPiece([shot],"miss")
                    return grid.grid
                
                # If opponet is 1 and you shoot 1 then it is hit
                
                elif coordValue == 1:
                    print("Hit!")
                    grid.addPiece([shot],"hit")
                    return grid.grid
                    
        elif oSide == 2:
            if coordValue == "miss":
                print("You've already shot there! Was a miss!")
                return "invalid"
            elif coordValue == "hit":
                print("You've already shot there! Was a hit!")
                return "invalid"

            # If shooting at side 1 (own), then it is invalid
            
            elif coordValue == 1:
                print("You cannot shoot your own ships!")
                return "invalid"
            elif coordValue == "":
                print("Miss!")
                grid.addPiece([shot],"miss")
                return grid.grid
            
            # If opponet is 2 and you shoot 2 then it is hit
            
            elif coordValue == 2:
                print("Hit!")
                grid.addPiece([shot],"hit")
                return grid.grid

            
    # Function takes in a grid, and the number of different ships wanted to add
    
    def makeShips(self,grid,side,shipLengths):

        # Add ships of varying lengths
        
        for length in range(len(shipLengths)):

            # Adds amount of ships for that length
            for amount in range(shipLengths[length]):
                ship = self.makeShip(grid,length+2)
                grid.addPiece(ship,side)
        return grid.grid
    
    # Function returns array of coordinates for a ship
    
    def makeShip(self,grid,length):
        ship = []

        # Randomise orientation
        
        orientation = random.randint(1,2)

        # Whilst valid ship has not been added
        
        while True:
            currentShip = []

            # Get root position depending on orientation

            if orientation == 1:
                x = random.randint(0,10-length)
                y = random.randint(0,9)
            elif orientation == 2:
                x = random.randint(0,9)
                y = random.randint(0,10-length)

            # Add coords depending on length
            
            for i in range(length):
                if orientation == 1:
                    currentShip.append([x+i,y])
                elif orientation == 2:
                    currentShip.append([x,y+i])
                    
            # Test that the coords are not filled already
            
            validShip = True
            for coord in currentShip:
                if grid.isEmpty(coord[0],coord[1]) == False:
                    
                    # If any coords are filled then the ship is invalid
                    
                    validShip = False

            # If ship is valid then stop trying and return ship coords
            
            if validShip:
               keepTrying = False
               ship = currentShip
               return ship
    
    # Function takes in coordinate inputs
    
    def inputCoord(self,maxX,maxY):
        x = -1
        y = -1

        # While the coordinates are not within grid params
        
        while x < 0 or x > maxX:
            try:
                x = int(input("Enter X coordinate: "))
            except:
                x = -1

        while y < 0 or y > maxY:
            try:
                y = int(input("Enter Y coordinate: "))
            except:
                y = -1

        return [x,y]

    #Clears the console
    
    def clearScreen(self):
        print("\n" * 100)
        
    game = Battleships()
# Battleships 2K16
# Completed 11/11/16, 13:00
# Developed by Tommy Kong

# This is a Battleships game.
# It allows players to:
#   Play against each other
#   Play against a computer
#   Practice shooting ships



import random, time


# Class for creating a grid

class Grid:

    # Create gird of width and height
    
    def __init__(self,width,height):
        self.grid = []
        self.pieces = [[0],[1],[2],["miss"],["hit"]]
        for y in range(height):
            row = []
            for x in range(width):
                row.append("")
            self.grid.append(row)

    # Add piece to given coordinates
    
    def addPiece(self,piece,side):
        for pieceSet in self.pieces:
            if pieceSet[0] == side:
                pieceSet.append(piece)
                
        for coord in piece:
            self.grid[coord[1]][coord[0]] = side
        
    # Function checks if the grid still has pieces of a certain side
    
    def isDefeated(self,side):
        for row in self.grid:
            for piece in row:
                if piece == side:
                    return False
        return True

    # Display the grid for the user
    
    def show(self):

        # Adding the top coordinates
        
        print("-" * 45)
        line = ""
        for i in range(10):
            line += "| " + str(i) + " "
        print(line + "|   |")
        print("-" * 45)

        # Adding the individual cells
        
        for y in range(len(self.grid)):
            line = ""
            for x in self.grid[y]:
                if x == "":
                    line += "| - "
                elif x == 0:
                    line += "| - "
                elif x == 1:
                    line += "| - "
                elif x == 2:
                    line += "| - "
                elif x == "miss":
                    line += "| X "
                elif x == "hit":
                    line += "| O "

            # Adding side coordinates
            
            line += "| " + str(y) + " |\n"

            for x in self.grid[y]:
                line+="----"
            line += "-----"
            print(line)

    # Returns if a grid is empty
    
    def isEmpty(self,x,y):
        if self.grid[y][x] == "":
            return True
        else:
            return False
    
    # Returns the value inside a coord
    
    def getCoordValue(self,x,y):
        return self.grid[y][x]

# Class which handles the battleships game

class Battleships:

    # Allow the user to choose from 3 options
    
    def __init__(self):
        while True:
            print("Welcome to Battleships!")
            print("You can - ")
            print("[1] PvP\n[2] PvE\n[3]Just Shoot Ships")
            decision = 0

            while decision < 1 or decision > 3:
                try:
                    decision = int(input("What would you like to do: "))
                except:
                    decision = 0

            if decision == 1:
                self.PVP()
            elif decision == 2:
                self.PVE()
            elif decision == 3:
                self.JSS()
       
    # Adds a ship

    def addShip(self,grid,side,length):
        
        orientation = 0
        while orientation < 1 or orientation > 2:
            try:
                orientation = int(input("Would you like the ship to be horizontal [1] or vertical [2]: "))
            except:
                orientation = 0

        if orientation == 1:
            rootCoord = self.inputCoord(10-(length),9)
        elif orientation == 2: 
            rootCoord = self.inputCoord(9,10-(length))
        
        ship = []
        
        # Whilst valid ship has not been added
        
        while True:
            currentShip = []
            # Add coords depending on length
            
            for i in range(length):
                if orientation == 1:
                    currentShip.append([rootCoord[0]+i,rootCoord[1]])
                elif orientation == 2:
                    currentShip.append([rootCoord[0],rootCoord[1]+i])
                    
            # Test that the coords are not filled already
            validShip = True
            for coord in currentShip:
                if grid.isEmpty(coord[0],coord[1]) == False:
                    # If any coords are filled then the ship is invalid
                    
                    validShip = False
                    print("There are already ships existing there!")
                    return self.addShip(grid,side,length)
                    

            # If ship is valid then stop trying and return ship coords
            
            if validShip:
               ship = currentShip
               return ship

    # Function returns list of ship lengths that has been sunk
    
    def getSunkShips(self,grid,side):

        # List of sunk ships
        
        sunkShips = []

        # Go through the pieces array in grid object
        for ship in range(1,len(grid.pieces[side])):
            sunkStatus = []

            # For each ship coordinate in a ship
            
            for shipCoord in grid.pieces[side][ship]:
                
                # If the coordinate can be found in the hit list then that part has been sunk
                
                sunk = False
                for hitCoord in range(1,len(grid.pieces[4])):
                    if shipCoord == grid.pieces[4][hitCoord][0]:
                        sunk = True
                        break
                sunkStatus.append(sunk)

            # Go through the sunk parts and if all of it is sunk then the ship is sunk
            
            sunkShip = True
            for status in sunkStatus:
                if status == False:
                    sunkShip = False
                    break

            if sunkShip == True:
                sunkShips.append(ship+1)
        return sunkShips
                    
    # Method for when the user wants to play against the computer

    def PVE(self):

        # Create grids
        
        grids = [Grid(10,10),Grid(10,10)]

        print("Now you are going to add your ships.")

        # Add ships for player 1
        
        print("Player 1 add ships.")
        print("You input the root coordinate of the ship. They extend to the right or down, depending on orientation.")

        # Add ships of length 2 - 6
        
        for shipLength in range(5):
            print("Add ship of length {}".format(shipLength+2))
            ship = self.addShip(grids[0],1,shipLength+2)
            grids[0].addPiece(ship,1)
            input("Press enter to continue...")
        self.clearScreen()
        print("Okay, the grids are set!")
        self.clearScreen()

        # Add ships for computer
        
        grids[1].grid = self.makeShips(grids[1],0,[1,1,1,1,1])

        
        turn = 1

        # Lists of coords the computer should shoot next
        
        compWaitList = [[]]

        # Coords the computer has tried
        compShotList = []
        compSunkShips = []
        compPreviousHits = []

        # While there are ships on both side
        
        while grids[0].isDefeated(1) == False and grids[1].isDefeated(0) == False:

            # If it is player 1's turn
            
            if turn == 1:
                
                print("Player 1's turn to shoot.")
                grids[1].show()
                validMove = False
                
                while validMove == False:

                    # Get shot input and try to shoot
                    # If shot is not invalid then update the grid
                    
                    shot = self.inputCoord(9,9)
                    potentialGrid = self.shoot(grids[1],0,shot)

                    if potentialGrid != "invalid":
                        grids[1].grid = potentialGrid
                        validMove = True
                    else:
                        continue
                    
                input("Press enter to continue.")
                self.clearScreen()
                print("Current grid for Player 1.")
                grids[1].show()

                # Check game is won or not
                
                if grids[1].isDefeated(0) == True:
                    self.clearScreen()
                    print("Player 1 wins!")
                    input("Press enter to continue...")
                    self.clearScreen()
                    break

                # If game is not won, tell the players of any full ships they have sunk.

                self.sunkShips = self.getSunkShips(grids[1],0)
                if len(self.sunkShips) >= 1:        
                    print("Player 1 has sunk...")
                    for ship in self.sunkShips:
                        print("Ship of length {}.".format(ship))
                else:
                    print("No ships have yet been sunk.")
                    
                input("Press enter for Computer's turn.")
                self.clearScreen()
                turn = 2

            # Computer's turn
            
            if turn == 2:
                
                print("Computer's turn to shoot.")
                
                validShot = False

                # Get a possible x and y coordinate to shoot
                
                while validShot == False:
                    
                    x = -1
                    y = -1
                    
                    if compWaitList == [[]]:
                        while x < 0 or x > 9:
                            x = random.randint(0,9)

                        while y < 0 or y > 9:
                            y = random.randint(0,9)

                    # Else take the first coord from the waiting list
                    
                    else:
                        if compWaitList[0] != []:
                            x = compWaitList[0][0][0]
                            y = compWaitList[0][0][1]
                            compWaitList[0].pop(0)
                        else:
                            x = compWaitList[1][0][0]
                            y = compWaitList[1][0][1]
                            compWaitList[1].pop(0)

                    alreadyShot = False

                    # If proposed x and y coordinate is in shot list then repeat loop
                    for coord in compShotList:
                        if coord == [x,y]:
                            alreadyShot = True
                            break
                        
                    if alreadyShot == False:
                        validShot = True

                print("Computer is deciding...")
                time.sleep(1)
                
                # Shoot with coords and also add them to used coords
                
                compShotList.append([x,y])
                potentialGrid = self.shoot(grids[0],1,[x,y],True)
                print("Computer shot at [{},{}].".format(x,y))

                # If it was a hit then try adding smart coords to wait list
                
                if potentialGrid[1] == "hit":
                    print("The computer hit!")
                    grids[0].show()

                    # If there has been previous hit of importance and there are still possible hit locations
                    if compPreviousHits != [] and compWaitList != []:

                        # If the number of sunk ship increases, get the sunk length then remove the last n-1 possible perpendicular coords
                        
                        if compSunkShips != self.getSunkShips(grids[0],1):
                            sunkShipLength = self.getSunkShips(grids[0],1)
                            print(compSunkShips)
                            print(sunkShipLength)
                            for length in compSunkShips:
                                if sunkShipLength[0] == length:
                                    sunkShipLength.pop(0)

                            compSunkShips = self.getSunkShips(grids[0],1)
                            compWaitList[0] = []

                            # Move the previous hit to last, to be removed
                            
                            compPreviousHits.append(compPreviousHits[0])
                            compPreviousHits.pop(0)
                            compPreviousHits.append([x,y])
                            
                            del compWaitList[len(compWaitList)-sunkShipLength[0]:]

                            if compWaitList == []:
                                compWaitList.append([])
                            del compPreviousHits[len(compPreviousHits)-sunkShipLength[0]:]

                        # Else find relation of the two coords
                        else:
                            
                            # Set limits to relating to whether they're on the edge and tets relation to last hit
                            
                            if compPreviousHits[0][0] == x:

                                # Add next parallel coord (in relation to the hit and previosuly hit coord) to high priority, and perpendicular coords to lowest priority
                                # This is so there is a higher probability of another hit
                                
                                if compPreviousHits[0][1] < y:
                                    compWaitList += [[[[x+1,y],[x-1,y]]]]
                                    if y != 9:
                                        compWaitList[0] = [[[x,y+1]]] + compWaitList[0]
                                else:
                                    compWaitList += [[[[x+1,y],[x-1,y]]]]
                                    if y != 0:
                                        compWaitList[0] = [[x,y-1]] + compWaitList[0]
                                    
                            elif compPreviousHits[0][1] == y:
                                if compPreviousHits[0][0] < x:
                                    compWaitList += [[[x,y-1],[x,y+1]]]
                                    if x != 9:
                                        compWaitList[0] = [[x+1,y]] + compWaitList[0]
                                else:
                                    compWaitList += [[[x,y-1],[x,y+1]]]
                                    if x != 0:
                                        compWaitList[0] = [[x-1,y]] + compWaitList[0]

                            compPreviousHits.append(compPreviousHits[0])
                            compPreviousHits.pop(0)
                            compPreviousHits = [[x,y]] + compPreviousHits
                    else:
                        
                        # Add adjacent coords to the waiting list, depending on position on the grid
                        if x == 0:
                            if y == 0:
                                compWaitList[0] = [[x+1,y]]
                                compWaitList.append([[x,y+1]])
                            elif y == 9:
                                compWaitList[0] = [[x+1,y]]
                                compWaitList.append([[x,y-1]])
                            else:
                                compWaitList[0] = [[x+1,y]]
                                compWaitList.append([[x,y-1],[x,y+1]])
                        elif x == 9:
                            if y == 0:
                                compWaitList[0] = [[x-1,y]]
                                compWaitList.append([[x,y+1]])
                            elif y == 9:
                                compWaitList[0] = [[x-1,y]]
                                compWaitList.append([[x,y-1]])
                            else:
                                compWaitList[0] = [[x-1,y]]
                                compWaitList.append([[x,y-1],[x,y+1]])
                        elif y == 0:
                            compWaitList[0] = [[x-1,y]]
                            compWaitList.append([[x+1,y],[x,y+1]])
                        elif y == 9:
                            compWaitList[0] = [[x-1,y]]
                            compWaitList.append([[x+1,y],[x,y-1]])
                        else:
                            compWaitList[0] = [[x-1,y]]
                            compWaitList.append([[x+1,y],[x,y-1],[x,y+1]])

                        compPreviousHits.append([x,y])
                    
                    grids[0].grid = potentialGrid[0]
                    validMove = True
                else:
                    print("The computer missed!")
                    grids[0].show()
                          
                # Check game is won or not
                
                if grids[0].isDefeated(1) == True:
                    self.clearScreen()
                    grids[0].show()
                    print("Player 2 wins!")
                    input("Press enter to continue...")
                    self.clearScreen()
                    break
                
                self.sunkShips = self.getSunkShips(grids[0],1)
                if len(self.sunkShips) >= 1:        
                    print("Computer has sunk...")
                    for ship in self.sunkShips:
                        print("Ship of length {}.".format(ship))
                else:
                    print("No ships have yet been sunk.")
                    
                input("Press enter for Player 1's turn.")
                self.clearScreen()
                turn = 1

            
        return    

    # Function takes in a grid, the opposing side, and the coordinates for the shot
    
    def shoot(self,grid,oSide,shot,isComputer=False):

        # Get value in the coord to be shot
        coordValue = grid.getCoordValue(shot[0],shot[1])

        # If the opponent is the computer
        
        if oSide == 0:
            
            # If value is miss or hit, it is an invalid move
            
            if coordValue == "miss":
                print("You've already shot there! Was a miss!")
                return "invalid"
            elif coordValue == "hit":
                print("You've already shot there! Was a hit!")
                return "invalid"
            
            # If blank, miss
            
            elif coordValue == "":
                print("Miss!")
                grid.addPiece([shot],"miss")
                return grid.grid

            # If computer piece, hit
            
            elif coordValue == 0:
                print("Hit!")
                grid.addPiece([shot],"hit")
                return grid.grid
            
        elif oSide == 1:
            if isComputer == True:
                if coordValue == "":
                    grid.addPiece([shot],"miss")
                    return [grid.grid,"miss"]
                elif coordValue == 1:
                    grid.addPiece([shot],"hit")
                    return [grid.grid,"hit"]
            else:
                if coordValue == "miss":
                    print("You've already shot there! Was a miss!")
                    return "invalid"
                elif coordValue == "hit":
                    print("You've already shot there! Was a hit!")
                    return "invalid"

                # If shooting at side 2 (own), then it is invalid
                
                elif coordValue == 2:
                    print("You cannot shoot your own ships!")
                    return "invalid"
                elif coordValue == "":
                    print("Miss!")
                    grid.addPiece([shot],"miss")
                    return grid.grid
                
                # If opponet is 1 and you shoot 1 then it is hit
                
                elif coordValue == 1:
                    print("Hit!")
                    grid.addPiece([shot],"hit")
                    return grid.grid
                    
        elif oSide == 2:
            if coordValue == "miss":
                print("You've already shot there! Was a miss!")
                return "invalid"
            elif coordValue == "hit":
                print("You've already shot there! Was a hit!")
                return "invalid"

            # If shooting at side 1 (own), then it is invalid
            
            elif coordValue == 1:
                print("You cannot shoot your own ships!")
                return "invalid"
            elif coordValue == "":
                print("Miss!")
                grid.addPiece([shot],"miss")
                return grid.grid
            
            # If opponet is 2 and you shoot 2 then it is hit
            
            elif coordValue == 2:
                print("Hit!")
                grid.addPiece([shot],"hit")
                return grid.grid

            
    # Function takes in a grid, and the number of different ships wanted to add
    
    def makeShips(self,grid,side,shipLengths):

        # Add ships of varying lengths
        
        for length in range(len(shipLengths)):

            # Adds amount of ships for that length
            for amount in range(shipLengths[length]):
                ship = self.makeShip(grid,length+2)
                grid.addPiece(ship,side)
        return grid.grid
    
    # Function returns array of coordinates for a ship
    
    def makeShip(self,grid,length):
        ship = []

        # Randomise orientation
        
        orientation = random.randint(1,2)

        # Whilst valid ship has not been added
        
        while True:
            currentShip = []

            # Get root position depending on orientation

            if orientation == 1:
                x = random.randint(0,10-length)
                y = random.randint(0,9)
            elif orientation == 2:
                x = random.randint(0,9)
                y = random.randint(0,10-length)

            # Add coords depending on length
            
            for i in range(length):
                if orientation == 1:
                    currentShip.append([x+i,y])
                elif orientation == 2:
                    currentShip.append([x,y+i])
                    
            # Test that the coords are not filled already
            
            validShip = True
            for coord in currentShip:
                if grid.isEmpty(coord[0],coord[1]) == False:
                    
                    # If any coords are filled then the ship is invalid
                    
                    validShip = False

            # If ship is valid then stop trying and return ship coords
            
            if validShip:
               keepTrying = False
               ship = currentShip
               return ship
    
    # Function takes in coordinate inputs
    
    def inputCoord(self,maxX,maxY):
        x = -1
        y = -1

        # While the coordinates are not within grid params
        
        while x < 0 or x > maxX:
            try:
                x = int(input("Enter X coordinate: "))
            except:
                x = -1

        while y < 0 or y > maxY:
            try:
                y = int(input("Enter Y coordinate: "))
            except:
                y = -1

        return [x,y]

    #Clears the console
    
    def clearScreen(self):
        print("\n" * 100)
        
    game = Battleships()
# Battleships 2K16
# Completed 11/11/16, 13:00
# Developed by Tommy Kong

# This is a Battleships game.
# It allows players to:
#   Play against each other
#   Play against a computer
#   Practice shooting ships



import random, time


# Class for creating a grid

class Grid:

    # Create gird of width and height
    
    def __init__(self,width,height):
        self.grid = []
        self.pieces = [[0],[1],[2],["miss"],["hit"]]
        for y in range(height):
            row = []
            for x in range(width):
                row.append("")
            self.grid.append(row)

    # Add piece to given coordinates
    
    def addPiece(self,piece,side):
        for pieceSet in self.pieces:
            if pieceSet[0] == side:
                pieceSet.append(piece)
                
        for coord in piece:
            self.grid[coord[1]][coord[0]] = side
        
    # Function checks if the grid still has pieces of a certain side
    
    def isDefeated(self,side):
        for row in self.grid:
            for piece in row:
                if piece == side:
                    return False
        return True

    # Display the grid for the user
    
    def show(self):

        # Adding the top coordinates
        
        print("-" * 45)
        line = ""
        for i in range(10):
            line += "| " + str(i) + " "
        print(line + "|   |")
        print("-" * 45)

        # Adding the individual cells
        
        for y in range(len(self.grid)):
            line = ""
            for x in self.grid[y]:
                if x == "":
                    line += "| - "
                elif x == 0:
                    line += "| - "
                elif x == 1:
                    line += "| - "
                elif x == 2:
                    line += "| - "
                elif x == "miss":
                    line += "| X "
                elif x == "hit":
                    line += "| O "

            # Adding side coordinates
            
            line += "| " + str(y) + " |\n"

            for x in self.grid[y]:
                line+="----"
            line += "-----"
            print(line)

    # Returns if a grid is empty
    
    def isEmpty(self,x,y):
        if self.grid[y][x] == "":
            return True
        else:
            return False
    
    # Returns the value inside a coord
    
    def getCoordValue(self,x,y):
        return self.grid[y][x]

# Class which handles the battleships game

class Battleships:

    # Allow the user to choose from 3 options
    
    def __init__(self):
        while True:
            print("Welcome to Battleships!")
            print("You can - ")
            print("[1] PvP\n[2] PvE\n[3]Just Shoot Ships")
            decision = 0

            while decision < 1 or decision > 3:
                try:
                    decision = int(input("What would you like to do: "))
                except:
                    decision = 0

            if decision == 1:
                self.PVP()
            elif decision == 2:
                self.PVE()
            elif decision == 3:
                self.JSS()
       
    # Adds a ship

    def addShip(self,grid,side,length):
        
        orientation = 0
        while orientation < 1 or orientation > 2:
            try:
                orientation = int(input("Would you like the ship to be horizontal [1] or vertical [2]: "))
            except:
                orientation = 0

        if orientation == 1:
            rootCoord = self.inputCoord(10-(length),9)
        elif orientation == 2: 
            rootCoord = self.inputCoord(9,10-(length))
        
        ship = []
        
        # Whilst valid ship has not been added
        
        while True:
            currentShip = []
            # Add coords depending on length
            
            for i in range(length):
                if orientation == 1:
                    currentShip.append([rootCoord[0]+i,rootCoord[1]])
                elif orientation == 2:
                    currentShip.append([rootCoord[0],rootCoord[1]+i])
                    
            # Test that the coords are not filled already
            validShip = True
            for coord in currentShip:
                if grid.isEmpty(coord[0],coord[1]) == False:
                    # If any coords are filled then the ship is invalid
                    
                    validShip = False
                    print("There are already ships existing there!")
                    return self.addShip(grid,side,length)
                    

            # If ship is valid then stop trying and return ship coords
            
            if validShip:
               ship = currentShip
               return ship

    # Function returns list of ship lengths that has been sunk
    
    def getSunkShips(self,grid,side):

        # List of sunk ships
        
        sunkShips = []

        # Go through the pieces array in grid object
        for ship in range(1,len(grid.pieces[side])):
            sunkStatus = []

            # For each ship coordinate in a ship
            
            for shipCoord in grid.pieces[side][ship]:
                
                # If the coordinate can be found in the hit list then that part has been sunk
                
                sunk = False
                for hitCoord in range(1,len(grid.pieces[4])):
                    if shipCoord == grid.pieces[4][hitCoord][0]:
                        sunk = True
                        break
                sunkStatus.append(sunk)

            # Go through the sunk parts and if all of it is sunk then the ship is sunk
            
            sunkShip = True
            for status in sunkStatus:
                if status == False:
                    sunkShip = False
                    break

            if sunkShip == True:
                sunkShips.append(ship+1)
        return sunkShips
                    
    # Method for when the user wants to play against the computer

    def PVE(self):

        # Create grids
        
        grids = [Grid(10,10),Grid(10,10)]

        print("Now you are going to add your ships.")

        # Add ships for player 1
        
        print("Player 1 add ships.")
        print("You input the root coordinate of the ship. They extend to the right or down, depending on orientation.")

        # Add ships of length 2 - 6
        
        for shipLength in range(5):
            print("Add ship of length {}".format(shipLength+2))
            ship = self.addShip(grids[0],1,shipLength+2)
            grids[0].addPiece(ship,1)
            input("Press enter to continue...")
        self.clearScreen()
        print("Okay, the grids are set!")
        self.clearScreen()

        # Add ships for computer
        
        grids[1].grid = self.makeShips(grids[1],0,[1,1,1,1,1])

        
        turn = 1

        # Lists of coords the computer should shoot next
        
        compWaitList = [[]]

        # Coords the computer has tried
        compShotList = []
        compSunkShips = []
        compPreviousHits = []

        # While there are ships on both side
        
        while grids[0].isDefeated(1) == False and grids[1].isDefeated(0) == False:

            # If it is player 1's turn
            
            if turn == 1:
                
                print("Player 1's turn to shoot.")
                grids[1].show()
                validMove = False
                
                while validMove == False:

                    # Get shot input and try to shoot
                    # If shot is not invalid then update the grid
                    
                    shot = self.inputCoord(9,9)
                    potentialGrid = self.shoot(grids[1],0,shot)

                    if potentialGrid != "invalid":
                        grids[1].grid = potentialGrid
                        validMove = True
                    else:
                        continue
                    
                input("Press enter to continue.")
                self.clearScreen()
                print("Current grid for Player 1.")
                grids[1].show()

                # Check game is won or not
                
                if grids[1].isDefeated(0) == True:
                    self.clearScreen()
                    print("Player 1 wins!")
                    input("Press enter to continue...")
                    self.clearScreen()
                    break

                # If game is not won, tell the players of any full ships they have sunk.

                self.sunkShips = self.getSunkShips(grids[1],0)
                if len(self.sunkShips) >= 1:        
                    print("Player 1 has sunk...")
                    for ship in self.sunkShips:
                        print("Ship of length {}.".format(ship))
                else:
                    print("No ships have yet been sunk.")
                    
                input("Press enter for Computer's turn.")
                self.clearScreen()
                turn = 2

            # Computer's turn
            
            if turn == 2:
                
                print("Computer's turn to shoot.")
                
                validShot = False

                # Get a possible x and y coordinate to shoot
                
                while validShot == False:
                    
                    x = -1
                    y = -1
                    
                    if compWaitList == [[]]:
                        while x < 0 or x > 9:
                            x = random.randint(0,9)

                        while y < 0 or y > 9:
                            y = random.randint(0,9)

                    # Else take the first coord from the waiting list
                    
                    else:
                        if compWaitList[0] != []:
                            x = compWaitList[0][0][0]
                            y = compWaitList[0][0][1]
                            compWaitList[0].pop(0)
                        else:
                            x = compWaitList[1][0][0]
                            y = compWaitList[1][0][1]
                            compWaitList[1].pop(0)

                    alreadyShot = False

                    # If proposed x and y coordinate is in shot list then repeat loop
                    for coord in compShotList:
                        if coord == [x,y]:
                            alreadyShot = True
                            break
                        
                    if alreadyShot == False:
                        validShot = True

                print("Computer is deciding...")
                time.sleep(1)
                
                # Shoot with coords and also add them to used coords
                
                compShotList.append([x,y])
                potentialGrid = self.shoot(grids[0],1,[x,y],True)
                print("Computer shot at [{},{}].".format(x,y))

                # If it was a hit then try adding smart coords to wait list
                
                if potentialGrid[1] == "hit":
                    print("The computer hit!")
                    grids[0].show()

                    # If there has been previous hit of importance and there are still possible hit locations
                    if compPreviousHits != [] and compWaitList != []:

                        # If the number of sunk ship increases, get the sunk length then remove the last n-1 possible perpendicular coords
                        
                        if compSunkShips != self.getSunkShips(grids[0],1):
                            sunkShipLength = self.getSunkShips(grids[0],1)
                            print(compSunkShips)
                            print(sunkShipLength)
                            for length in compSunkShips:
                                if sunkShipLength[0] == length:
                                    sunkShipLength.pop(0)

                            compSunkShips = self.getSunkShips(grids[0],1)
                            compWaitList[0] = []

                            # Move the previous hit to last, to be removed
                            
                            compPreviousHits.append(compPreviousHits[0])
                            compPreviousHits.pop(0)
                            compPreviousHits.append([x,y])
                            
                            del compWaitList[len(compWaitList)-sunkShipLength[0]:]

                            if compWaitList == []:
                                compWaitList.append([])
                            del compPreviousHits[len(compPreviousHits)-sunkShipLength[0]:]

                        # Else find relation of the two coords
                        else:
                            
                            # Set limits to relating to whether they're on the edge and tets relation to last hit
                            
                            if compPreviousHits[0][0] == x:

                                # Add next parallel coord (in relation to the hit and previosuly hit coord) to high priority, and perpendicular coords to lowest priority
                                # This is so there is a higher probability of another hit
                                
                                if compPreviousHits[0][1] < y:
                                    compWaitList += [[[[x+1,y],[x-1,y]]]]
                                    if y != 9:
                                        compWaitList[0] = [[[x,y+1]]] + compWaitList[0]
                                else:
                                    compWaitList += [[[[x+1,y],[x-1,y]]]]
                                    if y != 0:
                                        compWaitList[0] = [[x,y-1]] + compWaitList[0]
                                    
                            elif compPreviousHits[0][1] == y:
                                if compPreviousHits[0][0] < x:
                                    compWaitList += [[[x,y-1],[x,y+1]]]
                                    if x != 9:
                                        compWaitList[0] = [[x+1,y]] + compWaitList[0]
                                else:
                                    compWaitList += [[[x,y-1],[x,y+1]]]
                                    if x != 0:
                                        compWaitList[0] = [[x-1,y]] + compWaitList[0]

                            compPreviousHits.append(compPreviousHits[0])
                            compPreviousHits.pop(0)
                            compPreviousHits = [[x,y]] + compPreviousHits
                    else:
                        
                        # Add adjacent coords to the waiting list, depending on position on the grid
                        if x == 0:
                            if y == 0:
                                compWaitList[0] = [[x+1,y]]
                                compWaitList.append([[x,y+1]])
                            elif y == 9:
                                compWaitList[0] = [[x+1,y]]
                                compWaitList.append([[x,y-1]])
                            else:
                                compWaitList[0] = [[x+1,y]]
                                compWaitList.append([[x,y-1],[x,y+1]])
                        elif x == 9:
                            if y == 0:
                                compWaitList[0] = [[x-1,y]]
                                compWaitList.append([[x,y+1]])
                            elif y == 9:
                                compWaitList[0] = [[x-1,y]]
                                compWaitList.append([[x,y-1]])
                            else:
                                compWaitList[0] = [[x-1,y]]
                                compWaitList.append([[x,y-1],[x,y+1]])
                        elif y == 0:
                            compWaitList[0] = [[x-1,y]]
                            compWaitList.append([[x+1,y],[x,y+1]])
                        elif y == 9:
                            compWaitList[0] = [[x-1,y]]
                            compWaitList.append([[x+1,y],[x,y-1]])
                        else:
                            compWaitList[0] = [[x-1,y]]
                            compWaitList.append([[x+1,y],[x,y-1],[x,y+1]])

                        compPreviousHits.append([x,y])
                    
                    grids[0].grid = potentialGrid[0]
                    validMove = True
                else:
                    print("The computer missed!")
                    grids[0].show()
                          
                # Check game is won or not
                
                if grids[0].isDefeated(1) == True:
                    self.clearScreen()
                    grids[0].show()
                    print("Player 2 wins!")
                    input("Press enter to continue...")
                    self.clearScreen()
                    break
                
                self.sunkShips = self.getSunkShips(grids[0],1)
                if len(self.sunkShips) >= 1:        
                    print("Computer has sunk...")
                    for ship in self.sunkShips:
                        print("Ship of length {}.".format(ship))
                else:
                    print("No ships have yet been sunk.")
                    
                input("Press enter for Player 1's turn.")
                self.clearScreen()
                turn = 1

            
        return    

    # Function takes in a grid, the opposing side, and the coordinates for the shot
    
    def shoot(self,grid,oSide,shot,isComputer=False):

        # Get value in the coord to be shot
        coordValue = grid.getCoordValue(shot[0],shot[1])

        # If the opponent is the computer
        
        if oSide == 0:
            
            # If value is miss or hit, it is an invalid move
            
            if coordValue == "miss":
                print("You've already shot there! Was a miss!")
                return "invalid"
            elif coordValue == "hit":
                print("You've already shot there! Was a hit!")
                return "invalid"
            
            # If blank, miss
            
            elif coordValue == "":
                print("Miss!")
                grid.addPiece([shot],"miss")
                return grid.grid

            # If computer piece, hit
            
            elif coordValue == 0:
                print("Hit!")
                grid.addPiece([shot],"hit")
                return grid.grid
            
        elif oSide == 1:
            if isComputer == True:
                if coordValue == "":
                    grid.addPiece([shot],"miss")
                    return [grid.grid,"miss"]
                elif coordValue == 1:
                    grid.addPiece([shot],"hit")
                    return [grid.grid,"hit"]
            else:
                if coordValue == "miss":
                    print("You've already shot there! Was a miss!")
                    return "invalid"
                elif coordValue == "hit":
                    print("You've already shot there! Was a hit!")
                    return "invalid"

                # If shooting at side 2 (own), then it is invalid
                
                elif coordValue == 2:
                    print("You cannot shoot your own ships!")
                    return "invalid"
                elif coordValue == "":
                    print("Miss!")
                    grid.addPiece([shot],"miss")
                    return grid.grid
                
                # If opponet is 1 and you shoot 1 then it is hit
                
                elif coordValue == 1:
                    print("Hit!")
                    grid.addPiece([shot],"hit")
                    return grid.grid
                    
        elif oSide == 2:
            if coordValue == "miss":
                print("You've already shot there! Was a miss!")
                return "invalid"
            elif coordValue == "hit":
                print("You've already shot there! Was a hit!")
                return "invalid"

            # If shooting at side 1 (own), then it is invalid
            
            elif coordValue == 1:
                print("You cannot shoot your own ships!")
                return "invalid"
            elif coordValue == "":
                print("Miss!")
                grid.addPiece([shot],"miss")
                return grid.grid
            
            # If opponet is 2 and you shoot 2 then it is hit
            
            elif coordValue == 2:
                print("Hit!")
                grid.addPiece([shot],"hit")
                return grid.grid

            
    # Function takes in a grid, and the number of different ships wanted to add
    
    def makeShips(self,grid,side,shipLengths):

        # Add ships of varying lengths
        
        for length in range(len(shipLengths)):

            # Adds amount of ships for that length
            for amount in range(shipLengths[length]):
                ship = self.makeShip(grid,length+2)
                grid.addPiece(ship,side)
        return grid.grid
    
    # Function returns array of coordinates for a ship
    
    def makeShip(self,grid,length):
        ship = []

        # Randomise orientation
        
        orientation = random.randint(1,2)

        # Whilst valid ship has not been added
        
        while True:
            currentShip = []

            # Get root position depending on orientation

            if orientation == 1:
                x = random.randint(0,10-length)
                y = random.randint(0,9)
            elif orientation == 2:
                x = random.randint(0,9)
                y = random.randint(0,10-length)

            # Add coords depending on length
            
            for i in range(length):
                if orientation == 1:
                    currentShip.append([x+i,y])
                elif orientation == 2:
                    currentShip.append([x,y+i])
                    
            # Test that the coords are not filled already
            
            validShip = True
            for coord in currentShip:
                if grid.isEmpty(coord[0],coord[1]) == False:
                    
                    # If any coords are filled then the ship is invalid
                    
                    validShip = False

            # If ship is valid then stop trying and return ship coords
            
            if validShip:
               keepTrying = False
               ship = currentShip
               return ship
    
    # Function takes in coordinate inputs
    
    def inputCoord(self,maxX,maxY):
        x = -1
        y = -1

        # While the coordinates are not within grid params
        
        while x < 0 or x > maxX:
            try:
                x = int(input("Enter X coordinate: "))
            except:
                x = -1

        while y < 0 or y > maxY:
            try:
                y = int(input("Enter Y coordinate: "))
            except:
                y = -1

        return [x,y]

    #Clears the console
    
    def clearScreen(self):
        print("\n" * 100)
        
game = Battleships()
fix code formatting/indentation, remove "thanks for reading", use : not -
Source Link

Thank you for reading. I am a Year 12 student studying CS for my A-Levels. I have had previous Python experience but it is obviously not to professional/industry standard. Therefore, my goal for this review is for my code to be criticised, allowing me to improve towards reaching such standards.

Here is what I think I'd like a review on-:

    # Battleships 2K16
    # Completed 11/11/16, 13:00
    # Developed by Tommy Kong

    # This is a Battleships game.
    # It allows players to:
    #   Play against each other
    #   Play against a computer
    #   Practice shooting ships



    import random, time

Class for creating a grid

class Grid:

# CreateBattleships gird2K16
# ofCompleted width11/11/16, and13:00
# heightDeveloped by Tommy Kong

def# __init__(self,width,height):
This is a Battleships selfgame.grid = []
    self.pieces = [[0],[1],[2],["miss"],["hit"]]
   # forIt yallows inplayers range(height)to:
        row = []
     #   forPlay xagainst ineach range(width):other
      #   Play against a row.append("")computer
   #   Practice shooting self.grid.append(row)ships

# Add piece to given coordinates

def addPiece(self,piece,side):
    for pieceSet in self.pieces:
        if pieceSet[0] == side:
            pieceSet.append(piece)
            
    for coord in piece:
        self.grid[coord[1]][coord[0]] = side
    
# Function checks if the grid still has pieces of a certain side

defimport isDefeated(selfrandom,side):
    for row in self.grid:
        for piece in row:
            if piece == side:
                return False
    return Truetime

# Display the grid for the user

def# show(self):Class for creating a grid

    # Adding the top coordinates
    
    print("-" * 45)
    line = ""
    for i inclass range(10)Grid:
        line += "| " + str(i) + " "
    print(line + "|   |")
    print("-" * 45)

    # AddingCreate thegird individualof cellswidth and height
    
    for y indef range(len__init__(self.grid),width,height):
        lineself.grid = ""[]
        for x in self.grid[y]:
            if x == "":
                line += "| - "
            elif x == 0:
                line += "| - "
            elif x == 1:
                line += "|pieces -= "[[0],[1],[2],["miss"],["hit"]]
            eliffor xy ==in 2range(height):
                line += "|row -= "[]
            eliffor x ==in "miss"range(width):
                line += "| X "
            elif x == "hit":row.append("")
                line += "| O "self.grid.append(row)

    # Add piece to #given Addingcoordinates
    
    def addPiece(self,piece,side):
 coordinates       for pieceSet in self.pieces:
            if pieceSet[0] == side:
                pieceSet.append(piece)
                
        for coord in piece:
            self.grid[coord[1]][coord[0]] = side
        
    # Function checks if linethe +=grid "|still "has +pieces str(y)of +a "certain |\n"side
    
    def isDefeated(self,side):
        for xrow in self.grid[y]grid:
            line+="----"for piece in row:
        line += "-----"
      if piece print(line)
== side:
# Returns if a grid is empty

def isEmpty(self,x,y):
    if self.grid[y][x] == "":      return False
        return True
    else:
        return False

# Returns the value inside a coord

def# getCoordValue(self,x,y):
Display the grid for returnthe self.grid[y][x]user

Class which handles the battleships game

class Battleships:

# Allow the user to 
 choose from 3 optionsdef show(self):

def __init__(self):       # Adding the top coordinates
    while True:   
        print("Welcome"-" to* Battleships!"45)
        printline = ""
        for i in range("You10):
 can -          line += "| " + str(i) + " "
        print("[1]line PvP\n[2]+ PvE\n[3]Just"| Shoot Ships" |")
        decisionprint("-" =* 045)

        while# decisionAdding <the 1individual orcells
 decision > 3     
        for y in range(len(self.grid)):
            tryline = ""
            for x in self.grid[y]:
                decisionif =x int(input("What== would"":
 you like to do                line += "| - "
                elif x == 0:
                    line += "| - "))
            except    elif x == 1:
                decision = 0  line += "| - "
                elif x == 2:
                    line += "| - "
                elif x == "miss":
                    line += "| X "
                elif x == "hit":
                    line += "| O "

        if decision == 1:
            self.PVP()
        elif# decisionAdding ==side 2:coordinates
            self.PVE()
        elif decision == 3:
       line += "| " + self.JSSstr(y)
   
# Adds+ a" ship|\n"

def addShip(self,grid,side,length):
    
     orientation = 0
    while orientation < 1 orfor orientationx >in 2self.grid[y]:
        try:
            orientationline+="----"
 = int(input("Would you like the ship to be horizontal [1] or verticalline [2]:+= "))
        except:-----"
            orientation = 0print(line)

    if orientation == 1:
        rootCoord = self.inputCoord(10-(length),9)
    elif orientation == 2: 
    # Returns if a rootCoordgrid =is self.inputCoord(9,10-(length))empty
    
    shipdef =isEmpty(self,x,y):
 []       if self.grid[y][x] == "":
            return True
        else:
            return False
    
    # Whilst validReturns shipthe hasvalue notinside beena addedcoord
    
    while True:
        currentShip = []
        # Add coords depending on length
        
        for i in range(length):
            if orientation == 1:
                currentShip.append([rootCoord[0]+i,rootCoord[1]])
            elif orientation == 2:
               def currentShip.appendgetCoordValue([rootCoord[0]self,rootCoord[1]+i])
                
        # Test that the coords are not filled already
        validShip = True
        for coord in currentShip:
            if grid.isEmpty(coord[0]x,coord[1]y) == False:
                # If any coords are filled then the ship is invalid
                
                validShip = False
                print("There are already ships existing there!")
                return self.addShip(grid,side,length)
                

        # If ship is valid then stop trying and return ship coords
        
        if validShip:
           ship = currentShip
           return shipgrid[y][x]

# Function returns list of shipClass lengthswhich thathandles hasthe beenbattleships sunkgame

defclass getSunkShips(self,grid,side)Battleships:

    # ListAllow ofthe sunkuser shipsto choose from 3 options
    
    sunkShipsdef __init__(self):
        while True:
            print("Welcome to Battleships!")
            print("You can - ")
            print("[1] PvP\n[2] PvE\n[3]Just Shoot Ships")
            decision = []0

    # Go through the pieces array in grid objectwhile decision < 1 or decision > 3:
    for ship in range         try:
                    decision = int(1,leninput(grid.pieces[side]"What would you like to do: "))
                except:
        sunkStatus            decision = []0

        # For each ship coordinateif indecision a== ship1:
        
         for shipCoord in gridself.pieces[side][ship]:
            PVP()
            # If the coordinate can be found in the hit list then that part has been sunk
         elif decision == 2:
            sunk = False
            for hitCoord in range(1,len(gridself.pieces[4])PVE():
                ifelif shipCoorddecision == grid.pieces[4][hitCoord][0]3:
                    sunk = Trueself.JSS()
                    break
         # Adds a sunkStatus.append(sunk)ship

        # Go through the sunk parts and if all of it is sunk then the ship isdef sunkaddShip(self,grid,side,length):
        
        sunkShiporientation = True0
        forwhile statusorientation in< sunkStatus:
1 or orientation > 2:
        if status == False try:
                sunkShiporientation = Falseint(input("Would you like the ship to be horizontal [1] or vertical [2]: "))
            except:
    break            orientation = 0

        if sunkShiporientation == 1:
            rootCoord = self.inputCoord(10-(length),9)
        elif orientation == 2: 
            rootCoord = self.inputCoord(9,10-(length))
        
        ship = []
        
        # Whilst valid ship has not been added
        
        while True:
            sunkShipscurrentShip = []
            # Add coords depending on length
            
            for i in range(length):
                if orientation == 1:
                    currentShip.append(ship+1[rootCoord[0]+i,rootCoord[1]])
    return sunkShips           elif orientation == 2:
                    currentShip.append([rootCoord[0],rootCoord[1]+i])
                    
            # MethodTest that the coords are not filled already
            validShip = True
            for whencoord thein usercurrentShip:
 wants to play against            if grid.isEmpty(coord[0],coord[1]) == False:
                    # If any coords are filled then the computership is invalid
                    
                    validShip = False
                    print("There are already ships existing there!")
                    return self.addShip(grid,side,length)
                    

def PVE(self)           # If ship is valid then stop trying and return ship coords
            
            if validShip:
               ship = currentShip
               return ship

    # CreateFunction gridsreturns list of ship lengths that has been sunk
    
    grids =def [GridgetSunkShips(10,10)self,Grid(10grid,10side)]:

    print("Now you are going to# addList yourof sunk ships.")
        
        sunkShips = []

    # Add ships for player# 1
Go through the pieces 
 array in grid object
 print("Player 1 add ships.")
    print("Youfor inputship thein rootrange(1,len(grid.pieces[side])):
 coordinate of the ship. They extend to the right or down, dependingsunkStatus on= orientation.")[]

            # AddFor shipseach ofship lengthcoordinate 2in -a 6ship
            
            for shipLengthshipCoord in range(5)grid.pieces[side][ship]:
        print("Add ship of length {}".format(shipLength+2))    
        ship        # If the coordinate can be found in the hit list then that part has been sunk
                
                sunk = self.addShip(grids[0],1,shipLength+2)False
        grids[0].addPiece        for hitCoord in range(ship,1,len(grid.pieces[4])):
        input("Press enter to continue..         if shipCoord == grid.")pieces[4][hitCoord][0]:
    self.clearScreen()                    sunk = True
    print("Okay, the grids are set!")                break
    self            sunkStatus.clearScreenappend(sunk)

            # AddGo shipsthrough the sunk parts and if all of it is sunk then the ship is sunk
            
            sunkShip = True
            for computerstatus in sunkStatus:
                if status == False:
    grids[1].grid                sunkShip = self.makeShips(grids[1],0,[1,1,1,1,1])False
                    break

            if sunkShip == True:
    turn = 1          sunkShips.append(ship+1)
        return sunkShips
                    
    # Method for when the user wants to play against the computer

    # Lists of coords the computer should shoot next
    
    compWaitList =def [[]]PVE(self):

    # Coords the computer has# triedCreate grids
    compShotList = []
   
  compSunkShips = []
    compPreviousHitsgrids = [][Grid(10,10),Grid(10,10)]

    # While there are ships on both side
    
  print("Now you whileare grids[0].isDefeated(1)going ==to Falseadd andyour grids[1]ships.isDefeated(0") == False:

        # IfAdd itships isfor player 1's turn1
        
        if turn == 1:
            
            print("Player 1's turn1 toadd shootships.")
            grids[1].showprint()
            validMove = False
          "You input 
 the root coordinate of the ship. They extend to the right or whiledown, validMovedepending ==on False:orientation.")

        # Add ships of length 2 - 6
 # Get shot input and try to shoot
        for shipLength in range(5):
     # If shot is not invalid then updateprint("Add theship gridof length {}".format(shipLength+2))
            ship = self.addShip(grids[0],1,shipLength+2)
            grids[0].addPiece(ship,1)
            input("Press enter to continue...")
  shot =     self.inputCoordclearScreen(9,9)
        print("Okay, the grids are set!")
      potentialGrid = self.shootclearScreen(grids[1],0,shot)

               # ifAdd potentialGridships !=for "invalid":computer
             
        grids[1].grid = potentialGrid
                    validMove = True
                else:
                    continue
                
            input("Press enter to continue.")
            self.clearScreen()
            printmakeShips("Current grid for Player 1.")
            grids[1].show(,0,[1,1,1,1,1])

            # Check game is won or not
            
            if grids[1].isDefeated(0) == True:
                self.clearScreen()
               turn print("Player= 1 wins!")
                input("Press enter to continue...")
                self.clearScreen()
                break

        # Lists of coords #the Ifcomputer gameshould isshoot notnext
 won, tell the players of any full ships 
 they have sunk.     compWaitList = [[]]

            self.sunkShips = self.getSunkShips(grids[1],0)
            if len(self.sunkShips) >= 1:        
              # Coords print("Playerthe 1computer has sunk...")
                for ship in self.sunkShips:
                    print("Ship of length {}.".format(ship))
            else:
                print("No ships have yet been sunk.")
                tried
            input("Press enter forcompShotList Computer's= turn.")[]
          compSunkShips = self.clearScreen()[]
            turncompPreviousHits = 2[]

        # Computer'sWhile turnthere are ships on both side
        
        ifwhile turngrids[0].isDefeated(1) == 2:
            
            print("Computer's turnFalse toand shootgrids[1]."isDefeated(0)
            
            validShot === False:

            # Get a possible xIf andit yis coordinateplayer to1's shootturn
            
            whileif validShotturn == False1:
                
                xprint("Player =1's -1turn to shoot.")
                ygrids[1].show()
                validMove = -1False
                
                if compWaitList == [[]]:
                    while x < 0 or xvalidMove >== 9False:
                        x = random.randint(0,9)

                    while# yGet <shot 0input orand ytry >to 9:shoot
                    # If shot is ynot invalid then update the grid
                    
                    shot = randomself.randintinputCoord(09,9)
                    potentialGrid = self.shoot(grids[1],0,shot)

                # Else take the first coord from the waiting list
                
                else:
                    if compWaitList[0]potentialGrid != []"invalid":
                        xgrids[1].grid = compWaitList[0][0][0]potentialGrid
                        yvalidMove = compWaitList[0][0][1]
                        compWaitList[0].pop(0)True
                    else:
                        xcontinue
 = compWaitList[1][0][0]                  
                input("Press enter to continue.")
     y = compWaitList[1][0][1]         self.clearScreen()
                print("Current grid for Player 1.")
    compWaitList[1]            grids[1].popshow(0)

                alreadyShot# =Check Falsegame is won or not
                
                if grids[1].isDefeated(0) == True:
                    self.clearScreen()
                    print("Player 1 wins!")
                    input("Press enter to continue...")
                    self.clearScreen()
                    break

                # If proposedgame xis andnot ywon, coordinatetell isthe inplayers shotof listany thenfull repeatships loopthey have sunk.

                forself.sunkShips coord= inself.getSunkShips(grids[1],0)
 compShotList               if len(self.sunkShips) >= 1:        
                    ifprint("Player coord1 ==has [x,y]sunk...")
                    for ship in self.sunkShips:
                        alreadyShotprint("Ship =of Truelength {}.".format(ship))
                else:
         break           print("No ships have yet been sunk.")
                    
                ifinput("Press alreadyShotenter ==for False:Computer's turn.")
                self.clearScreen()
       validShot         turn = True2

            print("Computer is deciding...")
            time.sleep(1)
            
            # Shoot with coords and also add them to usedComputer's coordsturn
            
            compShotList.append([x,y])if turn == 2:
            potentialGrid = self.shoot(grids[0],1,[x,y],True)  
                print("Computer"Computer's shotturn atto [{},{}]shoot.".format(x,y))
                
                validShot = False

            # If it was a# hitGet thena trypossible addingx smartand coordsy coordinate to waitshoot
 list               
                while validShot == False:
                    
                    x = -1
                    y = -1
                    
                    if potentialGrid[1]compWaitList == "hit"[[]]:
                print("The computer hit!")      while x < 0 or x > 9:
                grids[0]            x = random.showrandint(0,9)

                # If there has been previous hit of importancewhile andy there< are0 stillor possibley hit> locations9:
                if compPreviousHits != [] and compWaitList !      y = []:random.randint(0,9)

                    # If the number of sunk ship increases,Else gettake the sunk lengthfirst thencoord removefrom the last n-1 possible perpendicularwaiting coordslist
                    
                    else:
                        if compSunkShipscompWaitList[0] != self.getSunkShips(grids[0],1)[]:
                        sunkShipLength    x = self.getSunkShips(grids[0],1)compWaitList[0][0][0]
                        print(compSunkShips)    y = compWaitList[0][0][1]
                        print    compWaitList[0].pop(sunkShipLength0)
                        forelse:
 length in compSunkShips:
                         x = compWaitList[1][0][0]
 if sunkShipLength[0] == length:
                        y = compWaitList[1][0][1]
       sunkShipLength                     compWaitList[1].pop(0)

                        compSunkShips = self.getSunkShips(grids[0],1)
                        compWaitList[0]alreadyShot = []False

                    # If proposed x #and Movey thecoordinate previousis hitin toshot last,list tothen berepeat removedloop
                     for coord in compShotList:
                        compPreviousHits.append(compPreviousHits[0])if coord == [x,y]:
                        compPreviousHits.pop(0)    alreadyShot = True
                        compPreviousHits.append([x,y])    break
                        
                    if alreadyShot == False:
 del compWaitList[len(compWaitList)-sunkShipLength[0]:]                      validShot = True

                print("Computer is deciding...")
      if compWaitList == []:       time.sleep(1)
                 
            compWaitList    # Shoot with coords and also add them to used coords
                
                compShotList.append([][x,y])
                potentialGrid = self.shoot(grids[0],1,[x,y],True)
      del compPreviousHits[len         print(compPreviousHits)-sunkShipLength[0]:"Computer shot at [{},{}].".format(x,y))

                 # If it #was Elsea findhit relationthen oftry theadding twosmart coords to wait list
                 
    else            if potentialGrid[1] == "hit":
                    print("The computer hit!")
                    grids[0].show()

                    # If there has been previous hit of importance and there are still possible hit locations
                    if compPreviousHits != [] and compWaitList != []:

                        # SetIf limitsthe tonumber relatingof tosunk whethership they'reincreases, onget the edgesunk andlength tetsthen relationremove tothe last hitn-1 possible perpendicular coords
                        
                        if compPreviousHits[0][0]compSunkShips != self.getSunkShips(grids[0],1):
                            sunkShipLength = self.getSunkShips(grids[0],1)
                            print(compSunkShips)
                            print(sunkShipLength)
                            for length in compSunkShips:
                                if sunkShipLength[0] == xlength:
                                    sunkShipLength.pop(0)

                            #compSunkShips Add= nextself.getSunkShips(grids[0],1)
 parallel coord (in relation to the hit and previosuly hit coord) to high priority, and perpendicular coords to lowest priority
        compWaitList[0] = []

                  # This is so there is a higher probability of another# Move the previous hit to last, to be removed
                            
                            if compPreviousHits[0][1] < y:
                                compWaitList += [[[[x+1,y],[x-1,y]]]]
                                if y != 9:
                                    compWaitList[0] = [[[x,y+1]]] + compWaitList[0]
                            else:
                                compWaitList += [[[[x+1,y],[x-1,y]]]]compPreviousHits.append(compPreviousHits[0])
                                if y != compPreviousHits.pop(0:
                                    compWaitList[0] = [[x,y-1]] + compWaitList[0]
                                
                        elif compPreviousHits[0][1] == y:
                            if compPreviousHits[0][0] < x:)
                                compWaitList += [[[x,y-1],compPreviousHits.append([x,y+1]]]
                                if x != 9:
                                    compWaitList[0] = [[x+1,y]] + compWaitList[0]y])
                            else:
                               del compWaitList[len(compWaitList += [[[x,y)-1],[x,y+1]]]
                                if x != 0sunkShipLength[0]:
                                    compWaitList[0] = [[x-1,y]] + compWaitList[0]]

                        compPreviousHits.append(compPreviousHits[0])
                        compPreviousHits.pop(0)
                        compPreviousHits = [[x,y]] + compPreviousHits
                else:
                    
                    # Add adjacent coords to the waiting list, depending on position on the grid
                    if x == 0:
                        if ycompWaitList == 0[]:
                            compWaitList[0] = [[x+1,y]]
                            compWaitList.append([[x,y+1]][])
                        elif y == 9:
                         del compPreviousHits[len(compPreviousHits)-sunkShipLength[0]:]

  compWaitList[0] = [[x+1,y]]
                     # Else find relation of the two compWaitList.append([[x,y-1]])coords
                        else:
                            
                            # Set limits to relating to whether they're on the edge and tets relation to last hit
                            
                            if compPreviousHits[0][0] == x:

                                # Add next parallel coord (in relation to the hit and previosuly hit coord) to high priority, and perpendicular coords to lowest priority
                                # This is so there is a higher probability of another hit
                                
                                if compPreviousHits[0][1] < y:
                                    compWaitList += [[[[x+1,y],[x-1,y]]]]
                                    if y != 9:
                                        compWaitList[0] = [[[x,y+1]]] + compWaitList[0]
                                else:
                                    compWaitList += [[[[x+1,y],[x-1,y]]]]
                                    if y != 0:
                                        compWaitList[0] = [[x,y-1]] + compWaitList[0]
                                    
                            elif compPreviousHits[0][1] == y:
                                if compPreviousHits[0][0] < x:
                                    compWaitList += [[[x,y-1],[x,y+1]]]
                                    if x != 9:
                                        compWaitList[0] = [[x+1,y]] + compWaitList[0]
                                else:
                                    compWaitList += [[[x,y-1],[x,y+1]]]
                                    if x != 0:
                                        compWaitList[0] = [[x-1,y]] + compWaitList[0]

                            compPreviousHits.append(compPreviousHits[0])
                            compPreviousHits.pop(0)
                            compPreviousHits = [[x,y]] + compPreviousHits
                    else:
                        
                        # Add adjacent coords to the waiting list, depending on position on the grid
                        if x == 0:
                            if y == 0:
                                compWaitList[0] = [[x+1,y]]
                                compWaitList.append([[x,y+1]])
                            elif y == 9:
                                compWaitList[0] = [[x+1,y]]
                                compWaitList.append([[x,y-1]])
                            else:
                                compWaitList[0] = [[x+1,y]]
                                compWaitList.append([[x,y-1],[x,y+1]])
                        elif x == 9:
                            if y == 0:
                                compWaitList[0] = [[x-1,y]]
                                compWaitList.append([[x,y+1]])
                            elif y == 9:
                                compWaitList[0] = [[x-1,y]]
                                compWaitList.append([[x,y-1]])
                            else:
                                compWaitList[0] = [[x-1,y]]
                                compWaitList.append([[x,y-1],[x,y+1]])
                        elif y == 0:
                            compWaitList[0] = [[x-1,y]]
                            compWaitList.append([[x[[x+1,y],[x,y+1]])
                        elif y == 9:
                            compWaitList[0] = [[x-1,y]]
                            compWaitList.append([[x[[x+1,y],[x,y-1]])
                        else:
                            compWaitList[0] = [[x-1,y]]
                            compWaitList.append([[x,y-1],[x,y+1]])
                    elif y == 0:
                        compWaitList[0] = [[x-1,y]]
                        compWaitList.append([[x+1,y],[x,y+1]])
                    elif y == 9:
                        compWaitList[0] = [[x-1,y]]
                        compWaitList.append([[x+1,y],[x,y-1]])
                    else:
                        compWaitList[0] = [[x-1,y]]
                        compWaitList.append([[x+1,y],[x,y-1],[x,y+1]])

                        compPreviousHits.append([x,y])
                    
                    grids[0].grid = potentialGrid[0]
                    validMove = True
                else:
                    print("The computer missed!")
                    grids[0].show()
                          
                # Check game is won or not
                
                if grids[0].grid = potentialGrid[0]
                validMoveisDefeated(1) === True
            else:
                print("The computer missed!")
                grids[0]self.showclearScreen()
                      
            # Check game is won or not
            
            if grids[0].isDefeated(1) == True:
                self.clearScreenshow()
                grids[0].show()
                print("Player 2 wins!")
                    input("Press enter to continue...")
                self.clearScreen()
                break
            
            self.sunkShips = self.getSunkShips(grids[0],1)
            if len(self.sunkShips) >= 1:        
                print("Computer has sunk...")
                for ship in self.sunkShips:
                    print("Ship of length {}.".formatclearScreen(ship))
            else:
                print("No ships have yet been sunk.")break
                
            input("Press enter for Player 1'sself.sunkShips turn= self."getSunkShips(grids[0],1)
                if len(self.clearScreensunkShips) >= 1:        
                    print("Computer has sunk...")
            turn = 1      for ship in self.sunkShips:
                        print("Ship of length {}.".format(ship))
                else:
    return                print("No ships have yet been sunk.")
                    
# Function takes in a grid, the opposing side, and the coordinates     input("Press enter for thePlayer shot
1's turn.")
def shoot(               self,grid,oSide,shot,isComputer=False.clearScreen():
                turn = 1

    # Get value in the coord to be shot
    coordValue = grid.getCoordValue(shot[0],shot[1])  return    

    # IfFunction takes in a grid, the opponentopposing isside, and the computercoordinates for the shot
    
    if oSide == 0:
        
        # If value is miss or hit, it is an invalid move
        
        if coordValue == "miss":
            print("You've already shot there! Was a miss!")
            return "invalid"
        elif coordValue == "hit":
           def printshoot("You've already shot there! Was a hit!")
            return "invalid"
        
        # If blankself, miss
        
        elif coordValue == "":
            print("Miss!")
            grid.addPiece([shot],"miss"oSide,shot,isComputer=False)
            return grid.grid:

        # If computer piece, hit
 Get value in the coord to be shot
        elif coordValue == 0:
            print("Hit!")
           = grid.addPiecegetCoordValue([shot]shot[0],"hit"shot[1]) 

        # If the opponent is returnthe grid.gridcomputer
        
    elif    if oSide == 10:
            
            # If value is miss or hit, it is an invalid move
            
            if isComputercoordValue == True"miss":
            if    print("You've already shot there! Was a miss!")
                return "invalid"
            elif coordValue == "hit":
                print("You've already shot there! Was a hit!")
                return "invalid"
            
            # If blank, miss
            
            elif coordValue == "":
                print("Miss!")
                grid.addPiece([shot],"miss")
                return [gridgrid.grid

            # If computer piece,"miss"] hit
            
            elif coordValue == 10:
                print("Hit!")
                grid.addPiece([shot],"hit")
                return grid.grid
            
        elif oSide == 1:
            if isComputer == True:
                if coordValue == "":
                    grid.addPiece([shot],"miss")
                    return [grid.grid,"miss"]
                elif coordValue == 1:
                    grid.addPiece([shot],"hit")
                    return [grid.grid,"hit"]
            else:
                if coordValue == "miss":
                    print("You've already shot there! Was a miss!")
                    return "invalid"
                elif coordValue == "hit":
                    print("You've already shot there! Was a hit!")
                    return "invalid"

                # If shooting at side 2 (own), then it is invalid
                
                elif coordValue == 2:
                    print("You cannot shoot your own ships!")
                    return "invalid"
                elif coordValue == "":
                    print("Miss!")
                    grid.addPiece([shot],"miss")
                    return grid.grid
                
                # If opponet is 1 and you shoot 1 then it is hit
                
                elif coordValue == 1:
                    print("Hit!")
                    grid.addPiece([shot],"hit")
                    return grid.grid
                    
        elif oSide == 2:
            if coordValue == "miss":
                print("You've already shot there! Was a miss!")
                return "invalid"
            elif coordValue == "hit":
                print("You've already shot there! Was a hit!")
                return "invalid"

            # If shooting at side 21 (own), then it is invalid
            
            elif coordValue == 21:
                print("You cannot shoot your own ships!")
                return "invalid"
            elif coordValue == "":
                print("Miss!")
                grid.addPiece([shot],"miss")
                return grid.grid
            
            # If opponet is 12 and you shoot 12 then it is hit
            
            elif coordValue == 12:
                print("Hit!")
                grid.addPiece([shot],"hit")
                return grid.grid
                
    elif oSide == 2:
        if coordValue == "miss":
            print("You've already shot there! Was a miss!")
            return "invalid"
        elif coordValue == "hit":
            print("You've already shot there! Was a hit!")
            return "invalid"

        # If shooting at side 1 (own), then it is invalid
        
        elif coordValue == 1:
            print("You cannot shoot your own ships!")
            return "invalid"
        elif coordValue == "":
            print("Miss!")
       # Function takes in a grid.addPiece([shot],"miss")
            return grid.grid
        
        # If opponet is 2 and you shoot 2 then it is hit
 the number of different ships wanted to add
        elif coordValue == 2:
           def printmakeShips("Hit!")
            self,grid.addPiece([shot],"hit"side,shipLengths)
            return grid.grid:

        # Add ships of varying lengths
        
# Function takes in a grid, and the number of different ships wantedfor tolength add

defin makeShipsrange(self,grid,side,len(shipLengths)):

            # AddAdds shipsamount of varyingships lengthsfor that length
            for amount in range(shipLengths[length]):
                ship = self.makeShip(grid,length+2)
                grid.addPiece(ship,side)
        return grid.grid
    
    for length in range(len(shipLengths)):

        # Adds amount of ships for that length
        for amount in range(shipLengths[length]):
            ship = self.makeShip(grid,length+2)
            grid.addPiece(ship,side)
    return grid.grid

# Function returns array of coordinates for a ship

def makeShip(self,grid,length):
    ship = []

    # Randomise orientation
    
    orientation =def random.randintmakeShip(1self,2grid,length):
        ship = []

    # Whilst valid ship has not# beenRandomise addedorientation
    
     while True:
        currentShiporientation = []random.randint(1,2)

        # GetWhilst rootvalid positionship dependinghas onnot orientationbeen added
        
        while True:
            currentShip = []

        if orientation == 1:
            x = random.randint(0,10-length)
            y = random.randint(0,9)
   # Get root position depending elifon orientation == 2:
            x = random.randint(0,9)
            y = random.randint(0,10-length)

        # Add coords depending on length
        
        for i in range(length):
            if orientation == 1:
                currentShipx = random.appendrandint([x+i0,y]10-length)
                y = random.randint(0,9)
            elif orientation == 2:
                currentShipx = random.appendrandint([x0,y+i]9)
                
        # Test that the coords are not filled already
        
         validShipy = True
        for coord in currentShip:
            if gridrandom.isEmptyrandint(coord[0]0,coord[1]10-length) == False:
                
                # If any coords are filled then the ship is invalid
                
                validShip = False

        # If ship is valid then stop trying and return ship coords
        
        if validShip:
           keepTrying = False
           ship = currentShip
           return ship

# Function takes in coordinate inputs

def inputCoord           # Add coords depending on length
            
            for i in range(self,maxXlength):
                if orientation == 1:
                    currentShip.append([x+i,maxYy])
                elif orientation == 2:
    x                currentShip.append([x,y+i])
                    
            # Test that the coords are not filled already
            
            validShip = -1True
    y        for coord in currentShip:
                if grid.isEmpty(coord[0],coord[1]) == False:
                    
                    # If any coords are filled then the ship is invalid
                    
                    validShip = -1False

            # WhileIf theship coordinatesis arevalid notthen withinstop gridtrying paramsand return ship coords
            
            if validShip:
               keepTrying = False
               ship = currentShip
               return ship
    
    while x <# 0Function ortakes xin >coordinate maxX:inputs
        try:
            x =def int(inputinputCoord("Enter X coordinate: ")self,maxX,maxY):
        except:
  x = -1
        xy = -1

        # While the coordinates are not within grid params
        
        while yx < 0 or yx > maxYmaxX:
            try:
            y    x = int(input("Enter YX coordinate: "))
            except:
            y    x = -1

    return [x,y]   while y < 0 or y > maxY:
            try:
                y = int(input("Enter Y coordinate: "))
            except:
                y = -1

#Clears the console      return [x,y]

def clearScreen(self):
    print("\n"#Clears *the 100)console
    
game = Battleships  def clearScreen(self):
        print("\n" * 100) 
        
    game = Battleships()

Thank you for reading. I am a Year 12 student studying CS for my A-Levels. I have had previous Python experience but it is obviously not to professional/industry standard. Therefore, my goal for this review is for my code to be criticised, allowing me to improve towards reaching such standards.

Here is what I think I'd like a review on-

    # Battleships 2K16
    # Completed 11/11/16, 13:00
    # Developed by Tommy Kong

    # This is a Battleships game.
    # It allows players to:
    #   Play against each other
    #   Play against a computer
    #   Practice shooting ships



    import random, time

Class for creating a grid

class Grid:

# Create gird of width and height

def __init__(self,width,height):
    self.grid = []
    self.pieces = [[0],[1],[2],["miss"],["hit"]]
    for y in range(height):
        row = []
        for x in range(width):
            row.append("")
        self.grid.append(row)

# Add piece to given coordinates

def addPiece(self,piece,side):
    for pieceSet in self.pieces:
        if pieceSet[0] == side:
            pieceSet.append(piece)
            
    for coord in piece:
        self.grid[coord[1]][coord[0]] = side
    
# Function checks if the grid still has pieces of a certain side

def isDefeated(self,side):
    for row in self.grid:
        for piece in row:
            if piece == side:
                return False
    return True

# Display the grid for the user

def show(self):

    # Adding the top coordinates
    
    print("-" * 45)
    line = ""
    for i in range(10):
        line += "| " + str(i) + " "
    print(line + "|   |")
    print("-" * 45)

    # Adding the individual cells
    
    for y in range(len(self.grid)):
        line = ""
        for x in self.grid[y]:
            if x == "":
                line += "| - "
            elif x == 0:
                line += "| - "
            elif x == 1:
                line += "| - "
            elif x == 2:
                line += "| - "
            elif x == "miss":
                line += "| X "
            elif x == "hit":
                line += "| O "

        # Adding side coordinates
        
        line += "| " + str(y) + " |\n"

        for x in self.grid[y]:
            line+="----"
        line += "-----"
        print(line)

# Returns if a grid is empty

def isEmpty(self,x,y):
    if self.grid[y][x] == "":
        return True
    else:
        return False

# Returns the value inside a coord

def getCoordValue(self,x,y):
    return self.grid[y][x]

Class which handles the battleships game

class Battleships:

# Allow the user to choose from 3 options

def __init__(self):
    while True:
        print("Welcome to Battleships!")
        print("You can - ")
        print("[1] PvP\n[2] PvE\n[3]Just Shoot Ships")
        decision = 0

        while decision < 1 or decision > 3:
            try:
                decision = int(input("What would you like to do: "))
            except:
                decision = 0

        if decision == 1:
            self.PVP()
        elif decision == 2:
            self.PVE()
        elif decision == 3:
            self.JSS()
   
# Adds a ship

def addShip(self,grid,side,length):
    
     orientation = 0
    while orientation < 1 or orientation > 2:
        try:
            orientation = int(input("Would you like the ship to be horizontal [1] or vertical [2]: "))
        except:
            orientation = 0

    if orientation == 1:
        rootCoord = self.inputCoord(10-(length),9)
    elif orientation == 2: 
        rootCoord = self.inputCoord(9,10-(length))
    
    ship = []
    
    # Whilst valid ship has not been added
    
    while True:
        currentShip = []
        # Add coords depending on length
        
        for i in range(length):
            if orientation == 1:
                currentShip.append([rootCoord[0]+i,rootCoord[1]])
            elif orientation == 2:
                currentShip.append([rootCoord[0],rootCoord[1]+i])
                
        # Test that the coords are not filled already
        validShip = True
        for coord in currentShip:
            if grid.isEmpty(coord[0],coord[1]) == False:
                # If any coords are filled then the ship is invalid
                
                validShip = False
                print("There are already ships existing there!")
                return self.addShip(grid,side,length)
                

        # If ship is valid then stop trying and return ship coords
        
        if validShip:
           ship = currentShip
           return ship

# Function returns list of ship lengths that has been sunk

def getSunkShips(self,grid,side):

    # List of sunk ships
    
    sunkShips = []

    # Go through the pieces array in grid object
    for ship in range(1,len(grid.pieces[side])):
        sunkStatus = []

        # For each ship coordinate in a ship
        
         for shipCoord in grid.pieces[side][ship]:
            
            # If the coordinate can be found in the hit list then that part has been sunk
            
            sunk = False
            for hitCoord in range(1,len(grid.pieces[4])):
                if shipCoord == grid.pieces[4][hitCoord][0]:
                    sunk = True
                    break
            sunkStatus.append(sunk)

        # Go through the sunk parts and if all of it is sunk then the ship is sunk
        
        sunkShip = True
        for status in sunkStatus:
            if status == False:
                sunkShip = False
                break

        if sunkShip == True:
            sunkShips.append(ship+1)
    return sunkShips
                
# Method for when the user wants to play against the computer

def PVE(self):

    # Create grids
    
    grids = [Grid(10,10),Grid(10,10)]

    print("Now you are going to add your ships.")

    # Add ships for player 1
    
     print("Player 1 add ships.")
    print("You input the root coordinate of the ship. They extend to the right or down, depending on orientation.")

    # Add ships of length 2 - 6
    
    for shipLength in range(5):
        print("Add ship of length {}".format(shipLength+2))
        ship = self.addShip(grids[0],1,shipLength+2)
        grids[0].addPiece(ship,1)
        input("Press enter to continue...")
    self.clearScreen()
    print("Okay, the grids are set!")
    self.clearScreen()

    # Add ships for computer
    
    grids[1].grid = self.makeShips(grids[1],0,[1,1,1,1,1])

    
    turn = 1

    # Lists of coords the computer should shoot next
    
    compWaitList = [[]]

    # Coords the computer has tried
    compShotList = []
    compSunkShips = []
    compPreviousHits = []

    # While there are ships on both side
    
    while grids[0].isDefeated(1) == False and grids[1].isDefeated(0) == False:

        # If it is player 1's turn
        
        if turn == 1:
            
            print("Player 1's turn to shoot.")
            grids[1].show()
            validMove = False
            
             while validMove == False:

                # Get shot input and try to shoot
                # If shot is not invalid then update the grid
                
                shot = self.inputCoord(9,9)
                potentialGrid = self.shoot(grids[1],0,shot)

                if potentialGrid != "invalid":
                    grids[1].grid = potentialGrid
                    validMove = True
                else:
                    continue
                
            input("Press enter to continue.")
            self.clearScreen()
            print("Current grid for Player 1.")
            grids[1].show()

            # Check game is won or not
            
            if grids[1].isDefeated(0) == True:
                self.clearScreen()
                print("Player 1 wins!")
                input("Press enter to continue...")
                self.clearScreen()
                break

            # If game is not won, tell the players of any full ships they have sunk.

            self.sunkShips = self.getSunkShips(grids[1],0)
            if len(self.sunkShips) >= 1:        
                print("Player 1 has sunk...")
                for ship in self.sunkShips:
                    print("Ship of length {}.".format(ship))
            else:
                print("No ships have yet been sunk.")
                
            input("Press enter for Computer's turn.")
            self.clearScreen()
            turn = 2

        # Computer's turn
        
        if turn == 2:
            
            print("Computer's turn to shoot.")
            
            validShot = False

            # Get a possible x and y coordinate to shoot
            
            while validShot == False:
                
                x = -1
                y = -1
                
                if compWaitList == [[]]:
                    while x < 0 or x > 9:
                        x = random.randint(0,9)

                    while y < 0 or y > 9:
                        y = random.randint(0,9)

                # Else take the first coord from the waiting list
                
                else:
                    if compWaitList[0] != []:
                        x = compWaitList[0][0][0]
                        y = compWaitList[0][0][1]
                        compWaitList[0].pop(0)
                    else:
                        x = compWaitList[1][0][0]
                        y = compWaitList[1][0][1]
                        compWaitList[1].pop(0)

                alreadyShot = False

                # If proposed x and y coordinate is in shot list then repeat loop
                for coord in compShotList:
                    if coord == [x,y]:
                        alreadyShot = True
                        break
                    
                if alreadyShot == False:
                    validShot = True

            print("Computer is deciding...")
            time.sleep(1)
            
            # Shoot with coords and also add them to used coords
            
            compShotList.append([x,y])
            potentialGrid = self.shoot(grids[0],1,[x,y],True)
            print("Computer shot at [{},{}].".format(x,y))

            # If it was a hit then try adding smart coords to wait list
            
            if potentialGrid[1] == "hit":
                print("The computer hit!")
                grids[0].show()

                # If there has been previous hit of importance and there are still possible hit locations
                if compPreviousHits != [] and compWaitList != []:

                    # If the number of sunk ship increases, get the sunk length then remove the last n-1 possible perpendicular coords
                    
                    if compSunkShips != self.getSunkShips(grids[0],1):
                        sunkShipLength = self.getSunkShips(grids[0],1)
                        print(compSunkShips)
                        print(sunkShipLength)
                        for length in compSunkShips:
                            if sunkShipLength[0] == length:
                                sunkShipLength.pop(0)

                        compSunkShips = self.getSunkShips(grids[0],1)
                        compWaitList[0] = []

                        # Move the previous hit to last, to be removed
                        
                        compPreviousHits.append(compPreviousHits[0])
                        compPreviousHits.pop(0)
                        compPreviousHits.append([x,y])
                        
                        del compWaitList[len(compWaitList)-sunkShipLength[0]:]

                        if compWaitList == []:
                            compWaitList.append([])
                        del compPreviousHits[len(compPreviousHits)-sunkShipLength[0]:]

                    # Else find relation of the two coords
                    else:
                        
                        # Set limits to relating to whether they're on the edge and tets relation to last hit
                        
                        if compPreviousHits[0][0] == x:

                            # Add next parallel coord (in relation to the hit and previosuly hit coord) to high priority, and perpendicular coords to lowest priority
                            # This is so there is a higher probability of another hit
                            
                            if compPreviousHits[0][1] < y:
                                compWaitList += [[[[x+1,y],[x-1,y]]]]
                                if y != 9:
                                    compWaitList[0] = [[[x,y+1]]] + compWaitList[0]
                            else:
                                compWaitList += [[[[x+1,y],[x-1,y]]]]
                                if y != 0:
                                    compWaitList[0] = [[x,y-1]] + compWaitList[0]
                                
                        elif compPreviousHits[0][1] == y:
                            if compPreviousHits[0][0] < x:
                                compWaitList += [[[x,y-1],[x,y+1]]]
                                if x != 9:
                                    compWaitList[0] = [[x+1,y]] + compWaitList[0]
                            else:
                                compWaitList += [[[x,y-1],[x,y+1]]]
                                if x != 0:
                                    compWaitList[0] = [[x-1,y]] + compWaitList[0]

                        compPreviousHits.append(compPreviousHits[0])
                        compPreviousHits.pop(0)
                        compPreviousHits = [[x,y]] + compPreviousHits
                else:
                    
                    # Add adjacent coords to the waiting list, depending on position on the grid
                    if x == 0:
                        if y == 0:
                            compWaitList[0] = [[x+1,y]]
                            compWaitList.append([[x,y+1]])
                        elif y == 9:
                            compWaitList[0] = [[x+1,y]]
                            compWaitList.append([[x,y-1]])
                        else:
                            compWaitList[0] = [[x+1,y]]
                            compWaitList.append([[x,y-1],[x,y+1]])
                    elif x == 9:
                        if y == 0:
                            compWaitList[0] = [[x-1,y]]
                            compWaitList.append([[x,y+1]])
                        elif y == 9:
                            compWaitList[0] = [[x-1,y]]
                            compWaitList.append([[x,y-1]])
                        else:
                            compWaitList[0] = [[x-1,y]]
                            compWaitList.append([[x,y-1],[x,y+1]])
                    elif y == 0:
                        compWaitList[0] = [[x-1,y]]
                        compWaitList.append([[x+1,y],[x,y+1]])
                    elif y == 9:
                        compWaitList[0] = [[x-1,y]]
                        compWaitList.append([[x+1,y],[x,y-1]])
                    else:
                        compWaitList[0] = [[x-1,y]]
                        compWaitList.append([[x+1,y],[x,y-1],[x,y+1]])

                    compPreviousHits.append([x,y])
                
                grids[0].grid = potentialGrid[0]
                validMove = True
            else:
                print("The computer missed!")
                grids[0].show()
                      
            # Check game is won or not
            
            if grids[0].isDefeated(1) == True:
                self.clearScreen()
                grids[0].show()
                print("Player 2 wins!")
                input("Press enter to continue...")
                self.clearScreen()
                break
            
            self.sunkShips = self.getSunkShips(grids[0],1)
            if len(self.sunkShips) >= 1:        
                print("Computer has sunk...")
                for ship in self.sunkShips:
                    print("Ship of length {}.".format(ship))
            else:
                print("No ships have yet been sunk.")
                
            input("Press enter for Player 1's turn.")
            self.clearScreen()
            turn = 1

        
    return    

# Function takes in a grid, the opposing side, and the coordinates for the shot

def shoot(self,grid,oSide,shot,isComputer=False):

    # Get value in the coord to be shot
    coordValue = grid.getCoordValue(shot[0],shot[1])

    # If the opponent is the computer
    
    if oSide == 0:
        
        # If value is miss or hit, it is an invalid move
        
        if coordValue == "miss":
            print("You've already shot there! Was a miss!")
            return "invalid"
        elif coordValue == "hit":
            print("You've already shot there! Was a hit!")
            return "invalid"
        
        # If blank, miss
        
        elif coordValue == "":
            print("Miss!")
            grid.addPiece([shot],"miss")
            return grid.grid

        # If computer piece, hit
        
        elif coordValue == 0:
            print("Hit!")
            grid.addPiece([shot],"hit")
            return grid.grid
        
    elif oSide == 1:
        if isComputer == True:
            if coordValue == "":
                grid.addPiece([shot],"miss")
                return [grid.grid,"miss"]
            elif coordValue == 1:
                grid.addPiece([shot],"hit")
                return [grid.grid,"hit"]
        else:
            if coordValue == "miss":
                print("You've already shot there! Was a miss!")
                return "invalid"
            elif coordValue == "hit":
                print("You've already shot there! Was a hit!")
                return "invalid"

            # If shooting at side 2 (own), then it is invalid
            
            elif coordValue == 2:
                print("You cannot shoot your own ships!")
                return "invalid"
            elif coordValue == "":
                print("Miss!")
                grid.addPiece([shot],"miss")
                return grid.grid
            
            # If opponet is 1 and you shoot 1 then it is hit
            
            elif coordValue == 1:
                print("Hit!")
                grid.addPiece([shot],"hit")
                return grid.grid
                
    elif oSide == 2:
        if coordValue == "miss":
            print("You've already shot there! Was a miss!")
            return "invalid"
        elif coordValue == "hit":
            print("You've already shot there! Was a hit!")
            return "invalid"

        # If shooting at side 1 (own), then it is invalid
        
        elif coordValue == 1:
            print("You cannot shoot your own ships!")
            return "invalid"
        elif coordValue == "":
            print("Miss!")
            grid.addPiece([shot],"miss")
            return grid.grid
        
        # If opponet is 2 and you shoot 2 then it is hit
        
        elif coordValue == 2:
            print("Hit!")
            grid.addPiece([shot],"hit")
            return grid.grid

        
# Function takes in a grid, and the number of different ships wanted to add

def makeShips(self,grid,side,shipLengths):

    # Add ships of varying lengths
    
    for length in range(len(shipLengths)):

        # Adds amount of ships for that length
        for amount in range(shipLengths[length]):
            ship = self.makeShip(grid,length+2)
            grid.addPiece(ship,side)
    return grid.grid

# Function returns array of coordinates for a ship

def makeShip(self,grid,length):
    ship = []

    # Randomise orientation
    
    orientation = random.randint(1,2)

    # Whilst valid ship has not been added
    
     while True:
        currentShip = []

        # Get root position depending on orientation

        if orientation == 1:
            x = random.randint(0,10-length)
            y = random.randint(0,9)
        elif orientation == 2:
            x = random.randint(0,9)
            y = random.randint(0,10-length)

        # Add coords depending on length
        
        for i in range(length):
            if orientation == 1:
                currentShip.append([x+i,y])
            elif orientation == 2:
                currentShip.append([x,y+i])
                
        # Test that the coords are not filled already
        
         validShip = True
        for coord in currentShip:
            if grid.isEmpty(coord[0],coord[1]) == False:
                
                # If any coords are filled then the ship is invalid
                
                validShip = False

        # If ship is valid then stop trying and return ship coords
        
        if validShip:
           keepTrying = False
           ship = currentShip
           return ship

# Function takes in coordinate inputs

def inputCoord(self,maxX,maxY):
    x = -1
    y = -1

    # While the coordinates are not within grid params
    
    while x < 0 or x > maxX:
        try:
            x = int(input("Enter X coordinate: "))
        except:
            x = -1

    while y < 0 or y > maxY:
        try:
            y = int(input("Enter Y coordinate: "))
        except:
            y = -1

    return [x,y]

#Clears the console

def clearScreen(self):
    print("\n" * 100)
    
game = Battleships()          

I am a Year 12 student studying CS for my A-Levels. I have had previous Python experience but it is obviously not to professional/industry standard. Therefore, my goal for this review is for my code to be criticised, allowing me to improve towards reaching such standards.

Here is what I think I'd like a review on:

# Battleships 2K16
# Completed 11/11/16, 13:00
# Developed by Tommy Kong

# This is a Battleships game.
# It allows players to:
#   Play against each other
#   Play against a computer
#   Practice shooting ships



import random, time


# Class for creating a grid

class Grid:

    # Create gird of width and height
    
    def __init__(self,width,height):
        self.grid = []
        self.pieces = [[0],[1],[2],["miss"],["hit"]]
        for y in range(height):
            row = []
            for x in range(width):
                row.append("")
            self.grid.append(row)

    # Add piece to given coordinates
    
    def addPiece(self,piece,side):
        for pieceSet in self.pieces:
            if pieceSet[0] == side:
                pieceSet.append(piece)
                
        for coord in piece:
            self.grid[coord[1]][coord[0]] = side
        
    # Function checks if the grid still has pieces of a certain side
    
    def isDefeated(self,side):
        for row in self.grid:
            for piece in row:
                if piece == side:
                    return False
        return True

    # Display the grid for the user
     
    def show(self):

        # Adding the top coordinates
        
        print("-" * 45)
        line = ""
        for i in range(10):
            line += "| " + str(i) + " "
        print(line + "|   |")
        print("-" * 45)

        # Adding the individual cells
        
        for y in range(len(self.grid)):
            line = ""
            for x in self.grid[y]:
                if x == "":
                    line += "| - "
                elif x == 0:
                    line += "| - "
                elif x == 1:
                    line += "| - "
                elif x == 2:
                    line += "| - "
                elif x == "miss":
                    line += "| X "
                elif x == "hit":
                    line += "| O "

            # Adding side coordinates
            
            line += "| " + str(y) + " |\n"

            for x in self.grid[y]:
                line+="----"
            line += "-----"
            print(line)

    # Returns if a grid is empty
    
    def isEmpty(self,x,y):
        if self.grid[y][x] == "":
            return True
        else:
            return False
    
    # Returns the value inside a coord
    
    def getCoordValue(self,x,y):
        return self.grid[y][x]

# Class which handles the battleships game

class Battleships:

    # Allow the user to choose from 3 options
    
    def __init__(self):
        while True:
            print("Welcome to Battleships!")
            print("You can - ")
            print("[1] PvP\n[2] PvE\n[3]Just Shoot Ships")
            decision = 0

            while decision < 1 or decision > 3:
                try:
                    decision = int(input("What would you like to do: "))
                except:
                    decision = 0

            if decision == 1:
                self.PVP()
            elif decision == 2:
                self.PVE()
            elif decision == 3:
                self.JSS()
       
    # Adds a ship

    def addShip(self,grid,side,length):
        
        orientation = 0
        while orientation < 1 or orientation > 2:
            try:
                orientation = int(input("Would you like the ship to be horizontal [1] or vertical [2]: "))
            except:
                orientation = 0

        if orientation == 1:
            rootCoord = self.inputCoord(10-(length),9)
        elif orientation == 2: 
            rootCoord = self.inputCoord(9,10-(length))
        
        ship = []
        
        # Whilst valid ship has not been added
        
        while True:
            currentShip = []
            # Add coords depending on length
            
            for i in range(length):
                if orientation == 1:
                    currentShip.append([rootCoord[0]+i,rootCoord[1]])
                elif orientation == 2:
                    currentShip.append([rootCoord[0],rootCoord[1]+i])
                    
            # Test that the coords are not filled already
            validShip = True
            for coord in currentShip:
                if grid.isEmpty(coord[0],coord[1]) == False:
                    # If any coords are filled then the ship is invalid
                    
                    validShip = False
                    print("There are already ships existing there!")
                    return self.addShip(grid,side,length)
                    

            # If ship is valid then stop trying and return ship coords
            
            if validShip:
               ship = currentShip
               return ship

    # Function returns list of ship lengths that has been sunk
    
    def getSunkShips(self,grid,side):

        # List of sunk ships
        
        sunkShips = []

        # Go through the pieces array in grid object
        for ship in range(1,len(grid.pieces[side])):
            sunkStatus = []

            # For each ship coordinate in a ship
            
            for shipCoord in grid.pieces[side][ship]:
                
                # If the coordinate can be found in the hit list then that part has been sunk
                
                sunk = False
                for hitCoord in range(1,len(grid.pieces[4])):
                    if shipCoord == grid.pieces[4][hitCoord][0]:
                        sunk = True
                        break
                sunkStatus.append(sunk)

            # Go through the sunk parts and if all of it is sunk then the ship is sunk
            
            sunkShip = True
            for status in sunkStatus:
                if status == False:
                    sunkShip = False
                    break

            if sunkShip == True:
                sunkShips.append(ship+1)
        return sunkShips
                    
    # Method for when the user wants to play against the computer

    def PVE(self):

        # Create grids
         
        grids = [Grid(10,10),Grid(10,10)]

        print("Now you are going to add your ships.")

        # Add ships for player 1
        
        print("Player 1 add ships.")
        print("You input the root coordinate of the ship. They extend to the right or down, depending on orientation.")

        # Add ships of length 2 - 6
        
        for shipLength in range(5):
            print("Add ship of length {}".format(shipLength+2))
            ship = self.addShip(grids[0],1,shipLength+2)
            grids[0].addPiece(ship,1)
            input("Press enter to continue...")
        self.clearScreen()
        print("Okay, the grids are set!")
        self.clearScreen()

        # Add ships for computer
         
        grids[1].grid = self.makeShips(grids[1],0,[1,1,1,1,1])

        
        turn = 1

        # Lists of coords the computer should shoot next
         
        compWaitList = [[]]

        # Coords the computer has tried
        compShotList = []
        compSunkShips = []
        compPreviousHits = []

        # While there are ships on both side
        
        while grids[0].isDefeated(1) == False and grids[1].isDefeated(0) == False:

            # If it is player 1's turn
            
            if turn == 1:
                
                print("Player 1's turn to shoot.")
                grids[1].show()
                validMove = False
                
                while validMove == False:

                    # Get shot input and try to shoot
                    # If shot is not invalid then update the grid
                    
                    shot = self.inputCoord(9,9)
                    potentialGrid = self.shoot(grids[1],0,shot)

                    if potentialGrid != "invalid":
                        grids[1].grid = potentialGrid
                        validMove = True
                    else:
                        continue
                    
                input("Press enter to continue.")
                self.clearScreen()
                print("Current grid for Player 1.")
                grids[1].show()

                # Check game is won or not
                
                if grids[1].isDefeated(0) == True:
                    self.clearScreen()
                    print("Player 1 wins!")
                    input("Press enter to continue...")
                    self.clearScreen()
                    break

                # If game is not won, tell the players of any full ships they have sunk.

                self.sunkShips = self.getSunkShips(grids[1],0)
                if len(self.sunkShips) >= 1:        
                    print("Player 1 has sunk...")
                    for ship in self.sunkShips:
                        print("Ship of length {}.".format(ship))
                else:
                    print("No ships have yet been sunk.")
                    
                input("Press enter for Computer's turn.")
                self.clearScreen()
                turn = 2

            # Computer's turn
            
            if turn == 2:
                
                print("Computer's turn to shoot.")
                
                validShot = False

                # Get a possible x and y coordinate to shoot
                
                while validShot == False:
                    
                    x = -1
                    y = -1
                    
                    if compWaitList == [[]]:
                        while x < 0 or x > 9:
                            x = random.randint(0,9)

                        while y < 0 or y > 9:
                            y = random.randint(0,9)

                    # Else take the first coord from the waiting list
                    
                    else:
                        if compWaitList[0] != []:
                            x = compWaitList[0][0][0]
                            y = compWaitList[0][0][1]
                            compWaitList[0].pop(0)
                        else:
                            x = compWaitList[1][0][0]
                            y = compWaitList[1][0][1]
                            compWaitList[1].pop(0)

                    alreadyShot = False

                    # If proposed x and y coordinate is in shot list then repeat loop
                    for coord in compShotList:
                        if coord == [x,y]:
                            alreadyShot = True
                            break
                        
                    if alreadyShot == False:
                        validShot = True

                print("Computer is deciding...")
                time.sleep(1)
                 
                # Shoot with coords and also add them to used coords
                
                compShotList.append([x,y])
                potentialGrid = self.shoot(grids[0],1,[x,y],True)
                print("Computer shot at [{},{}].".format(x,y))

                # If it was a hit then try adding smart coords to wait list
                 
                if potentialGrid[1] == "hit":
                    print("The computer hit!")
                    grids[0].show()

                    # If there has been previous hit of importance and there are still possible hit locations
                    if compPreviousHits != [] and compWaitList != []:

                        # If the number of sunk ship increases, get the sunk length then remove the last n-1 possible perpendicular coords
                        
                        if compSunkShips != self.getSunkShips(grids[0],1):
                            sunkShipLength = self.getSunkShips(grids[0],1)
                            print(compSunkShips)
                            print(sunkShipLength)
                            for length in compSunkShips:
                                if sunkShipLength[0] == length:
                                    sunkShipLength.pop(0)

                            compSunkShips = self.getSunkShips(grids[0],1)
                            compWaitList[0] = []

                            # Move the previous hit to last, to be removed
                            
                            compPreviousHits.append(compPreviousHits[0])
                            compPreviousHits.pop(0)
                            compPreviousHits.append([x,y])
                            
                            del compWaitList[len(compWaitList)-sunkShipLength[0]:]

                            if compWaitList == []:
                                compWaitList.append([])
                            del compPreviousHits[len(compPreviousHits)-sunkShipLength[0]:]

                        # Else find relation of the two coords
                        else:
                            
                            # Set limits to relating to whether they're on the edge and tets relation to last hit
                            
                            if compPreviousHits[0][0] == x:

                                # Add next parallel coord (in relation to the hit and previosuly hit coord) to high priority, and perpendicular coords to lowest priority
                                # This is so there is a higher probability of another hit
                                
                                if compPreviousHits[0][1] < y:
                                    compWaitList += [[[[x+1,y],[x-1,y]]]]
                                    if y != 9:
                                        compWaitList[0] = [[[x,y+1]]] + compWaitList[0]
                                else:
                                    compWaitList += [[[[x+1,y],[x-1,y]]]]
                                    if y != 0:
                                        compWaitList[0] = [[x,y-1]] + compWaitList[0]
                                    
                            elif compPreviousHits[0][1] == y:
                                if compPreviousHits[0][0] < x:
                                    compWaitList += [[[x,y-1],[x,y+1]]]
                                    if x != 9:
                                        compWaitList[0] = [[x+1,y]] + compWaitList[0]
                                else:
                                    compWaitList += [[[x,y-1],[x,y+1]]]
                                    if x != 0:
                                        compWaitList[0] = [[x-1,y]] + compWaitList[0]

                            compPreviousHits.append(compPreviousHits[0])
                            compPreviousHits.pop(0)
                            compPreviousHits = [[x,y]] + compPreviousHits
                    else:
                        
                        # Add adjacent coords to the waiting list, depending on position on the grid
                        if x == 0:
                            if y == 0:
                                compWaitList[0] = [[x+1,y]]
                                compWaitList.append([[x,y+1]])
                            elif y == 9:
                                compWaitList[0] = [[x+1,y]]
                                compWaitList.append([[x,y-1]])
                            else:
                                compWaitList[0] = [[x+1,y]]
                                compWaitList.append([[x,y-1],[x,y+1]])
                        elif x == 9:
                            if y == 0:
                                compWaitList[0] = [[x-1,y]]
                                compWaitList.append([[x,y+1]])
                            elif y == 9:
                                compWaitList[0] = [[x-1,y]]
                                compWaitList.append([[x,y-1]])
                            else:
                                compWaitList[0] = [[x-1,y]]
                                compWaitList.append([[x,y-1],[x,y+1]])
                        elif y == 0:
                            compWaitList[0] = [[x-1,y]]
                            compWaitList.append([[x+1,y],[x,y+1]])
                        elif y == 9:
                            compWaitList[0] = [[x-1,y]]
                            compWaitList.append([[x+1,y],[x,y-1]])
                        else:
                            compWaitList[0] = [[x-1,y]]
                            compWaitList.append([[x+1,y],[x,y-1],[x,y+1]])

                        compPreviousHits.append([x,y])
                    
                    grids[0].grid = potentialGrid[0]
                    validMove = True
                else:
                    print("The computer missed!")
                    grids[0].show()
                          
                # Check game is won or not
                
                if grids[0].isDefeated(1) == True:
                    self.clearScreen()
                    grids[0].show()
                    print("Player 2 wins!")
                    input("Press enter to continue...")
                    self.clearScreen()
                    break
                
                self.sunkShips = self.getSunkShips(grids[0],1)
                if len(self.sunkShips) >= 1:        
                    print("Computer has sunk...")
                    for ship in self.sunkShips:
                        print("Ship of length {}.".format(ship))
                else:
                    print("No ships have yet been sunk.")
                    
                input("Press enter for Player 1's turn.")
                self.clearScreen()
                turn = 1

            
        return    

    # Function takes in a grid, the opposing side, and the coordinates for the shot
    
    def shoot(self,grid,oSide,shot,isComputer=False):

        # Get value in the coord to be shot
        coordValue = grid.getCoordValue(shot[0],shot[1]) 

        # If the opponent is the computer
        
        if oSide == 0:
            
            # If value is miss or hit, it is an invalid move
            
            if coordValue == "miss":
                print("You've already shot there! Was a miss!")
                return "invalid"
            elif coordValue == "hit":
                print("You've already shot there! Was a hit!")
                return "invalid"
            
            # If blank, miss
            
            elif coordValue == "":
                print("Miss!")
                grid.addPiece([shot],"miss")
                return grid.grid

            # If computer piece, hit
            
            elif coordValue == 0:
                print("Hit!")
                grid.addPiece([shot],"hit")
                return grid.grid
            
        elif oSide == 1:
            if isComputer == True:
                if coordValue == "":
                    grid.addPiece([shot],"miss")
                    return [grid.grid,"miss"]
                elif coordValue == 1:
                    grid.addPiece([shot],"hit")
                    return [grid.grid,"hit"]
            else:
                if coordValue == "miss":
                    print("You've already shot there! Was a miss!")
                    return "invalid"
                elif coordValue == "hit":
                    print("You've already shot there! Was a hit!")
                    return "invalid"

                # If shooting at side 2 (own), then it is invalid
                
                elif coordValue == 2:
                    print("You cannot shoot your own ships!")
                    return "invalid"
                elif coordValue == "":
                    print("Miss!")
                    grid.addPiece([shot],"miss")
                    return grid.grid
                
                # If opponet is 1 and you shoot 1 then it is hit
                
                elif coordValue == 1:
                    print("Hit!")
                    grid.addPiece([shot],"hit")
                    return grid.grid
                    
        elif oSide == 2:
            if coordValue == "miss":
                print("You've already shot there! Was a miss!")
                return "invalid"
            elif coordValue == "hit":
                print("You've already shot there! Was a hit!")
                return "invalid"

            # If shooting at side 1 (own), then it is invalid
            
            elif coordValue == 1:
                print("You cannot shoot your own ships!")
                return "invalid"
            elif coordValue == "":
                print("Miss!")
                grid.addPiece([shot],"miss")
                return grid.grid
            
            # If opponet is 2 and you shoot 2 then it is hit
            
            elif coordValue == 2:
                print("Hit!")
                grid.addPiece([shot],"hit")
                return grid.grid

            
    # Function takes in a grid, and the number of different ships wanted to add
    
    def makeShips(self,grid,side,shipLengths):

        # Add ships of varying lengths
        
        for length in range(len(shipLengths)):

            # Adds amount of ships for that length
            for amount in range(shipLengths[length]):
                ship = self.makeShip(grid,length+2)
                grid.addPiece(ship,side)
        return grid.grid
    
    # Function returns array of coordinates for a ship
    
    def makeShip(self,grid,length):
        ship = []

        # Randomise orientation
        
        orientation = random.randint(1,2)

        # Whilst valid ship has not been added
        
        while True:
            currentShip = []

            # Get root position depending on orientation

            if orientation == 1:
                x = random.randint(0,10-length)
                y = random.randint(0,9)
            elif orientation == 2:
                x = random.randint(0,9)
                y = random.randint(0,10-length)

            # Add coords depending on length
            
            for i in range(length):
                if orientation == 1:
                    currentShip.append([x+i,y])
                elif orientation == 2:
                    currentShip.append([x,y+i])
                    
            # Test that the coords are not filled already
            
            validShip = True
            for coord in currentShip:
                if grid.isEmpty(coord[0],coord[1]) == False:
                    
                    # If any coords are filled then the ship is invalid
                    
                    validShip = False

            # If ship is valid then stop trying and return ship coords
            
            if validShip:
               keepTrying = False
               ship = currentShip
               return ship
    
    # Function takes in coordinate inputs
    
    def inputCoord(self,maxX,maxY):
        x = -1
        y = -1

        # While the coordinates are not within grid params
        
        while x < 0 or x > maxX:
            try:
                x = int(input("Enter X coordinate: "))
            except:
                x = -1

        while y < 0 or y > maxY:
            try:
                y = int(input("Enter Y coordinate: "))
            except:
                y = -1

        return [x,y]

    #Clears the console
    
    def clearScreen(self):
        print("\n" * 100) 
        
    game = Battleships()
Source Link

Battleships Player vs Computer Algorithm

Thank you for reading. I am a Year 12 student studying CS for my A-Levels. I have had previous Python experience but it is obviously not to professional/industry standard. Therefore, my goal for this review is for my code to be criticised, allowing me to improve towards reaching such standards.

The program is a computer version of the Battleships game. I have taken out the PvP and "Just Shoot Ships" methods. I believe the most interesting part is the PVE() function. This is whether the logic is implemented for the computer to play against the player.

Here is what I think I'd like a review on-

  • The use of variables and their names
  • The use of classes - how I've passed objects into functions; I think my use of classes and passing in objects is fairly inconsistent. I would like to know if there is a way I could improve this.
  • The use of list and whether it is good practice to use jagged arrays in such a way.
  • The efficiency of my algorithm in general if possible.
  • The effectiveness of commenting and how it can be improved to be more useful in a team environment

    # Battleships 2K16
    # Completed 11/11/16, 13:00
    # Developed by Tommy Kong

    # This is a Battleships game.
    # It allows players to:
    #   Play against each other
    #   Play against a computer
    #   Practice shooting ships



    import random, time

Class for creating a grid

class Grid:

# Create gird of width and height

def __init__(self,width,height):
    self.grid = []
    self.pieces = [[0],[1],[2],["miss"],["hit"]]
    for y in range(height):
        row = []
        for x in range(width):
            row.append("")
        self.grid.append(row)

# Add piece to given coordinates

def addPiece(self,piece,side):
    for pieceSet in self.pieces:
        if pieceSet[0] == side:
            pieceSet.append(piece)
            
    for coord in piece:
        self.grid[coord[1]][coord[0]] = side
    
# Function checks if the grid still has pieces of a certain side

def isDefeated(self,side):
    for row in self.grid:
        for piece in row:
            if piece == side:
                return False
    return True

# Display the grid for the user

def show(self):

    # Adding the top coordinates
    
    print("-" * 45)
    line = ""
    for i in range(10):
        line += "| " + str(i) + " "
    print(line + "|   |")
    print("-" * 45)

    # Adding the individual cells
    
    for y in range(len(self.grid)):
        line = ""
        for x in self.grid[y]:
            if x == "":
                line += "| - "
            elif x == 0:
                line += "| - "
            elif x == 1:
                line += "| - "
            elif x == 2:
                line += "| - "
            elif x == "miss":
                line += "| X "
            elif x == "hit":
                line += "| O "

        # Adding side coordinates
        
        line += "| " + str(y) + " |\n"

        for x in self.grid[y]:
            line+="----"
        line += "-----"
        print(line)

# Returns if a grid is empty

def isEmpty(self,x,y):
    if self.grid[y][x] == "":
        return True
    else:
        return False

# Returns the value inside a coord

def getCoordValue(self,x,y):
    return self.grid[y][x]

Class which handles the battleships game

class Battleships:

# Allow the user to choose from 3 options

def __init__(self):
    while True:
        print("Welcome to Battleships!")
        print("You can - ")
        print("[1] PvP\n[2] PvE\n[3]Just Shoot Ships")
        decision = 0

        while decision < 1 or decision > 3:
            try:
                decision = int(input("What would you like to do: "))
            except:
                decision = 0

        if decision == 1:
            self.PVP()
        elif decision == 2:
            self.PVE()
        elif decision == 3:
            self.JSS()
   
# Adds a ship

def addShip(self,grid,side,length):
    
    orientation = 0
    while orientation < 1 or orientation > 2:
        try:
            orientation = int(input("Would you like the ship to be horizontal [1] or vertical [2]: "))
        except:
            orientation = 0

    if orientation == 1:
        rootCoord = self.inputCoord(10-(length),9)
    elif orientation == 2: 
        rootCoord = self.inputCoord(9,10-(length))
    
    ship = []
    
    # Whilst valid ship has not been added
    
    while True:
        currentShip = []
        # Add coords depending on length
        
        for i in range(length):
            if orientation == 1:
                currentShip.append([rootCoord[0]+i,rootCoord[1]])
            elif orientation == 2:
                currentShip.append([rootCoord[0],rootCoord[1]+i])
                
        # Test that the coords are not filled already
        validShip = True
        for coord in currentShip:
            if grid.isEmpty(coord[0],coord[1]) == False:
                # If any coords are filled then the ship is invalid
                
                validShip = False
                print("There are already ships existing there!")
                return self.addShip(grid,side,length)
                

        # If ship is valid then stop trying and return ship coords
        
        if validShip:
           ship = currentShip
           return ship

# Function returns list of ship lengths that has been sunk

def getSunkShips(self,grid,side):

    # List of sunk ships
    
    sunkShips = []

    # Go through the pieces array in grid object
    for ship in range(1,len(grid.pieces[side])):
        sunkStatus = []

        # For each ship coordinate in a ship
        
        for shipCoord in grid.pieces[side][ship]:
            
            # If the coordinate can be found in the hit list then that part has been sunk
            
            sunk = False
            for hitCoord in range(1,len(grid.pieces[4])):
                if shipCoord == grid.pieces[4][hitCoord][0]:
                    sunk = True
                    break
            sunkStatus.append(sunk)

        # Go through the sunk parts and if all of it is sunk then the ship is sunk
        
        sunkShip = True
        for status in sunkStatus:
            if status == False:
                sunkShip = False
                break

        if sunkShip == True:
            sunkShips.append(ship+1)
    return sunkShips
                
# Method for when the user wants to play against the computer

def PVE(self):

    # Create grids
    
    grids = [Grid(10,10),Grid(10,10)]

    print("Now you are going to add your ships.")

    # Add ships for player 1
    
    print("Player 1 add ships.")
    print("You input the root coordinate of the ship. They extend to the right or down, depending on orientation.")

    # Add ships of length 2 - 6
    
    for shipLength in range(5):
        print("Add ship of length {}".format(shipLength+2))
        ship = self.addShip(grids[0],1,shipLength+2)
        grids[0].addPiece(ship,1)
        input("Press enter to continue...")
    self.clearScreen()
    print("Okay, the grids are set!")
    self.clearScreen()

    # Add ships for computer
    
    grids[1].grid = self.makeShips(grids[1],0,[1,1,1,1,1])

    
    turn = 1

    # Lists of coords the computer should shoot next
    
    compWaitList = [[]]

    # Coords the computer has tried
    compShotList = []
    compSunkShips = []
    compPreviousHits = []

    # While there are ships on both side
    
    while grids[0].isDefeated(1) == False and grids[1].isDefeated(0) == False:

        # If it is player 1's turn
        
        if turn == 1:
            
            print("Player 1's turn to shoot.")
            grids[1].show()
            validMove = False
            
            while validMove == False:

                # Get shot input and try to shoot
                # If shot is not invalid then update the grid
                
                shot = self.inputCoord(9,9)
                potentialGrid = self.shoot(grids[1],0,shot)

                if potentialGrid != "invalid":
                    grids[1].grid = potentialGrid
                    validMove = True
                else:
                    continue
                
            input("Press enter to continue.")
            self.clearScreen()
            print("Current grid for Player 1.")
            grids[1].show()

            # Check game is won or not
            
            if grids[1].isDefeated(0) == True:
                self.clearScreen()
                print("Player 1 wins!")
                input("Press enter to continue...")
                self.clearScreen()
                break

            # If game is not won, tell the players of any full ships they have sunk.

            self.sunkShips = self.getSunkShips(grids[1],0)
            if len(self.sunkShips) >= 1:        
                print("Player 1 has sunk...")
                for ship in self.sunkShips:
                    print("Ship of length {}.".format(ship))
            else:
                print("No ships have yet been sunk.")
                
            input("Press enter for Computer's turn.")
            self.clearScreen()
            turn = 2

        # Computer's turn
        
        if turn == 2:
            
            print("Computer's turn to shoot.")
            
            validShot = False

            # Get a possible x and y coordinate to shoot
            
            while validShot == False:
                
                x = -1
                y = -1
                
                if compWaitList == [[]]:
                    while x < 0 or x > 9:
                        x = random.randint(0,9)

                    while y < 0 or y > 9:
                        y = random.randint(0,9)

                # Else take the first coord from the waiting list
                
                else:
                    if compWaitList[0] != []:
                        x = compWaitList[0][0][0]
                        y = compWaitList[0][0][1]
                        compWaitList[0].pop(0)
                    else:
                        x = compWaitList[1][0][0]
                        y = compWaitList[1][0][1]
                        compWaitList[1].pop(0)

                alreadyShot = False

                # If proposed x and y coordinate is in shot list then repeat loop
                for coord in compShotList:
                    if coord == [x,y]:
                        alreadyShot = True
                        break
                    
                if alreadyShot == False:
                    validShot = True

            print("Computer is deciding...")
            time.sleep(1)
            
            # Shoot with coords and also add them to used coords
            
            compShotList.append([x,y])
            potentialGrid = self.shoot(grids[0],1,[x,y],True)
            print("Computer shot at [{},{}].".format(x,y))

            # If it was a hit then try adding smart coords to wait list
            
            if potentialGrid[1] == "hit":
                print("The computer hit!")
                grids[0].show()

                # If there has been previous hit of importance and there are still possible hit locations
                if compPreviousHits != [] and compWaitList != []:

                    # If the number of sunk ship increases, get the sunk length then remove the last n-1 possible perpendicular coords
                    
                    if compSunkShips != self.getSunkShips(grids[0],1):
                        sunkShipLength = self.getSunkShips(grids[0],1)
                        print(compSunkShips)
                        print(sunkShipLength)
                        for length in compSunkShips:
                            if sunkShipLength[0] == length:
                                sunkShipLength.pop(0)

                        compSunkShips = self.getSunkShips(grids[0],1)
                        compWaitList[0] = []

                        # Move the previous hit to last, to be removed
                        
                        compPreviousHits.append(compPreviousHits[0])
                        compPreviousHits.pop(0)
                        compPreviousHits.append([x,y])
                        
                        del compWaitList[len(compWaitList)-sunkShipLength[0]:]

                        if compWaitList == []:
                            compWaitList.append([])
                        del compPreviousHits[len(compPreviousHits)-sunkShipLength[0]:]

                    # Else find relation of the two coords
                    else:
                        
                        # Set limits to relating to whether they're on the edge and tets relation to last hit
                        
                        if compPreviousHits[0][0] == x:

                            # Add next parallel coord (in relation to the hit and previosuly hit coord) to high priority, and perpendicular coords to lowest priority
                            # This is so there is a higher probability of another hit
                            
                            if compPreviousHits[0][1] < y:
                                compWaitList += [[[[x+1,y],[x-1,y]]]]
                                if y != 9:
                                    compWaitList[0] = [[[x,y+1]]] + compWaitList[0]
                            else:
                                compWaitList += [[[[x+1,y],[x-1,y]]]]
                                if y != 0:
                                    compWaitList[0] = [[x,y-1]] + compWaitList[0]
                                
                        elif compPreviousHits[0][1] == y:
                            if compPreviousHits[0][0] < x:
                                compWaitList += [[[x,y-1],[x,y+1]]]
                                if x != 9:
                                    compWaitList[0] = [[x+1,y]] + compWaitList[0]
                            else:
                                compWaitList += [[[x,y-1],[x,y+1]]]
                                if x != 0:
                                    compWaitList[0] = [[x-1,y]] + compWaitList[0]

                        compPreviousHits.append(compPreviousHits[0])
                        compPreviousHits.pop(0)
                        compPreviousHits = [[x,y]] + compPreviousHits
                else:
                    
                    # Add adjacent coords to the waiting list, depending on position on the grid
                    if x == 0:
                        if y == 0:
                            compWaitList[0] = [[x+1,y]]
                            compWaitList.append([[x,y+1]])
                        elif y == 9:
                            compWaitList[0] = [[x+1,y]]
                            compWaitList.append([[x,y-1]])
                        else:
                            compWaitList[0] = [[x+1,y]]
                            compWaitList.append([[x,y-1],[x,y+1]])
                    elif x == 9:
                        if y == 0:
                            compWaitList[0] = [[x-1,y]]
                            compWaitList.append([[x,y+1]])
                        elif y == 9:
                            compWaitList[0] = [[x-1,y]]
                            compWaitList.append([[x,y-1]])
                        else:
                            compWaitList[0] = [[x-1,y]]
                            compWaitList.append([[x,y-1],[x,y+1]])
                    elif y == 0:
                        compWaitList[0] = [[x-1,y]]
                        compWaitList.append([[x+1,y],[x,y+1]])
                    elif y == 9:
                        compWaitList[0] = [[x-1,y]]
                        compWaitList.append([[x+1,y],[x,y-1]])
                    else:
                        compWaitList[0] = [[x-1,y]]
                        compWaitList.append([[x+1,y],[x,y-1],[x,y+1]])

                    compPreviousHits.append([x,y])
                
                grids[0].grid = potentialGrid[0]
                validMove = True
            else:
                print("The computer missed!")
                grids[0].show()
                      
            # Check game is won or not
            
            if grids[0].isDefeated(1) == True:
                self.clearScreen()
                grids[0].show()
                print("Player 2 wins!")
                input("Press enter to continue...")
                self.clearScreen()
                break
            
            self.sunkShips = self.getSunkShips(grids[0],1)
            if len(self.sunkShips) >= 1:        
                print("Computer has sunk...")
                for ship in self.sunkShips:
                    print("Ship of length {}.".format(ship))
            else:
                print("No ships have yet been sunk.")
                
            input("Press enter for Player 1's turn.")
            self.clearScreen()
            turn = 1

        
    return    

# Function takes in a grid, the opposing side, and the coordinates for the shot

def shoot(self,grid,oSide,shot,isComputer=False):

    # Get value in the coord to be shot
    coordValue = grid.getCoordValue(shot[0],shot[1])

    # If the opponent is the computer
    
    if oSide == 0:
        
        # If value is miss or hit, it is an invalid move
        
        if coordValue == "miss":
            print("You've already shot there! Was a miss!")
            return "invalid"
        elif coordValue == "hit":
            print("You've already shot there! Was a hit!")
            return "invalid"
        
        # If blank, miss
        
        elif coordValue == "":
            print("Miss!")
            grid.addPiece([shot],"miss")
            return grid.grid

        # If computer piece, hit
        
        elif coordValue == 0:
            print("Hit!")
            grid.addPiece([shot],"hit")
            return grid.grid
        
    elif oSide == 1:
        if isComputer == True:
            if coordValue == "":
                grid.addPiece([shot],"miss")
                return [grid.grid,"miss"]
            elif coordValue == 1:
                grid.addPiece([shot],"hit")
                return [grid.grid,"hit"]
        else:
            if coordValue == "miss":
                print("You've already shot there! Was a miss!")
                return "invalid"
            elif coordValue == "hit":
                print("You've already shot there! Was a hit!")
                return "invalid"

            # If shooting at side 2 (own), then it is invalid
            
            elif coordValue == 2:
                print("You cannot shoot your own ships!")
                return "invalid"
            elif coordValue == "":
                print("Miss!")
                grid.addPiece([shot],"miss")
                return grid.grid
            
            # If opponet is 1 and you shoot 1 then it is hit
            
            elif coordValue == 1:
                print("Hit!")
                grid.addPiece([shot],"hit")
                return grid.grid
                
    elif oSide == 2:
        if coordValue == "miss":
            print("You've already shot there! Was a miss!")
            return "invalid"
        elif coordValue == "hit":
            print("You've already shot there! Was a hit!")
            return "invalid"

        # If shooting at side 1 (own), then it is invalid
        
        elif coordValue == 1:
            print("You cannot shoot your own ships!")
            return "invalid"
        elif coordValue == "":
            print("Miss!")
            grid.addPiece([shot],"miss")
            return grid.grid
        
        # If opponet is 2 and you shoot 2 then it is hit
        
        elif coordValue == 2:
            print("Hit!")
            grid.addPiece([shot],"hit")
            return grid.grid

        
# Function takes in a grid, and the number of different ships wanted to add

def makeShips(self,grid,side,shipLengths):

    # Add ships of varying lengths
    
    for length in range(len(shipLengths)):

        # Adds amount of ships for that length
        for amount in range(shipLengths[length]):
            ship = self.makeShip(grid,length+2)
            grid.addPiece(ship,side)
    return grid.grid

# Function returns array of coordinates for a ship

def makeShip(self,grid,length):
    ship = []

    # Randomise orientation
    
    orientation = random.randint(1,2)

    # Whilst valid ship has not been added
    
    while True:
        currentShip = []

        # Get root position depending on orientation

        if orientation == 1:
            x = random.randint(0,10-length)
            y = random.randint(0,9)
        elif orientation == 2:
            x = random.randint(0,9)
            y = random.randint(0,10-length)

        # Add coords depending on length
        
        for i in range(length):
            if orientation == 1:
                currentShip.append([x+i,y])
            elif orientation == 2:
                currentShip.append([x,y+i])
                
        # Test that the coords are not filled already
        
        validShip = True
        for coord in currentShip:
            if grid.isEmpty(coord[0],coord[1]) == False:
                
                # If any coords are filled then the ship is invalid
                
                validShip = False

        # If ship is valid then stop trying and return ship coords
        
        if validShip:
           keepTrying = False
           ship = currentShip
           return ship

# Function takes in coordinate inputs

def inputCoord(self,maxX,maxY):
    x = -1
    y = -1

    # While the coordinates are not within grid params
    
    while x < 0 or x > maxX:
        try:
            x = int(input("Enter X coordinate: "))
        except:
            x = -1

    while y < 0 or y > maxY:
        try:
            y = int(input("Enter Y coordinate: "))
        except:
            y = -1

    return [x,y]

#Clears the console

def clearScreen(self):
    print("\n" * 100)
    
game = Battleships()