Evolution génétique: Fusées malines
Publié : dim. 28/janv./2018 21:27
Les fusées essaient d'atteindre leur but (le cercle bleu) en faisant évoluer leur population.
La fonction de fitness doit être amélioré. La longueur du génome, le nombre de fusée et le taux de mutation peut être ajusté.
La fonction de fitness doit être amélioré. La longueur du génome, le nombre de fusée et le taux de mutation peut être ajusté.
Code : Tout sélectionner
If InitSprite() = 0 Or InitKeyboard() = 0 Or InitMouse() = 0 Or OpenWindow(0, 0, 0, 800, 600, "Smart Rockets", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)=0 Or OpenWindowedScreen(WindowID(0),0,0,800,600,0,0,0,#PB_Screen_NoSynchronization )=0
MessageRequester("Error", "Can't open the sprite system", 0)
End
EndIf
#rocket=0:#target=1:#wall=2;sprites
#PopulationSize=200;number of rocket
#LifeSpan=700;length of the genome
#MutationRate=1 ;pourcent of mutation of the genes
Structure vector
x.f
y.f
EndStructure
Structure physic
hit.b
cancel.b
pos.vector
vel.vector
acc.vector
Maxfitness.f
gene.vector[#LifeSpan]
EndStructure
Global Target.vector:target\x=ScreenWidth()/2:target\y=70
Global wall.vector
wall\x=300
wall\y=300
Global Dim rocket.physic(#PopulationSize)
Global Generation.i=1
Global Hits.i=0
;create rocket's, target's and wall's sprites
CreateSprite(#rocket,32,32,#PB_Sprite_PixelCollision)
StartDrawing(SpriteOutput(#rocket))
LineXY(10,31,15,0,#Red)
LineXY(15,0,21,31,#Red)
LineXY(21,31,10,31,#Red)
FillArea(15,15,#Red,#Red)
StopDrawing()
CreateSprite(#target,32,32,#PB_Sprite_PixelCollision)
StartDrawing(SpriteOutput(#target))
Circle(15,15,15,#Blue)
StopDrawing()
CreateSprite(#wall,150,10,#PB_Sprite_PixelCollision)
StartDrawing(SpriteOutput(#wall))
Box(0,0,150,10,#White)
StopDrawing()
Procedure.f Heading(IndexRocket.i)
x.f=rocket(IndexRocket)\vel\x
y.f=rocket(IndexRocket)\vel\y
angle.f=ATan2(x,y)+#PI/2
ProcedureReturn Degree(angle)
EndProcedure
;Populate rockets
Procedure CreatePopulation()
For i=1 To #PopulationSize
rocket(i)\pos\x=ScreenWidth()/2-SpriteWidth(#rocket)/2
rocket(i)\pos\y=600-SpriteHeight(#rocket)
;create random DNA
For t=0 To #LifeSpan-1
rocket(i)\gene[t]\x=Cos(Random(2*#PI*10000)/10000)/10
rocket(i)\gene[t]\y=Sin(Random(2*#PI*10000)/10000)/10
Next t
Next i
EndProcedure
;Beget
Procedure CrossOver()
Static Dim ChildRocket.physic(#PopulationSize)
Generation+1
Hits=0
Protected NewList MatingPool()
;fill the mating pool with as much of each rocket as their fitness value
;so a large fitness value rocket has much more chance to be randomly picked to be parent
For IndexRocket=1 To #PopulationSize
For t=0 To rocket(IndexRocket)\Maxfitness
AddElement(MatingPool())
MatingPool()=IndexRocket
Next t
Next IndexRocket
For i=1 To #PopulationSize
PickedParentA=Random(ListSize(MatingPool())-1)
PickedParentB=Random(ListSize(MatingPool())-1)
midpoint.i=Random(#LifeSpan-1)
For t=0 To #LifeSpan-1
If t<midpoint
SelectElement(MatingPool(),PickedParentA)
Else
SelectElement(MatingPool(),PickedParentB)
EndIf
ChildRocket(i)\gene[t]=rocket(MatingPool())\gene[t]
;mutation
If Random(100)<#MutationRate
ChildRocket(i)\gene[t]\x=Cos(Random(2*#PI*10000)/10000)/10
ChildRocket(i)\gene[t]\y=Sin(Random(2*#PI*10000)/10000)/10
EndIf
Next t
rocket(i)\pos\x=ScreenWidth()/2-SpriteWidth(#rocket)/2
rocket(i)\pos\y=600-SpriteHeight(#rocket)
rocket(i)\vel\x=0
rocket(i)\vel\y=0
rocket(i)\hit=0
rocket(i)\Maxfitness=0
rocket(i)\cancel=0
Next i
For i=1 To #PopulationSize
For t=0 To #LifeSpan-1
rocket(i)\gene[t]=ChildRocket(i)\gene[t]
Next t
Next i
EndProcedure
Procedure UpdatePhysic()
Static Frame.i=0
For IndexRocket=1 To #PopulationSize
If rocket(IndexRocket)\cancel:Continue:EndIf
rocket(IndexRocket)\acc\x+rocket(IndexRocket)\gene[Frame]\x
rocket(IndexRocket)\acc\y+rocket(IndexRocket)\gene[Frame]\y
rocket(IndexRocket)\vel\x+rocket(IndexRocket)\acc\x
rocket(IndexRocket)\vel\y+rocket(IndexRocket)\acc\y
rocket(IndexRocket)\pos\x+rocket(IndexRocket)\vel\x
rocket(IndexRocket)\pos\y+rocket(IndexRocket)\vel\y
rocket(IndexRocket)\acc\x=0
rocket(IndexRocket)\acc\y=0
distance.f=Abs(rocket(IndexRocket)\pos\x-target\x)+Abs(rocket(IndexRocket)\pos\y-target\y)
;fitness between 0 and 100. 100 means it reachs accuratly the target
fitness.f=((ScreenWidth()+ScreenHeight())-distance)/(ScreenWidth()+ScreenHeight())*100
If fitness>rocket(IndexRocket)\Maxfitness:rocket(IndexRocket)\Maxfitness=fitness:EndIf
Next IndexRocket
Frame+1
If Frame=#LifeSpan:Frame=0:CrossOver():EndIf
EndProcedure
CreatePopulation()
Repeat
Repeat:Until WindowEvent()=0
FlipBuffers()
ClearScreen(#Black)
ExamineKeyboard()
UpdatePhysic()
;display rockets !
For IndexRocket=1 To #PopulationSize
RotateSprite(#rocket,Heading(IndexRocket),#PB_Absolute)
DisplayTransparentSprite(#rocket,rocket(IndexRocket)\pos\x,rocket(IndexRocket)\pos\y,128)
If rocket(IndexRocket)\hit=0 And SpritePixelCollision(#rocket,rocket(IndexRocket)\pos\x,rocket(IndexRocket)\pos\y,#target,target\x-SpriteWidth(#target)/2,target\y-SpriteHeight(#target)/2)
rocket(IndexRocket)\hit=1
Hits+1
;bonus to the rockets reaching the goal
If Hits>MaxHits:MaxHits=Hits:EndIf
rocket(IndexRocket)\Maxfitness*10
EndIf
If SpritePixelCollision(#rocket,rocket(IndexRocket)\pos\x,rocket(IndexRocket)\pos\y,#wall,wall\x,wall\y)
rocket(IndexRocket)\cancel=1
If rocket(IndexRocket)\hit=0
rocket(IndexRocket)\Maxfitness/10
EndIf
EndIf
Next IndexRocket
;display wall
DisplayTransparentSprite(#wall,wall\x,wall\y)
;display target
DisplayTransparentSprite(#target,target\x-SpriteWidth(#target)/2,target\y-SpriteHeight(#target)/2,128)
StartDrawing(ScreenOutput())
DrawText(0,0,"Generation : "+Str(Generation))
DrawText(0,25,"Target Hits : "+Str(Hits))
DrawText(0,50,"Max Target Hits : "+Str(MaxHits))
DrawText(0,75,"Press [Escape] to Quit")
StopDrawing()
Until KeyboardPushed(#PB_Key_Escape)