Esempio n. 1
0
def run_start():
    """
    This procedure draws the background battleship image and prompts the player to hit the space bar to play.
    :return: void
    """

    screen.blit(imageBattleshipSurface, (0, 0))

    battleshipTextBox = TextBox("Battleship!",
                                (SCREEN_WIDTH / 3, SCREEN_HEIGHT / 4),
                                fontsize=96)
    screen.blit(battleshipTextBox.surface, battleshipTextBox.rect)

    instructionsTextBox = TextBox("Press the SPACE bar to play",
                                  (SCREEN_WIDTH / 3, SCREEN_HEIGHT / 2),
                                  fontsize=48)
    screen.blit(instructionsTextBox.surface, instructionsTextBox.rect)

    pygame.display.flip()

    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            elif event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
                return
Esempio n. 2
0
    def run_rotate_ship(shipLength, anchorCoord, firstOrientation):
        """
        This is a sub-procedure to the 'run_choose_board_location' procedure and corresponds to the state where the player rotates their "anchored" ship.
        :param shipLength: int - the placement ship's length
        :param anchorCoord: coordinate (row, col) - the pivot coordinate of the ship's rotation
        :param firstOrientation: int - an orientation code (0-3) representing the initial orientation of the ship
        :return: a list of coordinates representing the placed coordinates of the ship or None if the user escapes
        """
        instructionsTextBoxRotate = TextBox("Use the UP (counter-clockwise) and DOWN (clockwise) arrow keys to rotate your ship.", (96, 10), fontsize=36)
        instructionsTextBoxEnter = TextBox("Press SPACE when you are satisfied with the orientation.", (96, 56), fontsize=36)

        screen.blit(instructionsTextBoxClick.surface, instructionsTextBoxClick.surface.fill(colors['BLACK']).move(instructionsTextBoxClick.window_coord))

        blit_objects(screen, [instructionsTextBoxEnter, instructionsTextBoxRotate, instructionsTextBoxEscape])
        pygame.display.flip()

        placeList = orientation_to_coord_list(anchorCoord, shipLength, firstOrientation)
        orientation = firstOrientation

        while True:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()
                elif event.type == pygame.KEYDOWN:
                    playNavigate()
                    if event.key == pygame.K_ESCAPE:
                        cover_instructions(screen, instructionsTextBoxRotate)
                        cover_instructions(screen, instructionsTextBoxEnter)
                        cover_instructions(screen, instructionsTextBoxEscape)
                        cover_instructions(screen, instructionsTextBoxClick)
                        escape_placement()
                        return None
                    elif event.key == pygame.K_UP and is_possible_orientation(anchorCoord, shipLength, orientation + 1, otherShipCoords):
                        orientation = (orientation + 1) % 4
                    elif event.key == pygame.K_DOWN and is_possible_orientation(anchorCoord, shipLength, orientation - 1, otherShipCoords):
                        orientation = (orientation - 1) % 4
                    elif event.key == pygame.K_SPACE:
                        cover_instructions(screen, instructionsTextBoxRotate)
                        cover_instructions(screen, instructionsTextBoxEnter)
                        cover_instructions(screen, instructionsTextBoxEscape)
                        cover_instructions(screen, instructionsTextBoxClick)
                        escape_placement()
                        pygame.display.flip()
                        return placeList
            placeList = orientation_to_coord_list(anchorCoord, shipLength, orientation)
            blit_board(screen, generate_placement_board(encode_placement_board(placeList, otherShipCoords)))
            pygame.display.flip()
            pygame.time.delay(100)
Esempio n. 3
0
def winner_screen_prompt_replay(winnerName):
    """
    This is a display screen procedure that displays the game's winner and prompts the user to click whether or not to play again.
    :param winnerName: string - the name of the game's winner
    :return: bool - represents whether or not to play again
    """
    screen.fill(colors['BLACK'])
    # display the winner text box
    winnerTextBox = TextBox("{} has won the game!".format(winnerName),
                            (130, 48),
                            fontsize=96,
                            textcolor=colors['GREEN'])
    # display the play again prompt
    playAgainTextBox = TextBox(
        "Would you like to play again? Click either 'YES' or 'NO'.",
        (90, SCREEN_HEIGHT * (3 / 8)),
        fontsize=56)
    # display the 'Yes' and 'No' boxes
    yesBox = TextBox("YES", ((SCREEN_WIDTH / 3) -
                             (128 * (2 / 3)), SCREEN_HEIGHT * (3 / 4)),
                     fontsize=128,
                     textcolor=colors['GREEN'])
    noBox = TextBox("NO", ((SCREEN_WIDTH * (2 / 3)) -
                           (128 * (2 / 3)), SCREEN_HEIGHT * (3 / 4)),
                    fontsize=128,
                    textcolor=colors['RED'])
    blit_objects(screen, [winnerTextBox, playAgainTextBox, yesBox, noBox])
    pygame.display.flip()
    # wait for click

    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            elif event.type == MOUSEBUTTONDOWN:
                clickedOnBox = get_intersect_object_from_list(
                    event.pos, [yesBox, noBox])
                if clickedOnBox is not None:
                    screen.fill(colors['BLACK'])
                    pygame.display.flip()
                    if clickedOnBox is yesBox:
                        return True
                    return False
        pygame.time.delay(200)
