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_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_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_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_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(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)
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)
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)