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

Pygame: Dot game using genetic algorithm

我使用库 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)

最后是点 class:

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

再次感谢!!

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

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

因为在进化时,点应该重现上一代点的最佳运动,因此当我使用随机角度时,它们独立于上一代移动。