def test_nests_group(self):
        test_render_group = pygame.sprite.LayeredUpdates()
        test_player = Player(test_render_group)
        test_disabled_nests = DisabledNests()
        test_timer = 0

        self.assertFalse(DisabledNests.check_for_win(test_player))

        nest = FrogNest(1)
        nest.disable(test_render_group, test_disabled_nests, test_player)
        self.assertFalse(DisabledNests.check_for_win(test_player))

        nest = FrogNest(2)
        nest.disable(test_render_group, test_disabled_nests, test_player)
        self.assertFalse(DisabledNests.check_for_win(test_player))

        nest = FrogNest(3)
        nest.disable(test_render_group, test_disabled_nests, test_player)
        self.assertFalse(DisabledNests.check_for_win(test_player))

        nest = FrogNest(4)
        nest.disable(test_render_group, test_disabled_nests, test_player)
        self.assertFalse(DisabledNests.check_for_win(test_player))

        nest = FrogNest(5)
        nest.disable(test_render_group, test_disabled_nests, test_player)
        self.assertTrue(DisabledNests.check_for_win(test_player))

        nest = FrogNest(1)
        nest.disable(test_render_group, test_disabled_nests, test_player)
        self.assertTrue(DisabledNests.check_for_win(test_player))
    def test_distance_in_lane_behind(self):
        test_player = Player(pygame.sprite.LayeredUpdates())
        test_net_group = pygame.sprite.Group()
        test_carL = Player(pygame.sprite.LayeredUpdates())
        test_carR = Player(pygame.sprite.LayeredUpdates())

        expected = (test_player.rect.center[0], Window.WIDTH - test_player.rect.center[0])
        actual = test_player.find_sprite_in_next_lane("down", test_net_group)
        self.assertEqual(expected, actual)

        # Move the test car to the lane ahead, left of the player
        test_carL.rect.y += 64
        test_carL.rect.x = test_player.rect.x - 50
        test_carR.rect.y += 64
        test_carR.rect.x = test_player.rect.x + 50

        test_net_group.add(test_carL, test_carR)
        expected = (test_player.rect.center[0] - (test_carL.rect.x + test_carL.rect.width),
                    test_carR.rect.x - test_player.rect.center[0])
        actual = test_player.find_sprite_in_next_lane("down", test_net_group)
        self.assertEqual(expected, actual)

        test_carL2 = Player(pygame.sprite.LayeredUpdates())
        test_carR2 = Player(pygame.sprite.LayeredUpdates())
        test_carL2.rect.y += 64
        test_carL2.rect.x = test_player.rect.x - 200
        test_carR2.rect.y += 64
        test_carR2.rect.x = test_player.rect.x + 200
        test_net_group.add(test_carL2, test_carR2)
        expected = (test_player.rect.center[0] - (test_carL.rect.x + test_carL.rect.width),
                    test_carR.rect.x - test_player.rect.center[0])
        actual = test_player.find_sprite_in_next_lane("down", test_net_group)
        self.assertEqual(expected, actual)

        test_carL.rect.y, test_carR.rect.y, test_carL2.rect.y, test_carR2.rect.y = 500, 500, 500, 500
        expected = (test_player.rect.center[0], Window.WIDTH - test_player.rect.center[0])
        actual = test_player.find_sprite_in_next_lane("down", test_net_group)
        self.assertEqual(expected, actual)
