-
Notifications
You must be signed in to change notification settings - Fork 0
/
ga.py
192 lines (158 loc) · 5.78 KB
/
ga.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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
import sys
import time
import random
import pygame
from math import sqrt
cities = list()
random.seed(1337)
#City class
class City:
#City has name and coords (x,y)
def __init__(self, n, x, y):
self.n = n
self.x = x
self.y = y
def __str__(self):
return "name : {0} coords : ({1},{2})".format(self.n, self.x, self.y)
#return dist between two cities
def score(v1, v2):
return sqrt(pow(v2.x - v1.x, 2)+pow(v2.y - v1.y, 2))
class Solution:
def __init__(self, init = True):
self.ary = list()
if init:
indices = range(0, len(cities))
self.ary = random.sample(indices, len(indices))
def score(self):
sum = 0
for i in range(0, len(cities)-1):
sum += City.score(cities[self.ary[i]], cities[self.ary[i+1]])
return sum
def crossover(s1, s2):
length = len(cities)
start = random.randint(0,length-1)
stop = random.randint(start + 1,length)
#on stocke les indices qu'on doit changer
indices_selectionnes_x = s1.ary[start:stop]
indices_selectionnes_y = s2.ary[start:stop]
#preparation
for i,n in enumerate(s1.ary):
if n in indices_selectionnes_y:
s1.ary[i] = "*"
for i,n in enumerate(s2.ary):
if n in indices_selectionnes_x:
s2.ary[i] = "*"
#print(indices_selectionnes_x)
#print(indices_selectionnes_y)
#print("s1 : ", s1.ary)
#print("s2 : ", s2.ary)
#tassement
Solution.compress(s1.ary, start, stop)
Solution.compress(s2.ary, start, stop)
#echange
s1.ary[start:stop] = indices_selectionnes_y
s2.ary[start:stop] = indices_selectionnes_x
childx = Solution(False)
childy = Solution(False)
childx.ary = s1.ary
childy.ary = s2.ary
#print("child 1", childx.ary)
#print("child 2", childy.ary)
return childx, childy
def compress(ary, start, stop):
temp = list()
for i in range(stop, len(ary)):
if ary[i] != "*":
temp.append(ary[i])
for i in range(0, stop):
if ary[i] != "*":
temp.append(ary[i])
temp.reverse()
for i in range(stop, len(ary)):
ary[i] = temp.pop()
for i in range(0, start):
ary[i] = temp.pop()
for i in range(start, stop):
ary[i] = "*"
return ary
def ga_solve(file = None, gui=True, maxTime=0):
circle_color = (100,200,200)
line_color = (200,200,200)
red = (255, 0, 0)
(width, height) = (500, 500)
if file == None:
screen = pygame.display.set_mode((width, height))
running = True
while running:
#get data
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
x,y = pygame.mouse.get_pos()
cities.append(City("v{:d}".format(len(cities)), x, y))
if event.type is pygame.KEYDOWN and event.key is pygame.K_ESCAPE:
ga_solve(None, True, maxTime)
if event.type == pygame.QUIT:
running = False
for c in cities:
pygame.draw.circle(screen, circle_color, (c.x, c.y), 10, 3)
pygame.display.flip()
else:
with open(file) as f:
for line in f:
#get data from file
words = line.split()
cities.append(City(words[0], int(words[1]), int(words[2])))
screen = pygame.display.set_mode((width, height))
time.clock()
popSize = 4
solutions = list()
nGen = 0
for i in range(popSize):
solutions.append(Solution(True))
bestScore = solutions[0].score()
bestPath = solutions[0].ary
while True:
#pour l'instant on croise la meilleure moitié du tableau et l'autre moitié on refait random, c'est pas terrible faudrait revoir ça ..
#ptêtre c'est précisé dans le pdf, je sais pas trop comment faire
#selection
solutions = sorted(solutions, key=lambda x : x.score()) #elitiste
if solutions[0].score() < bestScore:
bestScore = solutions[0].score()
bestPath = solutions[0].ary
#mutation
#ça faut faire
#crossover
#première partie du tableau remplacée par les enfants
for i in range(int((len(solutions)/2))-1):
c1, c2 = Solution.crossover(solutions[i], solutions[i+1])
solutions[i] = c1
solutions[i+1] = c2
#deuxième partie du tableau random
for i in range(int(len(solutions)/2), len(solutions)):
solutions[i] = Solution(True)
print("Best score : ", bestScore)
nGen+=1
print("gen number : ", nGen)
#affichage
if gui:
#clear le screen
screen.fill((0, 0, 0))
points = None
points = list()
bestpoints = None
bestpoints = list()
#on rajoute tout le parcours dans une liste de points
for i in range(len(solutions[0].ary)):
points.append((cities[solutions[0].ary[i]].x,cities[solutions[0].ary[i]].y))
bestpoints.append((cities[bestPath[i]].x, cities[bestPath[i]].y))
#on affiche les points
pygame.draw.lines(screen, line_color, False, points, 1)
pygame.draw.lines(screen, red, False, bestpoints, 1)
#on ajoute des cercles pour les villess
for c in cities:
pygame.draw.circle(screen, circle_color, (c.x, c.y), 10, 3)
#et on display le tout
pygame.display.flip()
#fin affichage
if time.clock() >= maxTime:
break