-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpopulation.py
130 lines (105 loc) · 5.09 KB
/
population.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
import copy
from settings import Settings
from snake import Snake
from food import Food
from inputs import Inputs
from NeuralNetwork import NeuralNetwork
import numpy as np
from p5 import *
import random
from cprofiler import profile
class Population:
def __init__(self, settings):
self.settings: Settings = settings
self.FoodArr: list[Food] = []
self.SnakeArr: list[Snake] = []
self.InputArr: list[Inputs] = []
self.NNArr: list[NeuralNetwork] = []
self.snakesAlive = settings.numberOfSnakes
self.genBestIndex = 0
def setup(self):
for i in range(self.settings.numberOfSnakes):
self.FoodArr.append(Food(self.settings))
self.SnakeArr.append(Snake(self.settings, self.FoodArr[i]))
self.InputArr.append(Inputs(self.settings, self.SnakeArr[i]))
self.NNArr.append(NeuralNetwork(self.settings, self.InputArr[i]))
self.resetBestBrain()
self.updateBestBrain()
def resetBestBrain(self):
for i in range(self.settings.numberOfSnakes):
self.SnakeArr[i].hasBestBrain = False
self.SnakeArr[i].food.isFoodForBestSnake = False
def run(self):
for i in range(self.settings.numberOfSnakes):
self.updateBestBrain()
self.SnakeArr[i].update()
if(self.SnakeArr[i].alive == True):
self.FoodArr[i].update()
self.InputArr[i].generateInputs()
self.NNArr[i].controlSnake(self.SnakeArr[i])
self.snakesAlive = self.settings.numberOfSnakesAlive
if(self.snakesAlive == 0):
print("gen bests ------ index: {} eats: {} score: {}".format(self.genBestIndex, self.SnakeArr[self.genBestIndex].total, self.SnakeArr[self.genBestIndex].fitness))
print("global bests --- index: {} eats: {} score: {}".format(self.settings.globalBestIndex, self.settings.globalBestTotal, self.settings.globalBestScore))
self.startNextGeneration()
def updateBestBrain(self):
if(self.SnakeArr[self.genBestIndex].alive == False):
self.SnakeArr[self.genBestIndex].hasBestBrain = False
self.SnakeArr[self.genBestIndex].food.isFoodForBestSnake = False
#not idempotent:
self.calcBestSnakeBrainIndex()
self.SnakeArr[self.genBestIndex].hasBestBrain = True
self.SnakeArr[self.genBestIndex].food.isFoodForBestSnake = True
def startNextGeneration(self):
print("starting next gen")
#increment generation
self.settings.generation += 1
#do algorithm for genetics
self.createNewBrains()
#reset scores
self.settings.reset()
self.resetSnakesAndFood()
def createNewBrains(self):
#create a New NN from Old NN that has been mutated
self.calcBestSnakeBrainIndex()
for i in range(self.settings.numberOfSnakes):
#keep best global snake, and the best one for this generation!
if(i != self.genBestIndex or i != self.settings.globalBestIndex):
#create babies and match them with snakes based on score
self.NNArr[i] = self.naturalSelection(i)
def resetSnakesAndFood(self):
for i in range(self.settings.numberOfSnakes):
# self.FoodArr[i].spawnAtRandomLocation()
self.SnakeArr[i].resetSnake()
def naturalSelection(self, index):
self.calcBestSnakeBrainIndex()
#create a new NeuralNetwork
childNN = NeuralNetwork(self.settings, self.InputArr[index])
# select two brains from the existing pool to mate
selectedIndex1 = self.selectNNFromSnakeFitness()
selectedIndex2 = self.selectNNFromSnakeFitness()
childNN = childNN.crossover(self.NNArr[selectedIndex1], self.NNArr[selectedIndex2])
childNN = childNN.mutate()
return(childNN)
def selectNNFromSnakeFitness(self):
# has test in test_1.py
rand = random.randint(0, self.settings.totalFitness)
# print("random number selected: {} totalfitness: {}".format(rand, self.settings.totalFitness))
sum = 0
for i in range(self.settings.numberOfSnakes):
sum += self.SnakeArr[i].fitness
if(sum >= rand):
# print("index {} was selected for breeding with fitness {} sum: {}, rand: {}".format(i, self.SnakeArr[i].fitness, sum, rand))
return i
raise Exception("Function should not reach here.")
def calcBestSnakeBrainIndex(self):
#don't update the best index unless it beats the global best!
genBestScore = 0
for i in range(self.settings.numberOfSnakes):
if(self.SnakeArr[i].fitness > genBestScore):
genBestScore = self.SnakeArr[i].fitness
self.genBestIndex = i
#update global if it's better
if(self.SnakeArr[i].fitness > self.settings.globalBestScore):
self.settings.globalBestScore = self.SnakeArr[i].fitness
self.settings.globalBestIndex = i