-
Notifications
You must be signed in to change notification settings - Fork 18
/
ga.cpp
178 lines (143 loc) · 4.38 KB
/
ga.cpp
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
// A very rough C++ version for the 2048 game
//
// Author: Olafur Waage / @olafurw
//
// Under the Apache License
// If you have any fun with this, please let me know, I would love to hear from you.
#include <iostream>
#include "grid.hpp"
unsigned int tournament_selection(const std::vector<grid>& population)
{
std::uniform_int_distribution<> dis(0, population.size() - 1);
unsigned int parent_a = dis(rand_gen());
int parent_a_score = population[parent_a].score();
unsigned int parent_b = dis(rand_gen());
int parent_b_score = population[parent_b].score();
return parent_a_score > parent_b_score ? parent_a : parent_b;
}
void mutation(std::vector<direction>& child_a_actions)
{
std::uniform_int_distribution<> dis(0, 99);
for(unsigned int i = 0; i < child_a_actions.size(); ++i)
{
if(dis(rand_gen()) < 10)
{
child_a_actions[i] = rand_action();
}
}
}
void one_point_crossover(const std::vector<direction>& parent_a,
const std::vector<direction>& parent_b,
grid& child_a,
grid& child_b)
{
std::uniform_int_distribution<> dis(0, parent_a.size());
std::vector<direction> child_a_actions;
std::vector<direction> child_b_actions;
unsigned int split_a = dis(rand_gen());
unsigned int smaller_parent = std::min(parent_a.size(), parent_b.size());
unsigned int larger_parent = std::max(parent_a.size(), parent_b.size());
unsigned int split = std::min(split_a, smaller_parent);
for(unsigned int i = 0; i < smaller_parent; ++i)
{
if(i < split)
{
child_a_actions.push_back(parent_a.at(i));
child_b_actions.push_back(parent_b.at(i));
}
else
{
child_a_actions.push_back(parent_b.at(i));
child_b_actions.push_back(parent_a.at(i));
}
}
// TODO: Refactor, doing this now since each
// child can be of different lengths
// and the split can be in the larger parent
for(unsigned int i = smaller_parent; i < larger_parent; ++i)
{
if(i < split)
{
if(larger_parent == parent_b.size())
{
child_a_actions.push_back(parent_b.at(i));
}
else
{
child_b_actions.push_back(parent_b.at(i));
}
}
else
{
if(larger_parent == parent_b.size())
{
child_a_actions.push_back(parent_b.at(i));
}
else
{
child_b_actions.push_back(parent_a.at(i));
}
}
}
mutation(child_a_actions);
mutation(child_b_actions);
child_a.add_actions(child_a_actions);
child_b.add_actions(child_b_actions);
}
void sort_population(std::vector<grid>& population)
{
std::sort(population.begin(), population.end(),
[](const grid & a, const grid & b)
{
return a.score() > b.score();
});
}
void sort_population_random(std::vector<grid>& population)
{
std::shuffle(population.begin(), population.end(), rand_gen());
}
int main()
{
// Initial population
std::vector<grid> population;
int largest = 0;
for(int i = 0; i < 100; ++i)
{
grid g;
while(g.can_move())
{
g.action(rand_action());
}
population.emplace_back(g);
}
for(unsigned int i = 0; i < 100000; ++i)
{
unsigned int parent_a = tournament_selection(population);
unsigned int parent_b = tournament_selection(population);
grid child_a;
grid child_b;
one_point_crossover(population.at(parent_a).actions(),
population.at(parent_b).actions(),
child_a,
child_b);
population.emplace_back(child_a);
population.emplace_back(child_b);
sort_population(population);
population.pop_back();
population.pop_back();
if(largest < population.at(0).score())
{
largest = population.at(0).score();
std::cout << largest << std::endl;
}
sort_population_random(population);
}
sort_population(population);
population.at(0).print();
for(auto const& p : population)
{
std::cout << p.score() << std::endl;
}
return 0;
}