def main(genomes="", config=""):
    """
    Main game method containing the main game loop. Also handles the logic regarding spawning in all of the
    players for a training generation and assessing their fitness.

    - :param genomes:
        Genomes passed in by NEAT-python library.
    - :param config:
        Configuration passed in by NEAT-python library.
    - :return:
        Exit code
    """

    if not training_flag:
        start_screen()

    timer = Timer()
    pygame.init()
    pygame.mixer.init()
    log_game()
    player_lines = []

    WIN.blit(background, (0, 0))
    frame_count = 0

    # Load the sounds
    if not training_flag:
        hop_sound = pygame.mixer.Sound("src/Assets/Sounds/hop.wav")
        pygame.mixer.music.load("src/Assets/Sounds/Frogger_music.mp3")
        pygame.mixer.music.play(-1)  # Loops the music indefinitely

    # Initialize on-screen text
    pygame.font.init()
    frogger_font = pygame.font.SysFont("Consolas", 30)

    # Initialize sprite groups
    render_group = pygame.sprite.LayeredUpdates()
    kill_group = DeathSprites()
    win_group = pygame.sprite.Group()
    disabled_nests = DisabledNests()
    river_group = RiverSprites()
    net_group = pygame.sprite.Group(
    )  # A group used for any sprites we want the neural net to see

    # A list of sprite groups that all logs and turtles should go in
    log_turtle_groups = [render_group, net_group]
    # A list of sprite groups that all cars should go in
    car_groups = [render_group, net_group, kill_group]

    # Initialize sprite groups for the water "lanes"
    water_lane1 = pygame.sprite.Group()
    water_lane2 = pygame.sprite.Group()
    water_lane3 = pygame.sprite.Group()
    water_lane4 = pygame.sprite.Group()
    water_lane5 = pygame.sprite.Group()
    water_lanes = [
        water_lane1, water_lane2, water_lane3, water_lane4, water_lane5
    ]

    # Initialize logs and turtles already on the screen at game start
    Log(AssetDictionary.get_asset("log-short"), 779,
        308).add(water_lane2, log_turtle_groups)
    Log(AssetDictionary.get_asset("log-short"), 539,
        308).add(water_lane2, log_turtle_groups)
    Log(AssetDictionary.get_asset("log-short"), 299,
        308).add(water_lane2, log_turtle_groups)

    TurtleSinker(AssetDictionary.get_asset("triple-turtle-sink"), -30, -79,
                 372).add(water_lane1, log_turtle_groups)
    Turtle(AssetDictionary.get_asset("triple-turtle"), frame_count, 221,
           372).add(water_lane1, log_turtle_groups)
    Turtle(AssetDictionary.get_asset("triple-turtle"), frame_count, 521,
           372).add(water_lane1, log_turtle_groups)

    Log(AssetDictionary.get_asset("log-long"), 425,
        244).add(water_lane3, render_group, log_turtle_groups)

    TurtleSinker(AssetDictionary.get_asset("double-turtle-sink"), -30, 0,
                 180).add(water_lane4, log_turtle_groups)
    Turtle(AssetDictionary.get_asset("double-turtle"), frame_count, 270,
           180).add(water_lane4, log_turtle_groups)
    Turtle(AssetDictionary.get_asset("double-turtle"), frame_count, 540,
           180).add(water_lane4, log_turtle_groups)

    Log(AssetDictionary.get_asset("log-medium"), 219,
        116).add(water_lane5, log_turtle_groups)
    Log(AssetDictionary.get_asset("log-medium"), 719,
        116).add(water_lane5, log_turtle_groups)

    # Initialize sprite groups for the car lanes
    car_lane1 = pygame.sprite.Group()
    car_lane2 = pygame.sprite.Group()
    car_lane3 = pygame.sprite.Group()
    car_lane4 = pygame.sprite.Group()
    car_lane5 = pygame.sprite.Group()

    # Initialize the cars at start of game
    Car(AssetDictionary.get_asset("car4"),
        WIN.get_width() - 500, 750, WIN).add(car_lane1, car_groups)
    Car(AssetDictionary.get_asset("car4"),
        WIN.get_width() - 260, 750, WIN).add(car_lane1, car_groups)
    Car(AssetDictionary.get_asset("car3"), 660, 700,
        WIN).add(car_lane2, car_groups)
    Car(AssetDictionary.get_asset("car3"), 300, 700,
        WIN).add(car_lane2, car_groups)
    Car(AssetDictionary.get_asset("car2"),
        WIN.get_width() - 400, 630, WIN).add(car_lane3, car_groups)
    Car(AssetDictionary.get_asset("semi-truck"),
        WIN.get_width() - 360, 500, WIN).add(car_lane5, car_groups)

    # Initialize sprites for Frog
    # player = Player(render_group)
    FrogNest(1).add(win_group, net_group)
    FrogNest(2).add(win_group, net_group)
    FrogNest(3).add(win_group, net_group)
    FrogNest(4).add(win_group, net_group)
    FrogNest(5).add(win_group, net_group)

    # Initialize sprites for Riverbank
    Riverbank(0).add(kill_group)
    Riverbank(1).add(kill_group)
    Riverbank(2).add(kill_group)
    Riverbank(3).add(kill_group)
    Riverbank(4).add(kill_group)
    Riverbank(5).add(kill_group)

    # Initialize sprites for WaterSprite
    river = WaterSprite()
    river.add(river_group)

    # Initialize sprites on the edges of the river for checking if the player is offscreen
    RiverEdge("left").add(kill_group)
    RiverEdge("right").add(kill_group)

    clock = pygame.time.Clock()

    # Create counter, timer and fonts for timer, counter
    timer_event = pygame.event.Event(pygame.USEREVENT, {})
    # pygame.time.set_timer(timer_event, 1000)

    # Initialize genomes and neural networks if flag is set
    if training_flag:
        nets = []
        players = []
        genome_list = []

        for genome_id, genome in genomes:
            genome.fitness = 0
            net = neat.nn.FeedForwardNetwork.create(genome, config)
            nets.append(net)
            players.append(Player(render_group))
            genome_list.append(genome)

    run = True

    # Main game loop
    while run:
        if not training_flag:  # If training the AI, let the game use all compute overhead
            clock.tick(FPS)
        max_lives = 0
        highest_score = 0
        # keypress = False
        # while not keypress:
        #     for game_event in pygame.event.get():
        #         if game_event.type == pygame.KEYDOWN:
        #             keypress = True

        for game_event in pygame.event.get():
            if game_event.type == pygame.QUIT:
                run = False

            # Timer for player to complete game
            if game_event == timer_event:
                timer.count_down()

        for i, player in enumerate(players):
            # Begin neural net logic
            genome_list[i].fitness = player.score

            # If the timer has hit zero, kill the player before letting it compute its move
            if timer.get_time() < 1:
                player.kill()

            # On every 10th frame, allow the neural net to move the frog
            if frame_count % 10 == 0:
                distance_to_sprite_ahead = player.find_distance_to_sprite(
                    "ahead", net_group, player_lines)
                distance_to_sprite_below = player.find_distance_to_sprite(
                    "down", net_group, player_lines)
                distance_to_left_sprite = player.find_distance_to_sprite(
                    "left", net_group, player_lines)
                distance_to_right_sprite = player.find_distance_to_sprite(
                    "right", net_group, player_lines)
                distance_in_lane_ahead = player.find_sprite_in_next_lane(
                    "ahead", net_group, player_lines)
                distance_in_lane_behind = player.find_sprite_in_next_lane(
                    "down", net_group, player_lines)

                frames_since_last_advancement = frame_count - player.last_advancement

                # Feed values to the neural net to compute the action to be taken on the current frame
                output = nets[players.index(player)].activate(
                    (player.rect.x, player.rect.y,
                     frames_since_last_advancement, distance_to_sprite_ahead,
                     distance_to_sprite_below, distance_to_left_sprite,
                     distance_to_right_sprite, player.on_sinking_turtle,
                     distance_in_lane_ahead[0], distance_in_lane_ahead[1],
                     distance_in_lane_behind[0], distance_in_lane_behind[1],
                     len(player.disabled_nests.sprites())))

                # If no node in the output layer is greater than 0.5, the player will do nothing on this frame
                if max(output) > 0.5:
                    max_node_index = output.index(max(output))

                    # Move the player based on the output of the neural net
                    key_to_press = determine_keypress(max_node_index)
                    player.move(key_to_press, frame_count)

            # If the player hasn't moved for 10 seconds or more, kill it
            if frames_since_last_advancement >= 300:
                player.kill()
            # End neural net logic

            # Handle player logic that does not involve neural net
            check_kill_collisions(player, kill_group)
            check_win_collisions(player, win_group, render_group, kill_group,
                                 disabled_nests, timer)
            river_group.check_if_sunk(player, river)
            add_player_to_water_lane(water_lanes, player)
            player.set_score()
            animate_sprites(water_lane1, water_lane4, frame_count, net_group)

            # Input handling for movement
            # for game_event in pygame.event.get():
            #     if game_event.type == pygame.KEYDOWN and player.can_move:
            #         player.can_move = False
            #         key_depressed = game_event.key
            #         move_player(player, key_depressed, MOVEMENT_DISTANCE_X, MOVEMENT_DISTANCE_Y)
            #         player.index = 1
            #         player.image = player.images[player.index]
            #     if game_event.type == pygame.KEYUP:
            #         player.can_move = True
            #         player.index = 0
            #         player.image = player.images[player.index]

            if player.lives_left < 0:
                players.remove(player)
                nets.remove(nets[i])
                genome_list.remove(genome_list[i])

            if player.score > highest_score:
                highest_score = player.score

            if player.lives_left > max_lives:
                max_lives = player.lives_left

        # Handle all logic that does not involve the player that must be done on every frame
        spawn_car_lanes(frame_count, car_lane1, car_lane2, car_lane3,
                        car_lane4, car_lane5, car_groups, WIN)
        spawn_water_lanes(frame_count, water_lane1, water_lane2, water_lane3,
                          water_lane4, water_lane5, log_turtle_groups, WIN)
        add_sprites_to_group(water_lanes, river_group)
        draw_sprites(render_group, WIN, background)

        # Initialize and render score text
        empty_text = frogger_font.render("Score: 00000", True, BLACK, BLACK)
        background.blit(empty_text, (20, 10))
        score_text = frogger_font.render("Score: " + str(int(highest_score)),
                                         True, WHITE, BLACK)
        background.blit(score_text, (20, 10))

        # Initialize and render lives left
        lives_text = frogger_font.render("Lives: " + str(max_lives), True,
                                         WHITE, BLACK)
        background.blit(lives_text, (650, 10))

        # Initialize and render timer
        empty_text = frogger_font.render("Time: 00", True, BLACK, BLACK)
        background.blit(empty_text, (355, 10))
        timer_text = frogger_font.render("Time: " + str(timer.get_time()),
                                         True, WHITE, BLACK)
        background.blit(timer_text, (355, 10))

        if len(players) <= 0:
            run = False

        # Iterate the frame counter
        frame_count += 1

        if timer.get_time() < 1:
            timer.reset()

        # Push a timer event to the event queue every second to iterate the timer
        if frame_count % FPS == 0:
            pygame.event.post(timer_event)