Esempio n. 4
0
def run_get_number_ships():
    """
    This prompts the user to select a number box. It returns an integer value for the number of ships that the game will be played with.
    :return: int from 1-5 representing the number of ships to play with
    """

    # define background, instruction, box for each number of ships
    def create_number_boxes():
        def create_number_box(j):
            x = SCREEN_WIDTH / 5
            y = SCREEN_HEIGHT - (SCREEN_HEIGHT / 3)
            return TextBox("{}".format(j), ((x * j) - 128, y), fontsize=128)

        return reduce(lambda others, j: others + [create_number_box(j)],
                      [1, 2, 3, 4, 5], [])

    instructionsTextBox = TextBox("Click the number of ships to play with:",
                                  (SCREEN_WIDTH / 7, SCREEN_HEIGHT / 3),
                                  fontsize=64)
    numberBoxes = create_number_boxes()

    # draw background
    screen.blit(imageBattleshipSurface, (0, 0))

    # draw instruction
    screen.blit(instructionsTextBox.surface, instructionsTextBox.rect)

    # draw number boxes
    for box in numberBoxes:
        screen.blit(box.surface, box.rect)

    pygame.display.flip()

    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            elif event.type == pygame.MOUSEBUTTONDOWN:
                for i in [1, 2, 3, 4, 5]:
                    if numberBoxes[i - 1].rect.collidepoint(event.pos):
                        return i
Esempio n. 5
0
def winner_screen_prompt_replay(winnerName, isAI, win_score):
    """
    This is a display screen procedure that displays the game's winner and prompts the user to click whether or not to play again.
    :param winnerName: string - the name of the game's winner
    :param isAI: bool - true if game is player vs ai, false when game is player vs player
    :param win_score: Scoreboard - the scoreboard for the game
    :return: bool - represents whether or not to play again
    """
    pygame.mixer.music.stop()
    pygame.mixer.music.load('../sounds/win.mp3')
    pygame.mixer.music.play(0)
    screen.fill(colors['BLACK'])
    # display the winner text box
    winnerTextBox = TextBox("{} has won the game!".format(winnerName), (130, 48), fontsize=96, textcolor=colors['GREEN'])
    # display the play again prompt
    playAgainTextBox = TextBox("Would you like to play again? Click either 'YES' or 'NO'.", (90, SCREEN_HEIGHT * (3 / 8)), fontsize=56)
    # display the 'Yes' and 'No' boxes
    yesBox = TextBox("YES", ((SCREEN_WIDTH / 3) - (128 * (2 / 3)), SCREEN_HEIGHT * (3 / 4)), fontsize=128, textcolor=colors['GREEN'])
    noBox = TextBox("NO", ((SCREEN_WIDTH * (2 / 3)) - (128 * (2 / 3)), SCREEN_HEIGHT * (3 / 4)), fontsize=128, textcolor=colors['RED'])

    if isAI:
        scoreBox = TextBox("Player 1 Score: " + str(win_score.get_p1_wins()) + "    AI Score: " + str(win_score.get_ai_wins()),
                            (45, 150), fontsize=90, textcolor=colors['BLUE'])
    else:
        scoreBox = TextBox("Player 1 Score: " + str(win_score.get_p1_wins()) + "    Player 2 Score: " + str(win_score.get_p2_wins()),
                            (45, 150), fontsize=90, textcolor=colors['BLUE'])

    blit_objects(screen, [winnerTextBox, playAgainTextBox, yesBox, noBox, scoreBox])
    pygame.display.flip()
    # wait for click

    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            elif event.type == MOUSEBUTTONDOWN:
                clickedOnBox = get_intersect_object_from_list(event.pos, [yesBox, noBox])
                if clickedOnBox is not None:
                    playNavigate()
                    screen.fill(colors['BLACK'])
                    pygame.display.flip()
                    if clickedOnBox is yesBox:
                        return True
                    return False
        pygame.time.delay(200)
Esempio n. 6
0
def run_get_num_players():
    """
    This will display a screen where users can select if they want to play with one or two players.
    """
    # define background, instruction, box for each number of ships
    def create_number_boxes():
        def create_number_box(j):
            x = SCREEN_WIDTH / 2
            y = SCREEN_HEIGHT - (SCREEN_HEIGHT / 3)
            return TextBox("{}".format(j), ((x * j) - 300, y), fontsize=128)
        return reduce(lambda others, j: others + [create_number_box(j)], [1, 2], [])


    instructionsTextBox = TextBox("Do you want to play with one or two players?", (SCREEN_WIDTH / 7, SCREEN_HEIGHT / 3), fontsize=64)
    numberBoxes = create_number_boxes()

    # draw background
    screen.blit(imageBattleshipSurface, (0, 0))

    # draw instruction
    screen.blit(instructionsTextBox.surface, instructionsTextBox.rect)

    # draw number boxes
    for box in numberBoxes:
        screen.blit(box.surface, box.rect)

    pygame.display.flip()

    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            elif event.type == pygame.MOUSEBUTTONDOWN:
                for i in [1, 2]:
                    if numberBoxes[i - 1].rect.collidepoint(event.pos):
                        playNavigate()
                        return i
