diff --git a/ple/games/pong.py b/ple/games/pong.py index 16056cd..4177129 100644 --- a/ple/games/pong.py +++ b/ple/games/pong.py @@ -1,7 +1,7 @@ import math import sys -import pygame +import pygame, pygame.sprite from pygame.constants import K_w, K_s from ple.games.utils.vec2d import vec2d from ple.games.utils import percent_round_int @@ -42,18 +42,6 @@ def __init__(self, radius, speed, rng, self.rect = self.image.get_rect() self.rect.center = pos_init - def line_intersection(self, p0_x, p0_y, p1_x, p1_y, p2_x, p2_y, p3_x, p3_y): - - s1_x = p1_x - p0_x - s1_y = p1_y - p0_y - s2_x = p3_x - p2_x - s2_y = p3_y - p2_y - - s = (-s1_y * (p0_x - p2_x) + s1_x * (p0_y - p2_y)) / (-s2_x * s1_y + s1_x * s2_y) - t = (s2_x * (p0_y - p2_y) - s2_y * (p0_x - p2_x)) / (-s2_x * s1_y + s1_x * s2_y) - - return (s >= 0 and s <= 1 and t >= 0 and t <= 1) - def update(self, agentPlayer, cpuPlayer, dt): self.pos.x += self.vel.x * dt @@ -61,21 +49,21 @@ def update(self, agentPlayer, cpuPlayer, dt): is_pad_hit = False - if self.pos.x <= agentPlayer.pos.x + agentPlayer.rect_width: - if self.line_intersection(self.pos_before.x, self.pos_before.y, self.pos.x, self.pos.y, agentPlayer.pos.x + agentPlayer.rect_width / 2, agentPlayer.pos.y - agentPlayer.rect_height / 2, agentPlayer.pos.x + agentPlayer.rect_width / 2, agentPlayer.pos.y + agentPlayer.rect_height / 2): - self.pos.x = max(0, self.pos.x) - self.vel.x = -1 * (self.vel.x + self.speed * 0.05) - self.vel.y += agentPlayer.vel.y * 2.0 - self.pos.x += self.radius - is_pad_hit = True - - if self.pos.x >= cpuPlayer.pos.x - cpuPlayer.rect_width: - if self.line_intersection(self.pos_before.x, self.pos_before.y, self.pos.x, self.pos.y, cpuPlayer.pos.x - cpuPlayer.rect_width / 2, cpuPlayer.pos.y - cpuPlayer.rect_height / 2, cpuPlayer.pos.x - cpuPlayer.rect_width / 2, cpuPlayer.pos.y + cpuPlayer.rect_height / 2): - self.pos.x = min(self.SCREEN_WIDTH, self.pos.x) - self.vel.x = -1 * (self.vel.x + self.speed * 0.05) - self.vel.y += cpuPlayer.vel.y * 0.006 - self.pos.x -= self.radius - is_pad_hit = True + #Using pygame collision detection, we can pass in the objects directly, first the player + if pygame.sprite.collide_rect(self, agentPlayer): + self.pos.x = max(0, self.pos.x) + self.vel.x = -1 * (self.vel.x + self.speed * 0.05) + self.vel.y += agentPlayer.vel.y * 2.0 + self.pos.x += self.radius + is_pad_hit = True + + #then we test the cpu, much cleaner! + if pygame.sprite.collide_rect(self, cpuPlayer): + self.pos.x = min(self.SCREEN_WIDTH, self.pos.x) + self.vel.x = -1 * (self.vel.x + self.speed * 0.05) + self.vel.y += cpuPlayer.vel.y * 0.006 + self.pos.x -= self.radius + is_pad_hit = True # Little randomness in order not to stuck in a static loop if is_pad_hit: diff --git a/tests/test_pong.py b/tests/test_pong.py index cfcc7c5..3e095c1 100644 --- a/tests/test_pong.py +++ b/tests/test_pong.py @@ -3,22 +3,7 @@ from ple.games.pong import Pong, Ball, Player import pygame, time, sys, pytest -@pytest.mark.parametrize("x1,y1,x2,y2,x3,y3,x4,y4,expected", [ - (0,0,10,10,0,10,10,0,True), #X-like intersection of lines - (0,0,0,5,0,0,5,0,True), #Shared first end-point (0,0) - (0,0,0,5.00000000009,10,10,0,5.0000000001,False), #nearly touching end-point - (0,5,0,0,0,5,0,0,True), #entirely overlapping lines (both end-points shared) - (1,1,1,6,2,1,2,6,False), #parallel lines (FAILS: Division by zero) - (1,6,1,1,2,6,2,1,False), #parallel lines, rotated 90 degrees (FAILS: Division by zero) - (5,5,10,10,6,6,11,11,False), #parallel lines at a 45 degree angle (FAILS: Division by zero) - (0,0,0,10,10,5,0,5,True), #T-like intersection, with one end-point meeting another line midway -]) - -def test_line_intersection(x1,y1,x2,y2,x3,y3,x4,y4,expected): - game=Ball(10,1,1,(50,50),100,100) #these parameters do not affect the line_intersection function - answer = game.line_intersection(x1,y1,x2,y2,x3,y3,x4,y4) - assert answer == expected - +#This test passes if a positive difference in movement speed is detected def test_movement_up(): game=Pong() p=PLE(game, display_screen=True, fps=20, force_fps=1) @@ -29,6 +14,7 @@ def test_movement_up(): newState=p.getGameState() assert oldState["player_velocity"] > newState["player_velocity"] +#This tests passes is a negative difference in movement speed is detected def test_movement_down(): game=Pong() p=PLE(game, display_screen=True, fps=20, force_fps=1) @@ -39,35 +25,27 @@ def test_movement_down(): newState=p.getGameState() assert oldState["player_velocity"] < newState["player_velocity"] +#This test passes if an exception is thrown when a negative cpu speed is specified def test_negative_cpu_speed(): with pytest.raises(Exception): game=Pong(cpu_speed_ratio=-1) +#This test passes if an exception is thrown when a negative player speed is specified def test_negative_player_speed(): with pytest.raises(Exception): game=Pong(players_speed_ratio=-1) +#This test passes if an exception is thrown when a negative ball speed is specified def test_negative_ball_speed(): with pytest.raises(Exception): game=Pong(ball_speed_ratio=-1) +#This test passes if an exception is thrown when a negative game size is specified def test_invalid_game_size(): with pytest.raises(Exception): game=Pong(width=-200, height=-200) +#This test passes if an exception is thrown when a negative max score is specified def test_invalid_max_score(): with pytest.raises(Exception): - game=Pong(MAX_SCORE=-1) - -#I'm commenting out this test currently because it is unclear whether the game should -# throw an exception for an undefinied action, or do nothing (basically a wait step) -# Refer to ple.py lines 361-367 in the definition of act(int) for this -# -#def test_invalid_action_input(): -# game=Pong() -# p=PLE(game, display_screen=True, fps=20, force_fps=1) -# p.init() -# time.sleep(.5) -# with pytest.raises(Exception): -# p.act(10) - + game=Pong(MAX_SCORE=-1) \ No newline at end of file diff --git a/tests/test_raycastmaze.py b/tests/test_raycastmaze.py index d12f430..1dc2f79 100644 --- a/tests/test_raycastmaze.py +++ b/tests/test_raycastmaze.py @@ -3,31 +3,37 @@ from ple.games.raycastmaze import RaycastMaze import pygame, time, sys, pytest - +#This test passes if an exception is thrown when a negative initial position is specified def test_oob_init_pos(): with pytest.raises(Exception): game=RaycastMaze(init_pos=(-1,-1)) +#This test passes if an exception is thrown when the map size is below the minimum for the algorithm (5) def test_below_min_map_size(): with pytest.raises(Exception): game=RaycastMaze(map_size=3) +#This test passes if an exception is thrown when a large map size is specified def test_beyond_max_map_size(): with pytest.raises(Exception): game=RaycastMaze(map_size=400) +#This test passes if an exception is thrown when a negative move speed is specified def test_negative_move_speed(): with pytest.raises(Exception): game=RaycastMaze(move_speed=-1) +#This test passes if an exception is thrown when a negative turn speed is specified def test_negative_turn_speed(): with pytest.raises(Exception): game=RaycastMaze(turn_speed=-1) +#This test passes if an exception is thrown when a non-usefully large turn speed is specified def test_beyond_max_turn_speed(): with pytest.raises(Exception): game=RaycastMaze(turn_speed=400) +#This test passes if an exception is thrown when a negative window size is specified def test_negative_game_size(): with pytest.raises(Exception): game=RaycastMaze(width=-100,height=-100)