Exemple #4
0
def move_player(player: Player, key_depressed, movement_distance_x,
                movement_distance_y, sound_effect):
    """
    Handles player movement when the AI is not being trained. This should only be called when the game is being played
    by a human.

    - :param player:
        A Player object.
    - :param key_depressed:
        An int representing the key that was pressed to call the function. 119 for moving up, 97 for left, 100 for right, 115 for down. These correspond to WASD.
    -:param movement_distance_x:
        An int representing the distance a player will move in the horizontal directions
    :param movement_distance_y:
        An int representing the distance a player will move in the vertical directions
    - :param sound_effect:
        A sound effect asset to be played when the player moves
    - :return:
        None
    """
    x_change = 0
    y_change = 0
    up = 119  # 'w' key ascii
    left = 97  # 'a' key ascii
    right = 100  # 'd' key ascii
    down = 115  # 's' key ascii

    if key_depressed == up:  # if up key is pressed
        if player.rect.y > 60:  # not at top
            sound_effect.play()
            y_change -= movement_distance_y  # move up
            up_image = AssetDictionary.get_asset("frog")
            up_image2 = AssetDictionary.get_asset("frog_jumping")
            player.images = [up_image, up_image2]
        new_y = player.rect.y
        if player.farthest_distance > new_y > 110:
            player.farthest_distance = new_y
            player.score += 10

    elif key_depressed == left:  # if left key is pressed
        if player.rect.x > 20:  # not at leftmost border
            sound_effect.play()
            x_change -= movement_distance_x
            left_image = pygame.transform.rotate(
                AssetDictionary.get_asset("frog"), 90)
            left_image2 = pygame.transform.rotate(
                AssetDictionary.get_asset("frog_jumping"), 90)
            player.images = [left_image, left_image2]

    elif key_depressed == right:  # if right key is pressed
        if player.rect.x < 750:  # not at rightmost border
            sound_effect.play()
            x_change += movement_distance_x
            right_image = pygame.transform.rotate(
                AssetDictionary.get_asset("frog"), -90)
            right_image2 = pygame.transform.rotate(
                AssetDictionary.get_asset("frog_jumping"), -90)
            player.images = [right_image, right_image2]

    elif key_depressed == down:  # if down key is pressed
        if player.rect.y < 800:  # not at bottom
            sound_effect.play()
            y_change += movement_distance_y
            down_image = pygame.transform.rotate(
                AssetDictionary.get_asset("frog"), 180)
            down_image2 = pygame.transform.rotate(
                AssetDictionary.get_asset("frog_jumping"), 180)
            player.images = [down_image, down_image2]

    player.rect.x += x_change
    player.rect.y += y_change
    def test_find_distance_to_right_sprite(self):
        test_player = Player(pygame.sprite.LayeredUpdates())
        test_net_group = pygame.sprite.Group()
        test_car = Player(pygame.sprite.LayeredUpdates())

        expected = Window.WIDTH - test_player.rect.center[0]
        actual = test_player.find_distance_to_sprite("right", test_net_group)
        self.assertEqual(expected, actual)

        # Move the test car to the right side of the player
        test_car.rect.y = test_player.rect.y
        test_car.rect.x = test_player.rect.x + 50
        test_car.add(test_net_group)

        expected = test_car.rect.x - test_player.rect.center[0]
        actual = test_player.find_distance_to_sprite("right", test_net_group)
        self.assertEqual(expected, actual)

        test_car.rect.y += 10
        actual = test_player.find_distance_to_sprite("right", test_net_group)
        self.assertEqual(expected, actual)

        test_car.rect.y -= 10
        actual = test_player.find_distance_to_sprite("right", test_net_group)
        self.assertEqual(expected, actual)

        test_car.rect.y -= 1000
        expected = Window.WIDTH - test_player.rect.center[0]
        actual = test_player.find_distance_to_sprite("right", test_net_group)
        self.assertEqual(expected, actual)

        test_car.rect.x -= 150
        test_car2 = Player(pygame.sprite.LayeredUpdates())
        test_net_group.add(test_car2)
        test_car2.rect.y = test_player.rect.y
        test_car2.rect.x = test_player.rect.x + 50
        expected = test_car2.rect.x - test_player.rect.center[0]
        actual = test_player.find_distance_to_sprite("right", test_net_group)
        self.assertEqual(expected, actual)

        test_car.rect.y = test_player.rect.y
        test_car.rect.x = Window.WIDTH
        expected = test_car2.rect.x - test_player.rect.center[0]
        actual = test_player.find_distance_to_sprite("right", test_net_group)
        self.assertEqual(expected, actual)
    def test_find_distance_to_left_sprite(self):
        test_player = Player(pygame.sprite.LayeredUpdates())
        test_net_group = pygame.sprite.Group()
        test_car = Player(pygame.sprite.LayeredUpdates())

        expected = test_player.rect.center[0]
        actual = test_player.find_distance_to_sprite("left", test_net_group)
        self.assertEqual(expected, actual)

        # Move the test car to the left side of the player
        test_car.rect.y = test_player.rect.y
        test_car.rect.x = test_player.rect.x - 50
        test_car.add(test_net_group)

        expected = test_player.rect.center[0] - (test_car.rect.x + test_car.rect.width)
        actual = test_player.find_distance_to_sprite("left", test_net_group)
        self.assertEqual(expected, actual)

        test_car.rect.y += 10
        actual = test_player.find_distance_to_sprite("left", test_net_group)
        self.assertEqual(expected, actual)

        test_car.rect.y -= 10
        actual = test_player.find_distance_to_sprite("left", test_net_group)
        self.assertEqual(expected, actual)

        test_car.rect.y -= 1000
        expected = test_player.rect.center[0]
        actual = test_player.find_distance_to_sprite("left", test_net_group)
        self.assertEqual(expected, actual)

        test_car.rect.x += 150
        test_car2 = Player(pygame.sprite.LayeredUpdates())
        test_net_group.add(test_car2)
        test_car2.rect.y = test_player.rect.y
        test_car2.rect.x = test_player.rect.x - 50
        expected = test_player.rect.center[0] - (test_car2.rect.x + test_car.rect.width)
        actual = test_player.find_distance_to_sprite("left", test_net_group)
        self.assertEqual(expected, actual)

        test_car.rect.y = test_player.rect.y
        test_car.rect.x = 0
        expected = test_player.rect.center[0] - (test_car2.rect.x + test_car.rect.width)
        actual = test_player.find_distance_to_sprite("left", test_net_group)
        self.assertEqual(expected, actual)
    def test_find_distance_to_sprite_behind(self):
        test_player = Player(pygame.sprite.LayeredUpdates())
        test_player.rect.y -= 500
        test_net_group = pygame.sprite.Group()
        test_car = Player(pygame.sprite.LayeredUpdates())

        expected = Window.HEIGHT - test_player.rect.center[1]
        actual = test_player.find_distance_to_sprite("down", test_net_group)
        self.assertEqual(expected, actual)

        # Move the test car behind the player
        test_car.rect.x = test_player.rect.x
        test_car.rect.y = test_player.rect.y + 50
        test_net_group.add(test_car)

        expected = test_car.rect.y - test_player.rect.center[1]
        actual = test_player.find_distance_to_sprite("down", test_net_group)
        self.assertEqual(expected, actual)

        test_car.rect.x -= 10
        actual = test_player.find_distance_to_sprite("down", test_net_group)
        self.assertEqual(expected, actual)

        test_car.rect.x += 20
        actual = test_player.find_distance_to_sprite("down", test_net_group)
        self.assertEqual(expected, actual)

        test_car.rect.x += 1000
        expected = Window.HEIGHT - test_player.rect.center[1]
        actual = test_player.find_distance_to_sprite("down", test_net_group)
        self.assertEqual(expected, actual)

        test_car.rect.y += 150
        test_car2 = Player(pygame.sprite.LayeredUpdates())
        test_net_group.add(test_car2)
        test_car2.rect.x = test_player.rect.x
        test_car2.rect.y = test_player.rect.y + 50
        expected = test_car2.rect.y - test_player.rect.center[1]
        actual = test_player.find_distance_to_sprite("down", test_net_group)
        self.assertEqual(expected, actual)

        test_car.rect.x = test_player.rect.x
        test_car.rect.y = Window.HEIGHT - test_car.rect.height
        expected = test_car2.rect.y - test_player.rect.center[1]
        actual = test_player.find_distance_to_sprite("down", test_net_group)
        self.assertEqual(expected, actual)
    def test_find_distance_to_sprite_ahead(self):
        test_player = Player(pygame.sprite.LayeredUpdates())
        test_net_group = pygame.sprite.Group()
        test_car = Player(pygame.sprite.LayeredUpdates())

        expected = test_player.rect.center[1]
        actual = test_player.find_distance_to_sprite("ahead", test_net_group)
        self.assertEqual(expected, actual)

        # Move the test car in front of the player
        test_car.rect.x = test_player.rect.x
        test_car.rect.y = test_player.rect.y - 50
        test_net_group.add(test_car)

        expected = test_player.rect.center[1] - test_car.rect.y
        actual = test_player.find_distance_to_sprite("ahead", test_net_group)
        self.assertEqual(expected, actual)

        test_car.rect.x -= 10
        actual = test_player.find_distance_to_sprite("ahead", test_net_group)
        self.assertEqual(expected, actual)

        test_car.rect.x += 20
        actual = test_player.find_distance_to_sprite("ahead", test_net_group)
        self.assertEqual(expected, actual)

        test_car.rect.x += 1000
        expected = test_player.rect.center[1]
        actual = test_player.find_distance_to_sprite("ahead", test_net_group)
        self.assertEqual(expected, actual)

        test_car2 = Player(pygame.sprite.LayeredUpdates())
        test_net_group.add(test_car2)
        test_car.rect.y += 150
        test_car2.rect.x = test_player.rect.x
        test_car2.rect.y = test_player.rect.y - 50
        expected = test_player.rect.center[1] - test_car2.rect.y
        actual = test_player.find_distance_to_sprite("ahead", test_net_group)
        self.assertEqual(expected, actual)

        test_car.rect.x = test_player.rect.x
        test_car.rect.y = 0
        actual = test_player.find_distance_to_sprite("ahead", test_net_group)
        self.assertEqual(expected, actual)
    def test_player_score(self):
        test_player = Player(pygame.sprite.LayeredUpdates())

        self.assertEqual(test_player.score, 0)

        test_player.set_score()
        self.assertEqual(test_player.score, 0)

        test_player.move("w", 10)
        test_player.set_score()
        self.assertEqual(round(test_player.score, 2), 10)
        self.assertEqual(test_player.last_advancement, 10)

        test_player.move("d", 11)
        test_player.set_score()
        self.assertEqual(round(test_player.score, 2), 10)
        self.assertEqual(test_player.last_advancement, 10)

        test_player.move("a", 12)
        test_player.set_score()
        self.assertEqual(round(test_player.score, 2), 10)
        self.assertEqual(test_player.last_advancement, 10)

        test_player.move("s", 13)
        test_player.set_score()
        self.assertEqual(round(test_player.score, 2), 10)
        self.assertEqual(test_player.last_advancement, 10)

        test_player.move("w", 14)
        test_player.move("w", 15)
        test_player.set_score()
        self.assertEqual(round(test_player.score, 2), 20)
        self.assertEqual(test_player.last_advancement, 15)
    def test_move_player(self):
        """Test whether the movement system works as expected"""
        test_render_group = pygame.sprite.LayeredUpdates()
        test_player = Player(test_render_group)
        pygame.mixer.init()
        test_sound = pygame.mixer.Sound("../Assets/Sounds/hop.wav")
        up = 119  # 'w' key ascii
        left = 97  # 'a' key ascii
        right = 100  # 'd' key ascii
        down = 115  # 's' key ascii

        MOVEMENT_DISTANCE_X = AssetDictionary.get_asset("frog").get_width() + 4
        MOVEMENT_DISTANCE_Y = AssetDictionary.get_asset("frog").get_height() + 12

        # Test move up
        test_player.rect.x = 400
        test_player.rect.y = 400
        move_player(test_player, up, MOVEMENT_DISTANCE_X, MOVEMENT_DISTANCE_Y, test_sound)
        self.assertEqual(test_player.rect.y, 400 - MOVEMENT_DISTANCE_Y)

        # Test move left
        test_player.rect.x = 400
        test_player.rect.y = 400
        move_player(test_player, left, MOVEMENT_DISTANCE_X, MOVEMENT_DISTANCE_Y, test_sound)
        self.assertEqual(test_player.rect.x, 400 - MOVEMENT_DISTANCE_X)

        # Test move right
        test_player.rect.x = 400
        test_player.rect.y = 400
        move_player(test_player, right, MOVEMENT_DISTANCE_X, MOVEMENT_DISTANCE_Y, test_sound)
        self.assertEqual(test_player.rect.x, 400 + MOVEMENT_DISTANCE_X)

        # Test move down
        test_player.rect.x = 400
        test_player.rect.y = 400
        move_player(test_player, down, MOVEMENT_DISTANCE_X, MOVEMENT_DISTANCE_Y, test_sound)
        self.assertEqual(test_player.rect.y, 400 + MOVEMENT_DISTANCE_Y)

        # Test move left if player is at left edge
        test_player.rect.x = 20
        test_player.rect.y = 400
        move_player(test_player, left, MOVEMENT_DISTANCE_X, MOVEMENT_DISTANCE_Y, test_sound)
        self.assertEqual(test_player.rect.x, 20)

        # Test move right if player is at right edge
        test_player.rect.x = 750
        test_player.rect.y = 400
        move_player(test_player, right, MOVEMENT_DISTANCE_X, MOVEMENT_DISTANCE_Y, test_sound)
        self.assertEqual(test_player.rect.x, 750)

        # Test move up if player is at top edge
        test_player.rect.x = 400
        test_player.rect.y = 20
        move_player(test_player, up, MOVEMENT_DISTANCE_X, MOVEMENT_DISTANCE_Y, test_sound)
        self.assertEqual(test_player.rect.y, 20)

        # Test move down if player is at bottom edge
        test_player.rect.x = 800
        test_player.rect.y = 400
        move_player(test_player, down, MOVEMENT_DISTANCE_X, MOVEMENT_DISTANCE_Y, test_sound)
        self.assertEqual(test_player.rect.x, 800)
    def test_player(self):
        pygame.init()
        test_render_group = pygame.sprite.LayeredUpdates()
        actual = Player(test_render_group)
        test_timer = Timer(20)
        nest = FrogNest(1)

        actual.rect.x = 101
        actual.rect.y = 415
        actual.index = 1
        actual.direction = "right"

        expected = Player(test_render_group)

        actual.return_home()

        self.assertEqual(actual.rect.x, expected.rect.x)
        self.assertEqual(actual.rect.y, expected.rect.y)
        self.assertEqual(actual.index, expected.index)
        self.assertEqual(actual.direction, expected.direction)

        actual.farthest_distance = 265
        expected.score += 50 + 2 * test_timer.get_time()

        actual.nest(test_timer, nest)

        self.assertEqual(actual.farthest_distance, expected.farthest_distance)
        self.assertEqual(actual.score, expected.score)
        self.assertTrue(actual.disabled_nests.has(nest))

        actual.win_game()
        expected.score += 2000

        self.assertEqual(actual.score, expected.score)

        actual.kill()
        expected.lives_left -= 1

        self.assertEqual(actual.lives_left, expected.lives_left)