Esempio n. 7
0
def run_get_ai_difficulty_level():
    """
    This will display a screen where users can select the difficulty of the AI to play agianst in one player mode
    """
    # define background, instruction, box for each number of ships
    def create_number_boxes():
        def create_number_box(j):
            x = SCREEN_WIDTH / 3
            y = SCREEN_HEIGHT - (SCREEN_HEIGHT / 3)
            return TextBox("{}".format(j), ((x * j) - 200, y), fontsize=128)
        return reduce(lambda others, j: others + [create_number_box(j)], [1, 2, 3], [])


    instructionsTextBox = TextBox("Select AI diffiuclty: 1) Easy, 2) Medium, 3) Hard", (SCREEN_WIDTH / 7, SCREEN_HEIGHT / 3), fontsize=64)
    numberBoxes = create_number_boxes()

    # draw background
    screen.blit(imageBattleshipSurface, (0, 0))

    # draw instruction
    screen.blit(instructionsTextBox.surface, instructionsTextBox.rect)

    # draw number boxes
    for box in numberBoxes:
        screen.blit(box.surface, box.rect)

    pygame.display.flip()

    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            elif event.type == pygame.MOUSEBUTTONDOWN:
                for i in [1, 2, 3]:
                    if numberBoxes[i - 1].rect.collidepoint(event.pos):
                        playNavigate()
                        return i
Esempio n. 8
0
def run_place_ships(numShips, playerName):
    """
    This is a procedure that allows the user to interactively place their ships on a placement board. It iterates until all ships are placed.
    :param numShips: int - represents the number of placeable ships
    :param playerName: string - used to display the message prompting the user to place their ships
    :return: a list of list of coordinates. Each sub list represents the grouping of a ship.
    """

    # define the board to place on
    placeBoard = Board(((SCREEN_WIDTH / 3), (SCREEN_HEIGHT / 6)),
                       (SCREEN_WIDTH / 2), (SCREEN_HEIGHT * (2 / 3)))

    instructionsTextBox1 = TextBox(
        "Click a blue ship on the left to select it for placement.", (48, 48))

    instructionsTextBoxEscape = TextBox(
        "Press the ESC button to cancel placing this ship.", (96, 102),
        fontsize=36)

    instructionsTextBoxClick = TextBox(
        "Click an anchor box on the grid. You will then be able to rotate your ship.",
        (48, 48))

    def ship_size_to_coord(size):
        queueWidth = SCREEN_WIDTH / 3
        queueHeight = SCREEN_HEIGHT * (2 / 3)
        queueX = SCREEN_WIDTH / 8
        queueY = SCREEN_HEIGHT / 4

        firstColX = queueX
        firstRowY = queueY

        secondColX = queueX + (queueWidth * (1 / 3))

        switch = {
            1: (firstColX, firstRowY),
            2: (firstColX, firstRowY + (placeBoard.squareHeight * 2)),
            3: (firstColX, firstRowY + (placeBoard.squareHeight * 5)),
            4: (secondColX, firstRowY),
            5: (secondColX, firstRowY + (placeBoard.squareHeight * 5))
        }
        return switch[size]

    # define ship surfaces based on numShips - they sit to the left of the board

    def create_ship_queue(n):
        return reduce(
            lambda prevs, i: prevs + [
                Ship(i, placeBoard.squareWidth - 1, placeBoard.squareHeight -
                     1, ship_size_to_coord(i))
            ], range(1, n + 1), [])

    shipQueue = create_ship_queue(numShips)

    # black the screen
    screen.fill(colors['BLACK'])
    pygame.display.flip()

    # blit_objects(screen, placeBoard.squares + placeBoard.rowLabels + placeBoard.colLabels)
    # blit_objects(screen, shipQueue)
    # screen.blit(instructionsTextBox1.surface, instructionsTextBox1.rect)

    def get_clicked_ship(pos):
        return get_intersect_object_from_list(pos, shipQueue)

    # Display the welcome message
    welcomeBox = TextBox("{}, place your ships!".format(playerName),
                         (130, SCREEN_HEIGHT / 3),
                         fontsize=96,
                         textcolor=colors['GREEN'])
    screen.blit(welcomeBox.surface, welcomeBox.rect)
    pygame.display.update(welcomeBox.rect)
    pygame.time.delay(2000)
    screen.fill(colors['BLACK'])

    # event loop
    shipCoordsList = []

    while True:
        if not shipQueue:
            screen.fill((0, 0, 0))
            pygame.display.flip()
            return list(
                filter(lambda e: not isinstance(e, tuple), shipCoordsList))
        screen.blit(instructionsTextBox1.surface, instructionsTextBox1.rect)
        blit_objects(screen, shipQueue)
        blit_board(
            screen,
            generate_placement_board(
                encode_placement_board([], flatten(shipCoordsList))))
        screen.blit(instructionsTextBox1.surface, instructionsTextBox1.rect)
        pygame.display.flip()
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            elif event.type == pygame.MOUSEBUTTONDOWN:
                clickedShip = get_clicked_ship(event.pos)
                if clickedShip is not None:
                    # highlight ship in the queue
                    highlight(screen, clickedShip, colors['GREEN'])
                    chosenLocation = run_choose_board_location(
                        clickedShip, shipCoordsList)
                    if chosenLocation is None:
                        cover_instructions(screen, instructionsTextBoxEscape)
                        cover_instructions(screen, instructionsTextBoxClick)
                        highlight(screen, clickedShip, colors['BLUE'])
                    else:
                        shipCoordsList += [chosenLocation]
                        shipQueue.remove(clickedShip)
                        highlight(screen, clickedShip, colors['BLACK'])
                        # blit_objects(screen, shipQueue)
        screen.blit(instructionsTextBox1.surface, instructionsTextBox1.rect)
        pygame.display.flip()
        pygame.time.delay(200)
