1extern crate rand;
2extern crate evco;
3
4use std::fmt;
5use std::ops::Rem;
6use rand::{OsRng, Rng, Rand};
7use std::collections::VecDeque;
8
9use evco::gp::*;
10use evco::gp::tree::*;
11
12#[derive(PartialEq, Eq, Clone, Copy, Debug)]
13pub enum TurnDirection {
14 Left,
15 Ahead,
16 Right,
17}
18
19impl Rand for TurnDirection {
20 fn rand<R: Rng>(r: &mut R) -> TurnDirection {
21 match r.next_u32() % 3 {
22 0 => TurnDirection::Left,
23 1 => TurnDirection::Ahead,
24 2 => TurnDirection::Right,
25 _ => unreachable!(),
26 }
27 }
28}
29
30#[derive(PartialEq, Eq, Clone, Copy, Debug)]
31pub enum CompassDirection {
32 North,
33 East,
34 South,
35 West,
36}
37
38impl CompassDirection {
39 fn variants() -> &'static [CompassDirection] {
40 static VARIANTS: &'static [CompassDirection] = &[CompassDirection::North,
41 CompassDirection::East,
42 CompassDirection::South,
43 CompassDirection::West];
44 VARIANTS
45 }
46}
47
48impl Rand for CompassDirection {
49 fn rand<R: Rng>(r: &mut R) -> CompassDirection {
50 match r.next_u32() % 4 {
51 0 => CompassDirection::North,
52 1 => CompassDirection::East,
53 2 => CompassDirection::South,
54 3 => CompassDirection::West,
55 _ => unreachable!(),
56 }
57 }
58}
59
60#[derive(PartialEq, Eq, Clone, Copy, Debug)]
61pub struct Vector {
62 x: isize,
63 y: isize,
64}
65
66impl Vector {
67 fn neighbour(&self, direction: &CompassDirection) -> Vector {
68 match *direction {
69 CompassDirection::North => {
70 Vector {
71 x: self.x,
72 y: self.y - 1,
73 }
74 }
75 CompassDirection::East => {
76 Vector {
77 x: self.x + 1,
78 y: self.y,
79 }
80 }
81 CompassDirection::South => {
82 Vector {
83 x: self.x,
84 y: self.y + 1,
85 }
86 }
87 CompassDirection::West => {
88 Vector {
89 x: self.x - 1,
90 y: self.y,
91 }
92 }
93 }
94 }
95
96 fn direction_to(&self, possible_neighbour: Vector) -> Option<CompassDirection> {
97 for direction in CompassDirection::variants() {
98 let neighbour = self.neighbour(direction);
99 if neighbour == possible_neighbour {
100 return Some(*direction);
101 }
102 }
103 None
104 }
105}
106
107#[derive(PartialEq, Eq, Clone, Debug)]
108pub struct SnakeEnvironment {
109 pub size: Vector,
110 pub food: Vector,
111 pub snake: Vec<Vector>,
112}
113
114impl SnakeEnvironment {
115 fn turn_to_compass_direction(&self, turn_direction: TurnDirection) -> CompassDirection {
116 let snake_current_compass_direction = self.snake[1].direction_to(self.snake[0]).unwrap();
117 let directions = CompassDirection::variants();
118 let index: isize =
119 directions.iter().position(|&r| r == snake_current_compass_direction).unwrap() as isize;
120 let new_compass_direction_index = match turn_direction {
121 TurnDirection::Left => (index + 3).rem(4),
122 TurnDirection::Ahead => index,
123 TurnDirection::Right => (index + 5).rem(4),
124 };
125 directions[new_compass_direction_index as usize]
126 }
127
128 fn sense_danger(&self, turn_direction: TurnDirection) -> bool {
129 let compass_direction = self.turn_to_compass_direction(turn_direction);
130 let cell_in_direction = self.snake[0].neighbour(&compass_direction);
131 (cell_in_direction.x < 0 || cell_in_direction.y < 0 ||
132 cell_in_direction.x >= self.size.x || cell_in_direction.y >= self.size.y ||
133 self.snake.contains(&cell_in_direction))
134 }
135
136 fn sense_food(&self, turn_direction: TurnDirection) -> bool {
137 let compass_direction = self.turn_to_compass_direction(turn_direction);
138 let cell_in_direction = self.snake[0].neighbour(&compass_direction);
139 self.food == cell_in_direction
140 }
141
142 fn perform_movement(&mut self, turn_direction: TurnDirection) {
143 let compass_direction = self.turn_to_compass_direction(turn_direction);
144 let old_head = self.snake[0];
145 self.snake.pop();
146 self.snake.insert(0, old_head.neighbour(&compass_direction));
147 }
148}
149
150#[derive(Clone, Debug)]
151pub enum SnakeTree {
152 IfDanger(TurnDirection, BoxTree<SnakeTree>, BoxTree<SnakeTree>),
153 IfFood(TurnDirection, BoxTree<SnakeTree>, BoxTree<SnakeTree>),
154 Move(TurnDirection),
155}
156
157use SnakeTree::*;
158
159impl Tree for SnakeTree {
160 type Environment = SnakeEnvironment;
161 type Action = TurnDirection;
162
163 fn branch<R: Rng>(tg: &mut TreeGen<R>, current_depth: usize) -> BoxTree<Self> {
164 let direction = TurnDirection::rand(tg);
165 let true_ = Self::child(tg, current_depth + 1);
166 let false_ = Self::child(tg, current_depth + 1);
167 if tg.gen() {
168 IfDanger(direction, true_, false_).into()
169 } else {
170 IfFood(direction, true_, false_).into()
171 }
172 }
173
174 fn leaf<R: Rng>(tg: &mut TreeGen<R>, _: usize) -> BoxTree<Self> {
175 Move(TurnDirection::rand(tg)).into()
176 }
177
178 fn count_children(&mut self) -> usize {
179 match *self {
180 IfDanger(_, _, _) |
181 IfFood(_, _, _) => 2,
182 Move(_) => 0,
183 }
184 }
185
186 fn children(&self) -> Vec<&BoxTree<Self>> {
187 match *self {
188 IfDanger(_, ref left_, ref right_) |
189 IfFood(_, ref left_, ref right_) => vec![left_, right_],
190 Move(_) => vec![],
191 }
192 }
193
194 fn children_mut(&mut self) -> Vec<&mut BoxTree<Self>> {
195 match *self {
196 IfDanger(_, ref mut left_, ref mut right_) |
197 IfFood(_, ref mut left_, ref mut right_) => vec![left_, right_],
198 Move(_) => vec![],
199 }
200 }
201
202 fn evaluate(&self, env: &Self::Environment) -> Self::Action {
203 match *self {
204 IfDanger(direction, ref left_, ref right_) => {
205 if env.sense_danger(direction) {
206 left_.evaluate(env)
207 } else {
208 right_.evaluate(env)
209 }
210 }
211 IfFood(direction, ref left_, ref right_) => {
212 if env.sense_food(direction) {
213 left_.evaluate(env)
214 } else {
215 right_.evaluate(env)
216 }
217 }
218 Move(direction) => direction,
219 }
220 }
221}
222
223impl fmt::Display for SnakeTree {
224 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
225 let mut stack: VecDeque<&Self> = VecDeque::new();
226 let mut depth_stack: VecDeque<usize> = VecDeque::new();
227 stack.push_back(self);
228 depth_stack.push_back(0);
229 while let (Some(node), Some(depth)) = (stack.pop_back(), depth_stack.pop_back()) {
230 for _ in 0..depth {
231 write!(f, " ")?;
232 }
233 match *node {
234 IfDanger(direction, _, _) => write!(f, "IfDanger({:?})", direction)?,
235 IfFood(direction, _, _) => write!(f, "IfFood({:?})", direction)?,
236 Move(direction) => write!(f, "Move({:?})", direction)?,
237 }
238 write!(f, "\n")?;
239
240 let mut children = node.children();
241 children.reverse();
242 for child in children {
243 stack.push_back(child);
244 depth_stack.push_back(depth + 1);
245 }
246 }
247 Ok(())
248 }
249}
250
251fn main() {
252 let mut rng = OsRng::new().unwrap();
253 let mut tree_gen = TreeGen::full(&mut rng, 1, 4);
254
255 let mut indv1: Individual<SnakeTree> = Individual::new(&mut tree_gen);
256 let mut indv2: Individual<SnakeTree> = Individual::new(&mut tree_gen);
257
258 let mut rng = OsRng::new().unwrap();
259 let crossover = Crossover::one_point();
260 println!("---");
261 println!("{}", indv1);
262 println!("{}", indv2);
263 println!("---");
264 crossover.mate(&mut indv1, &mut indv2, &mut rng);
265 println!("{}", indv1);
266 println!("{}", indv2);
267 println!("---");
268
269 println!("{}", indv1);
270 let mut mutate_rng = OsRng::new().unwrap();
271 let mut tree_gen = TreeGen::full(&mut mutate_rng, 1, 2);
272 let mutation = Mutation::uniform();
273 mutation.mutate(&mut indv1, &mut tree_gen);
274 println!("{}", indv1);
275
276 let mut env = SnakeEnvironment {
277 size: Vector { x: 10, y: 10 },
278 food: Vector { x: 9, y: 9 },
279 snake: vec![Vector { x: 3, y: 3 }, Vector { x: 4, y: 3 }],
280 };
281
282 for _ in 0..200 {
283 let indv: Individual<SnakeTree> = Individual::new(&mut tree_gen);
284
285 let mut score1 = 0;
286 let mut score2 = 0;
287 let mut tick = 100;
288 while tick > 0 {
289 let move_ = indv.tree.evaluate(&env);
291 if env.sense_danger(move_) {
292 break;
293 }
294 if env.sense_food(move_) {
295 score2 += 1;
296 tick += 100;
297 env.food = Vector {
298 x: rng.gen_range(0, 11),
299 y: rng.gen_range(0, 11),
300 };
301 }
302 env.perform_movement(move_);
303 score1 += 1;
304 tick -= 1;
305 }
306 if score2 >= 1 {
307 println!("lived={:?} ate={:?}", score1, score2);
308 println!("{}", indv);
309 }
310 }
311}