I am trying to train a NEAT algorithm to play a simple game called 'curvefever'. I was able to create a pygame version of curvefever and now I want to train the AI to play it. Therefore, the AI has to learn to avoid obstacles: borders surrounding the game and tracks that each player leaves behind, like in Snake.
At the moment I am doing this in the following way:
- Each player has a set of 'sensors' reaching forward that detect if and how far away an obstacle is.
- Each 'sensor' is a straight line consisting of several pygame rectangles.
- For each sensor it will detect if a collision with one of the obstacle rectangles occurred and calculate the distance of the collision to the player.
- Which sensor detected the collision and the distance of the collision is the information that goes to the neural network.
The problem is that this is very slow! Running 'python -m cProfile -s cumtime ai.py' I figured that it is the detection of obstacles that is slowing the script down, taking up about 50% of the total runtime.
Please see some code below how I create the lines of sight:
posx = x-position of player
posy = y-position of player
dir = direction the player is going
dangle = is the degree-spacing between lines of sight
angle = total range (in degrees) of lines of sight
def create_lines_of_sight(posx, posy, dir, dangle, angle, length):
dirs = [xdir for xdir in np.ceil(np.arange(dir-angle,dir+angle,dangle))]
d_posx = np.cos(np.deg2rad(dir))
d_posy = np.sin(np.deg2rad(dir))
return list(map(functools.partial(f_lrects,posx,posy,length), dirs))
def create_rects(posx, posy, d_posx, d_posy, i):
return f_rect(posx+i*d_posx,posy+i*d_posy,1,1,0,curvefever.WHITE)
f_create_rect = create_rects
def create_line_of_rects(posx, posy, length,dir):
l = pygame.sprite.Group()
ladd = l.add
d_posx = np.cos(np.deg2rad(dir))
d_posy = np.sin(np.deg2rad(dir))
i = [i for i in range(2,length,8)]
ladd(map(functools.partial(f_create_rect,posx,posy,d_posx,d_posy),i))
return l
f_lrects = create_line_of_rects
All obstacles are rectangles defined as:
class Rect(pygame.sprite.Sprite):
def __init__(self,x,y,width,height,dir,color):
super().__init__()
self.image = pygame.Surface([width, height])
self.image.fill(color)
self.rect = self.image.get_rect()
self.rect.centerx = x
self.rect.centery = y
and are saved in a sprite group.
What I tried
I tried adding a map command to get rid of the for loop, that did not speed it up much.
I tried adding the function names to remove the function lookup, I read this makes it faster, but it didn't.
I tried detecting an obstacle using 'Bresenham's Line Algorithm' and checking if an obstacle (x,y) position overlaps with the line of sight. Although this was a faster it did not work as it often missed obstacles. This happened because the line of sight did not exactly match the obstacle centre (rectx,recty) although it did overlap with the rectangle itself.
What do other people use to detect obstacles (maybe in pygame)? Any tips on how I can make this faster or more efficient are very welcome.
Thank you very much for your help!

dangle,angle? Are these angles related to the "sensors"? Are these angles constant?