Esempio n. 9
0
 def create_number_box(j):
     x = SCREEN_WIDTH / 5
     y = SCREEN_HEIGHT - (SCREEN_HEIGHT / 3)
     return TextBox("{}".format(j), ((x * j) - 128, y), fontsize=128)
Esempio n. 10
0
 def generate_sunk_ship_alert(shipLength):
     return TextBox("You sunk the other player's {}".format(
         ship_length_to_name(shipLength)),
                    (SCREEN_WIDTH / 4, SCREEN_HEIGHT * (9 / 10)),
                    textcolor=colors['GREEN'])
Esempio n. 11
0
def run_game_loop(shipCoords1, shipCoords2):
    """
    This is the main game loop for battleship. It consists of a loop the allows one player to guess, stores that guess, updates the current player, and then switches the turn.
    :param shipCoords1: a list of lists of coordinates corresponding to the first player's chosen ship locations.
    :param shipCoords2: a list of lists of coordinates corresponding to the second player's chosen ship locations.
    :return: string - the name of the player who won (either "Player 1" or "Player 2")
    """

    switchTurnsInstructionsBox = TextBox(
        "Press the SPACE key to switch turns.", (240, 48))
    switchTurnsInstructionsBox2 = TextBox(
        "Please switch spots with your playing partner. Press any key to continue.",
        (35, SCREEN_HEIGHT / 2),
        fontsize=44)
    guessBoardLabel = TextBox("Attack Board", (200, SCREEN_HEIGHT / 5),
                              textcolor=colors['RED'])
    myBoardLabel = TextBox("My Board", (SCREEN_WIDTH - 370, SCREEN_HEIGHT / 5),
                           textcolor=colors['GREEN'])
    hitTextBox = TextBox("Hit!",
                         ((SCREEN_WIDTH / 2) - 70, SCREEN_HEIGHT * (8 / 10)),
                         textcolor=colors['GREEN'],
                         fontsize=96)
    missTextBox = TextBox("Miss.",
                          ((SCREEN_WIDTH / 2) - 70, SCREEN_HEIGHT * (8 / 10)),
                          textcolor=colors['RED'],
                          fontsize=96)

    player1 = Player(shipCoords1, "Player 1")
    player2 = Player(shipCoords2, "Player 2")
    state = State(player1, player2)

    def generate_sunk_ship_alert(shipLength):
        return TextBox("You sunk the other player's {}".format(
            ship_length_to_name(shipLength)),
                       (SCREEN_WIDTH / 4, SCREEN_HEIGHT * (9 / 10)),
                       textcolor=colors['GREEN'])

    def produce_guess_board():
        return generate_guess_board(
            encode_guess_board(state.player1.guesses, state.player2.ships))

    def produce_guessed_at_board():
        return generate_guessed_at_board(
            encode_guessed_at_board(state.player2.guesses,
                                    state.player1.ships))

    def wait_for_click_guess(square):
        while True:
            for event in pygame.event.get():
                if event.type == pygame.MOUSEBUTTONDOWN and square.rect.collidepoint(
                        event.pos):
                    return square.grid_coord
                elif event.type == pygame.MOUSEMOTION and not square.rect.collidepoint(
                        event.pos):
                    return None
            pygame.time.delay(30)

    def run_switch_turns():
        # display switch turns instruction message
        screen.blit(switchTurnsInstructionsBox.surface,
                    switchTurnsInstructionsBox.rect)
        pygame.display.flip()
        # wait till they hit SPACE
        while True:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()
                elif event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
                    # black the screen
                    screen.fill((0, 0, 0))
                    # display the instructions to switch turns
                    screen.blit(switchTurnsInstructionsBox2.surface,
                                switchTurnsInstructionsBox2.rect)
                    pygame.display.flip()
                    while True:
                        for event in pygame.event.get():
                            if event.type == pygame.QUIT:
                                pygame.quit()
                                sys.exit()
                            elif event.type == KEYDOWN or event.type == MOUSEBUTTONDOWN:
                                screen.fill(colors['BLACK'])
                                return True
            pygame.time.delay(50)
        return False

    while True:
        whosTurnTextBox = TextBox("{}'s Turn".format(state.player1.name),
                                  (SCREEN_WIDTH * (3 / 8), 40),
                                  fontsize=64,
                                  textcolor=colors['GREEN'])
        guessInstructionsTextBox = TextBox(
            "Click a coordinate on the Attack Board to fire a missile!",
            (110, 96))
        initialGuessBoard = produce_guess_board()
        blit_board(screen, initialGuessBoard)
        blit_board(screen, produce_guessed_at_board())
        blit_objects(screen, [
            guessBoardLabel, myBoardLabel, guessInstructionsTextBox,
            whosTurnTextBox
        ])
        pygame.display.flip()
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            elif event.type == MOUSEMOTION:
                hoveredSquare = get_hovered_square(event.pos,
                                                   initialGuessBoard)
                if (hoveredSquare
                        is not None) and (hoveredSquare.grid_coord
                                          not in state.player1.guesses):
                    highlight(screen, hoveredSquare, colors['YELLOW'])
                    guess = wait_for_click_guess(hoveredSquare)
                    if guess is not None:
                        pygame.draw.rect(screen, colors['BLACK'],
                                         guessInstructionsTextBox.rect)
                        pygame.draw.rect(screen, colors['BLACK'],
                                         whosTurnTextBox.rect)
                        if hit(guess, state.player2.ships):
                            highlight(screen, hoveredSquare, colors['GREEN'])
                            screen.blit(hitTextBox.surface, hitTextBox.rect)
                            sunkenShipLength = which_sunk(
                                guess, state.player1.guesses,
                                state.player2.ships)
                            state.update(guess)
                            if sunkenShipLength is not None:
                                sunkAlertBox = generate_sunk_ship_alert(
                                    sunkenShipLength)
                                screen.blit(sunkAlertBox.surface,
                                            sunkAlertBox.rect)
                                pygame.display.flip()
                                if state.is_game_over():
                                    pygame.display.flip()
                                    pygame.time.delay(2000)
                                    screen.fill(colors['BLACK'])
                                    return state.player2.name
                        else:
                            highlight(screen, hoveredSquare, colors['RED'])
                            screen.blit(missTextBox.surface, missTextBox.rect)
                            state.update(guess)
                        pygame.display.flip()
                        pygame.time.delay(1500)
                        if run_switch_turns():
                            screen.fill(colors['BLACK'])
                            break
        pygame.display.flip()
        pygame.time.delay(30)
