Pygame:使用遗传算法的点游戏



我使用库Pygame创建了一个点游戏,并实现了遗传算法,以便在点上创建一些学习效果。基本上,在每一代中,点的运动都应该进化。但就我而言,我试图调试的点不会进化,但我真的不知道问题出在哪里。

这是主文件:

import pygame as pg
import random
import dots
import population
import math
vec = pg.math.Vector2
############ Some color codes  ############
WHITE = (255, 255, 255)
BLUE = (0,   0, 255)
GREEN = (0, 255,   0)
RED = (255,   0,   0)
BLACK = (0, 0, 0)
GREY = (169, 169, 169)
TEXTCOLOR = (0,   0,  0)
###########################################
(width,height)=(800,800)
dotStartPos = (width/2, height/2)
goalPos = (int(width/2), 0)
alldotsaredead = False
running = True

# Initiliaze pygame #
pg.init()
FONT = pg.font.Font("freesansbold.ttf", 15)
clock = pg.time.Clock()
# Make screen and filling it with color
window = pg.display.set_mode((width, height))
# Create dots sprite group
dotssprite = pg.sprite.Group()
# goaldotsprite = pg.sprite.Group()
# Creating dots
my_population = population.Population(100,(400,700),window,1000,0)
my_dots = my_population.my_dots
[dotssprite.add(d) for d in my_dots]

# Function to update screen
def udpatescreen():
global my_population, dotssprite
window.fill(WHITE)
text_count_surf = FONT.render("Gen : " + str(my_population.gen), True, BLACK)
text_count_rect = text_count_surf.get_rect(center=(70, 30))
window.blit(text_count_surf, text_count_rect)
pg.draw.circle(window, RED, goalPos, 10)
dotssprite.draw(window)
pg.display.update()
# Function to reset screen
def resetscreen():
global my_population, my_dots, dotssprite
window.fill(WHITE)
pg.draw.circle(window, RED, goalPos, 10)
dotssprite.empty()
my_dots = my_population.my_dots
[dotssprite.add(d) for d in my_dots]
dotssprite.draw(window)

# Function to update dots sprite
def rundots():
global my_population, dotssprite
my_population.move()
dotssprite.update()

while running:
clock.tick(60)
for event in pg.event.get():
if event.type==pg.QUIT:
running = False
if my_population.allDotsDead() is False:
rundots()
else:
my_population.calculatefitness()
my_population.naturalselection()
my_population.mutatedembabies()
resetscreen()
udpatescreen()

这是每个点的大脑:

import pygame as pg
import random
import math
class Brain():
def __init__(self,size):
self.size=size
self.directions=[]
self.step=0
def randomize(self):
for i in range(self.size):
randomangle=random.uniform(0,2*math.pi)
self.directions.append(randomangle)
def clone(self):
self.brainclone = Brain(self.size)
# print("old directions",self.directions)
for d in self.directions:
self.brainclone.directions.append(d)
# print("new directions",self.brainclone.directions)    
return self.brainclone
def mutate(self):
self.mutationrate = 0.01
for i in range(len(self.directions)):
self.rand = random.uniform(0,1)
if self.rand < self.mutationrate:
self.directions[i] = random.uniform(0,2*math.pi)

这是点的填充:

import pygame as pg
import dots
import random
import math
class Population():
def __init__(self,size,startpos,window,step,id):
self.size = size
self.gen = 1
self.my_dots = []
self.id = id
(x,y) = startpos
for i in range(size):
self.my_dots.append(dots.Dots((255,255,255),x,y,5,window,i,step))
def move(self):
for d in self.my_dots:
d.move(random.uniform(0,2*math.pi))
def calculatefitness(self):
for d in self.my_dots:
d.calculatefitness()
def allDotsDead(self):
for d in self.my_dots:
if (not d.dead) and (not d.reachedgoal):
return False
return True 
def naturalselection(self):
self.newdots = []
self.calculateFitnessSum()
for d in self.my_dots:
# Select parent based on fitness
self.parent = self.selectparent()
# Get a baby
self.baby = self.parent.gimmebaby()
self.newdots.append(self.baby)
self.my_dots = self.newdots
self.gen += 1
self.id += 1
def calculateFitnessSum(self):
self.fitnesssum = 0
for d in self.my_dots:
self.fitnesssum += d.fitness    
def selectparent(self):
self.rand = random.uniform(0,self.fitnesssum)
self.runningsum = 0
for d in self.my_dots:
self.runningsum += d.fitness
if self.runningsum > self.rand:
return d
# Should never go to this point     
return None
def mutatedembabies(self):
for d in self.my_dots:
# print("old brain: ",d.brain.directions)
d.brain.mutate()
# print("new brain: ",d.brain.directions)

最后是点类:

import pygame as pg
import random
import brain
import math
vec = pg.math.Vector2
class Dots(pg.sprite.Sprite):
def __init__(self,color,x,y,radius,window,id,step):
pg.sprite.Sprite.__init__(self)
self.maxspeed = 4
self.window = window
self.id = id
self.color = color
self.x = x
self.y = y
self.pos = vec (self.x,self.y)
self.radius = radius
self.step = step
self.id = id
self.image = pg.Surface((10,10),pg.SRCALPHA)
self.rect = self.image.get_rect(center=self.pos)
self.image.fill(color)
#pg.draw.circle(self.image,(random.randrange(0,255),random.randrange(0,255),random.randrange(0,255)),(5,5),self.radius)
pg.draw.ellipse(self.image,(random.randrange(0,255),random.randrange(0,255),random.randrange(0,255)),[0, 0, 10, 10],0)
self.vel = vec(0, 0)    
self.accel = vec(0, 0)
self.dead = False
self.brain = brain.Brain(step)
self.brain.randomize()
self.reachedgoal = False
def move(self,angle):
# self.update()
if self.dead or self.reachedgoal:
self.rect.clamp_ip(self.window.get_rect())
else:
if self.vel.length() > self.maxspeed:
self.vel.scale_to_length(self.maxspeed)
if self.brain.step < len(self.brain.directions):
self.accel = [math.cos(angle), math.sin(angle)]
self.step += 1
else:
self.dead = True
self.vel += self.accel
self.pos += self.vel
self.rect.center = self.pos
def update(self):
if (not self.dead) and (not self.reachedgoal):
self.move(random.uniform(0,2*math.pi))
if self.pos.x < 0 or self.pos.x > self.window.get_width() or self.pos.y < 2 or self.pos.y > self.window.get_height():
self.dead = True
if self.pos.distance_to(vec((400, 0))) < 15:  # Change pos of goal if goal changed
self.reachedgoal = True

def calculatefitness(self):
self.distanceTogoal = self.pos.distance_to(vec((self.window.get_width()/2), 0)) 
self.fitness = 1/(self.distanceTogoal*self.distanceTogoal)

def gimmebaby(self):
self.baby = Dots((255,255,255),self.x,self.y,5,self.window,self.id,self.step) # A revoir
self.baby.brain = self.brain.clone()
return self.baby

再次感谢!!

我想通了:在我的点类中,当我尝试移动每个点时,我使用一个随机函数,该函数返回一个介于 0 和 2*pi 之间的随机值,相反,我应该使用大脑的方向,所以它会像:

self.move(self.brain.directions[self.brain.step])

因为在进化时,点应该像上一代的点一样再现最好的运动,因此当我使用随机角度时,它们独立于过去几代人移动。

最新更新