Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 16 additions & 28 deletions ple/games/pong.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -42,40 +42,28 @@ 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
self.pos.y += self.vel.y * 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:
Expand Down
38 changes: 8 additions & 30 deletions tests/test_pong.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand All @@ -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)
8 changes: 7 additions & 1 deletion tests/test_raycastmaze.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)