Esempio n. 12
0
def run_choose_board_location(ship, otherShipCoords):
    """
    This is a sub-procedure to the procedure 'run_placed_ships'. Logically, this represents the state for the player to place an already selected ship.
    :param ship: a Ship object that holds the information about its length and other properties
    :param otherShipCoords: a list of all the other previously-placed coordinates. Used prevent invalid placement.
    :return: a list of coordinates corresponding to where the ship was placed or None if the user escapes the transaction
    """
    instructionsTextBoxClick = TextBox(
        "Click an anchor box on the grid. You will then be able to rotate your ship.",
        (48, 48))
    instructionsTextBoxEscape = TextBox(
        "Press the ESC button to cancel placing this ship.", (96, 102),
        fontsize=36)

    otherCoordsPairsList = list(map(lambda coord: (coord, 2), otherShipCoords))

    ## display a board with the other placed ships' coordinates filled in
    initialBoard = generate_placement_board(otherCoordsPairsList)

    def escape_placement():
        blit_board(screen, initialBoard)
        pygame.display.flip()

    # highlight the updateBoard squares that correspond to each coordinate in the passed in list of coordinates
    # just display a new board?
    def display_suggestion_placement_board(coordList):
        codePairs = encode_placement_board(coordList, otherCoordsPairsList)
        blit_board(screen, generate_placement_board(codePairs))

    def wait_for_click_display(board, square):
        while True:
            blit_board(screen, board)
            pygame.display.flip()
            for event in pygame.event.get():
                if event.type == pygame.MOUSEBUTTONDOWN and square.rect.collidepoint(
                        event.pos):
                    return True
                elif event.type == pygame.MOUSEMOTION and not square.rect.collidepoint(
                        event.pos):
                    return False
                elif event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
                    cover_instructions(screen, instructionsTextBoxEscape)
                    cover_instructions(screen, instructionsTextBoxClick)
                    return None
            pygame.time.delay(100)

    def run_rotate_ship(shipLength, anchorCoord, firstOrientation):
        """
        This is a sub-procedure to the 'run_choose_board_location' procedure and corresponds to the state where the player rotates their "anchored" ship.
        :param shipLength: int - the placement ship's length
        :param anchorCoord: coordinate (row, col) - the pivot coordinate of the ship's rotation
        :param firstOrientation: int - an orientation code (0-3) representing the initial orientation of the ship
        :return: a list of coordinates representing the placed coordinates of the ship or None if the user escapes
        """
        instructionsTextBoxRotate = TextBox(
            "Use the UP (counter-clockwise) and DOWN (clockwise) arrow keys to rotate your ship.",
            (96, 10),
            fontsize=36)
        instructionsTextBoxEnter = TextBox(
            "Press SPACE when you are satisfied with the orientation.",
            (96, 56),
            fontsize=36)

        screen.blit(
            instructionsTextBoxClick.surface,
            instructionsTextBoxClick.surface.fill(colors['BLACK']).move(
                instructionsTextBoxClick.window_coord))

        blit_objects(screen, [
            instructionsTextBoxEnter, instructionsTextBoxRotate,
            instructionsTextBoxEscape
        ])
        pygame.display.flip()

        placeList = orientation_to_coord_list(anchorCoord, shipLength,
                                              firstOrientation)
        orientation = firstOrientation

        while True:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()
                elif event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_ESCAPE:
                        cover_instructions(screen, instructionsTextBoxRotate)
                        cover_instructions(screen, instructionsTextBoxEnter)
                        cover_instructions(screen, instructionsTextBoxEscape)
                        cover_instructions(screen, instructionsTextBoxClick)
                        escape_placement()
                        return None
                    elif event.key == pygame.K_UP and is_possible_orientation(
                            anchorCoord, shipLength, orientation + 1,
                            otherShipCoords):
                        orientation = (orientation + 1) % 4
                    elif event.key == pygame.K_DOWN and is_possible_orientation(
                            anchorCoord, shipLength, orientation - 1,
                            otherShipCoords):
                        orientation = (orientation - 1) % 4
                    elif event.key == pygame.K_SPACE:
                        cover_instructions(screen, instructionsTextBoxRotate)
                        cover_instructions(screen, instructionsTextBoxEnter)
                        cover_instructions(screen, instructionsTextBoxEscape)
                        cover_instructions(screen, instructionsTextBoxClick)
                        escape_placement()
                        pygame.display.flip()
                        return placeList
            placeList = orientation_to_coord_list(anchorCoord, shipLength,
                                                  orientation)
            blit_board(
                screen,
                generate_placement_board(
                    encode_placement_board(placeList, otherShipCoords)))
            pygame.display.flip()
            pygame.time.delay(100)

    blit_board(screen, initialBoard)
    # screen.blit(ship.surface, ship.rect)
    # screen.blit(instructionsTextBoxClick.surface, instructionsTextBoxClick.rect)
    # screen.blit(instructionsTextBoxEscape.surface, instructionsTextBoxEscape.rect)
    pygame.display.flip()

    while True:
        screen.blit(ship.surface, ship.rect)
        screen.blit(instructionsTextBoxClick.surface,
                    instructionsTextBoxClick.rect)
        screen.blit(instructionsTextBoxEscape.surface,
                    instructionsTextBoxEscape.rect)
        pygame.display.flip()
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            elif event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
                return None
            elif event.type == MOUSEMOTION:
                hoveredSquare = get_hovered_square(event.pos, initialBoard)
                if hoveredSquare is not None:
                    firstOrientation = first_possible_orientation(
                        hoveredSquare.grid_coord, ship.length, otherShipCoords)
                    if firstOrientation is not None:
                        suggestionCoords = orientation_to_coord_list(
                            hoveredSquare.grid_coord, ship.length,
                            firstOrientation)
                        displayBoard = generate_placement_board(
                            encode_placement_board(suggestionCoords,
                                                   otherShipCoords))
                        didClick = wait_for_click_display(
                            displayBoard, hoveredSquare)
                        if didClick:
                            placed = run_rotate_ship(ship.length,
                                                     hoveredSquare.grid_coord,
                                                     firstOrientation)
                            if placed is not None:
                                otherShipCoords += placed
                                return placed
                            else:
                                escape_placement()
                                cover_instructions(screen,
                                                   instructionsTextBoxEscape)
                                cover_instructions(screen,
                                                   instructionsTextBoxClick)
                                return None
                        elif didClick is None:
                            escape_placement()
                            cover_instructions(screen,
                                               instructionsTextBoxClick)
                            return None
        pygame.display.flip()
        pygame.time.delay(50)
Esempio n. 13
0
 def generate_sunk_ship_alert(shipLength):
     #PLAY SUNK SHIP EXPLOSION SOUND
     playSink()
     return TextBox("You sunk the other player's {}".format(ship_length_to_name(shipLength)), (SCREEN_WIDTH / 4, SCREEN_HEIGHT * (9 / 10)), textcolor=colors['GREEN'])
Esempio n. 14
0
def run_ai_game_loop(shipCoords1, shipCoords2, aiDifficulty):
    """
    This is the main game loop for battleship. It consists of a loop the allows one player to guess, stores that guess, updates the current player, and then switches the turn.
    :param shipCoords1: a list of lists of coordinates corresponding to the first player's chosen ship locations.
    :param shipCoords2: a list of lists of coordinates corresponding to the second player's chosen ship locations.
    :return: string - the name of the player who won (either "Player 1" or "Player 2")
    """
    pygame.mixer.music.stop()
    pygame.mixer.music.load('../sounds/gameplay.mp3')
    pygame.mixer.music.play(-1)

    switchTurnsInstructionsBox = TextBox("Press the SPACE key to switch turns.", (240, 48))
    switchTurnsInstructionsBox2 = TextBox("Please switch spots with your playing partner. Press any key to continue.", (35, SCREEN_HEIGHT / 2), fontsize=44)
    guessBoardLabel = TextBox("Attack Board", (200, SCREEN_HEIGHT / 5), textcolor=colors['RED'])
    myBoardLabel = TextBox("My Board", (SCREEN_WIDTH - 370, SCREEN_HEIGHT / 5), textcolor=colors['GREEN'])
    hitTextBox = TextBox("Hit!", ((SCREEN_WIDTH / 2) - 70, SCREEN_HEIGHT * (8 / 10)), textcolor=colors['GREEN'], fontsize=96)
    missTextBox = TextBox("Miss.", ((SCREEN_WIDTH / 2) - 70, SCREEN_HEIGHT * (8 / 10)), textcolor=colors['RED'], fontsize=96)

    player1 = Player(shipCoords1, "Player 1")
    player2 = Player(shipCoords2, "AI")
    state = State(player1, player2)

    hits = []
    guesses = []

    spotsToHit = shipCoords1

    def generate_sunk_ship_alert(shipLength):
        #PLAY SUNK SHIP EXPLOSION SOUND
        playSink()
        return TextBox("You sunk the other player's {}".format(ship_length_to_name(shipLength)), (SCREEN_WIDTH / 4, SCREEN_HEIGHT * (9 / 10)), textcolor=colors['GREEN'])

    def produce_guess_board():
        return generate_guess_board(encode_guess_board(state.player1.guesses, state.player2.ships))

    def produce_guessed_at_board():
        return generate_guessed_at_board(encode_guessed_at_board(state.player2.guesses, state.player1.ships))

    def wait_for_click_guess(square):
        while True:
            for event in pygame.event.get():
                if event.type == pygame.MOUSEBUTTONDOWN and square.rect.collidepoint(event.pos):
                    playNavigate()
                    return square.grid_coord
                elif event.type == pygame.MOUSEMOTION and not square.rect.collidepoint(event.pos):
                    return None
            pygame.time.delay(30)

    def checkDestroyed(arr, shipCoords1):
        for i in shipCoords1:
            print("check destroyed of", arr, " to ", i)
            if sorted(arr) == sorted(i):
                return True
        return False

    def med_ai_traverse(ax, ay, shipCoords1, arr):
        guess = (ay,ax)
        print(shipCoords1)
        if checkDestroyed(arr, shipCoords1):
            print("leaving function")
            print(arr)
            return arr
        elif (ay-1, ax) in shipCoords1 and (ay-1, ax) not in state.player2.guesses and ay-1 > 0:
            print("Going up")
            arr.append((ay-1, ax))
            state.update((ay-1, ax))
            med_ai_traverse(ax, ay-1, shipCoords1, arr)
        elif (ay, ax+1) in shipCoords1 and (ay, ax+1) not in state.player2.guesses and ax+1 < 9:
            print("Going right")
            arr.append((ay, ax+1))
            state.update((ay, ax+1))
            med_ai_traverse(ax+1, ay, shipCoords1, arr)

        elif (ay+1, ax) in shipCoords1 and (ay+1, ax) not in state.player2.guesses and ay+1 < 9:
            print("Going down")
            arr.append((ay+1, ax))
            state.update((ay+1, ax))
            med_ai_traverse(ax, ay+1, shipCoords1, arr)

        elif (ay, ax-1) in shipCoords1 and (ay, ax-1) not in state.player2.guesses and ax-1 > 0:
            print("Going left")
            arr.append((ay, ax-1))
            state.update((ay, ax-1))
            med_ai_traverse(ax-1, ay, shipCoords1, arr)

        else:
            print("Going back to the original anchor")
            return med_ai_traverse(arr[0][1], arr[0][0], shipCoords1, arr) #arr[0][0,1] is the original hit point



    def run_switch_turns():
        # display switch turns instruction message
        screen.blit(switchTurnsInstructionsBox.surface, switchTurnsInstructionsBox.rect)
        pygame.display.flip()
        # wait till they hit SPACE
        while True:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()
                elif event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
                    playNavigate()
                    # black the screen
                    screen.fill((0, 0, 0))
                    # display the instructions to switch turns
                    screen.blit(switchTurnsInstructionsBox2.surface, switchTurnsInstructionsBox2.rect)
                    pygame.display.flip()
                    while True:
                        for event in pygame.event.get():
                            if event.type == pygame.QUIT:
                                pygame.quit()
                                sys.exit()
                            elif event.type == KEYDOWN or event.type == MOUSEBUTTONDOWN:
                                playNavigate()
                                screen.fill(colors['BLACK'])
                                return True
            pygame.time.delay(50)
        return False

    while True:
        if state.player1.name == "Player 1":
            whosTurnTextBox = TextBox("{}'s Turn".format(state.player1.name), (SCREEN_WIDTH * (3 / 8), 40), fontsize=64, textcolor=colors['GREEN'])
            guessInstructionsTextBox = TextBox("Click a coordinate on the Attack Board to fire a missile!", (110, 96))
            initialGuessBoard = produce_guess_board()
            blit_board(screen, initialGuessBoard)
            blit_board(screen, produce_guessed_at_board())
            blit_objects(screen, [guessBoardLabel, myBoardLabel, guessInstructionsTextBox, whosTurnTextBox])
            pygame.display.flip()
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()
                elif event.type == MOUSEMOTION:
                    hoveredSquare = get_hovered_square(event.pos, initialGuessBoard)
                    if (hoveredSquare is not None) and (hoveredSquare.grid_coord not in state.player1.guesses):
                        highlight(screen, hoveredSquare, colors['YELLOW'])
                        guess = wait_for_click_guess(hoveredSquare)
                        if guess is not None:
                            print("Human Guess:", guess)
                            pygame.draw.rect(screen, colors['BLACK'], guessInstructionsTextBox.rect)
                            pygame.draw.rect(screen, colors['BLACK'], whosTurnTextBox.rect)
                            if hit(guess, state.player2.ships):
                                #PLAY HIT SOUND
                                playHit()
                                highlight(screen, hoveredSquare, colors['GREEN'])
                                screen.blit(hitTextBox.surface, hitTextBox.rect)
                                sunkenShipLength = which_sunk(guess, state.player1.guesses, state.player2.ships)
                                state.update(guess)
                                if sunkenShipLength is not None:
                                    sunkAlertBox = generate_sunk_ship_alert(sunkenShipLength)
                                    screen.blit(sunkAlertBox.surface, sunkAlertBox.rect)
                                    pygame.display.flip()
                                    if state.is_game_over():
                                        pygame.display.flip()
                                        pygame.time.delay(2000)
                                        screen.fill(colors['BLACK'])
                                        return state.player2.name
                            else:
                                #PLAY MISS SOUND
                                playMiss()
                                highlight(screen, hoveredSquare, colors['RED'])
                                screen.blit(missTextBox.surface, missTextBox.rect)
                                state.update(guess)
                            pygame.display.flip()
                            pygame.time.delay(1500)
                            if run_switch_turns():
                                screen.fill(colors['BLACK'])
                                break
            pygame.display.flip()
            pygame.time.delay(30)
        else:
            guess = 0
            if aiDifficulty == 1:
                x = random.randint(1, 8)
                y = random.randint(1, 8)
                guess = (y, x)
                print("AI Guess:", guess)
                #state.update((y, x))
                if guess in flatten(state.player2.ships):
                    print("in hit")
                    sunkenShipLength = which_sunk(guess, state.player1.guesses, state.player2.ships)
                    state.update(guess)
                    if sunkenShipLength is not None:
                        sunkAlertBox = generate_sunk_ship_alert(sunkenShipLength)
                        screen.blit(sunkAlertBox.surface, sunkAlertBox.rect)
                        pygame.display.flip()
                        if state.is_game_over():
                            pygame.display.flip()
                            pygame.time.delay(2000)
                            screen.fill(colors['BLACK'])
                            return state.player2.name
                else:
                    state.update(guess)

            elif aiDifficulty == 2:
                x = random.randint(1, 8)
                y = random.randint(1, 8)
                while (y,x) in state.player1.guesses:
                    x = random.randint(1, 8)
                    y = random.randint(1, 8)
                print("AI Guess:", (y, x))
                print(state.player1.name)
                print("MY SHIPS", state.player2.ships)
                if (y,x) in flatten(state.player2.ships) and (y,x) not in hits:
                    ax = x
                    ay = y
                    state.update((ay,ax))
                    hits.append((ay,ax))
                    arr = [(ay,ax)]
                    #sunkenShipLength = which_sunk((ay,ax), state.player1.guesses, state.player2.ships)
                    
                    
                    print("true")
                    listOfHitsInTurn = med_ai_traverse(ax, ay, flatten(state.player2.ships), arr)
                    hits.append(listOfHitsInTurn) #add the list of hits from recursive function to hits and guesses
                    state.update(listOfHitsInTurn)
                    if state.is_game_over():
                        pygame.display.flip()
                        pygame.time.delay(2000)
                        screen.fill(colors['BLACK'])
                        return state.player2.name
                else:
                    state.update((y,x))
                aiGuessedText = TextBox("Guess: {}".format((y,x)))
                #pygame.display.flip()

            else:
                randShipNum = random.randint(0, len(spotsToHit) - 1)
                singleShip = spotsToHit[randShipNum]
                randSpotNum = random.randint(0, len(singleShip) - 1)
                singleSpot = singleShip[randSpotNum]
                guess = singleSpot
                state.update(spotsToHit)
                print()
                print(randShipNum)
                print(singleShip)
                print(randSpotNum)
                print(singleSpot)
                print(guess)
                print(spotsToHit)
                spotsToHit[randShipNum].remove(singleSpot)
                if len(spotsToHit[randShipNum]) == 0:
                    spotsToHit.remove([])
                print(spotsToHit)

                if len(flatten(spotsToHit)) == 0:
                    screen.fill(colors['BLACK'])
                    return state.player2.name