Skip to main content

vec_rac/
brain.rs

1use crate::racetrack::Racetrack;
2use crate::rng::Rng;
3use crate::vector::Vector;
4use std::iter;
5
6// XXX: Change repeat_array when you change this.
7const N_MID_WEIGHTS: usize = 32;
8
9#[derive(Clone, PartialEq, PartialOrd)]
10pub struct Brain {
11    view_dist: i32,
12    mid_weights: [Vec<f32>; N_MID_WEIGHTS],
13    out_weights: [[f32; N_MID_WEIGHTS]; 5],
14}
15
16impl Brain {
17    pub fn random(view_dist: i32, rng: &mut Rng) -> Brain {
18        let view_dist = pos_round_up_2(i32::abs(view_dist));
19        let n_inputs = ((view_dist / 2) * (view_dist / 2) * 4) as usize - 2;
20        Brain {
21            view_dist,
22            mid_weights: repeat_array(|| {
23                iter::repeat_with(|| random_f32(rng))
24                    .take(n_inputs)
25                    .collect()
26            }),
27            out_weights: [
28                repeat_array(|| random_f32(rng)),
29                repeat_array(|| random_f32(rng)),
30                repeat_array(|| random_f32(rng)),
31                repeat_array(|| random_f32(rng)),
32                repeat_array(|| random_f32(rng)),
33            ],
34        }
35    }
36
37    pub fn mutant(&self, rng: &mut Rng, amount: f64) -> Brain {
38        let amount = amount as f32;
39        let mut mutant = self.clone();
40        for neuron in mutant.mid_weights.iter_mut() {
41            for weight in neuron {
42                *weight += random_f32(rng) * amount;
43            }
44        }
45        for neuron in mutant.out_weights.iter_mut() {
46            for weight in neuron {
47                *weight += random_f32(rng) * amount;
48            }
49        }
50        mutant
51    }
52
53    pub fn compute_accel(&self, vel: Vector, track: &Racetrack) -> Vector {
54        let mut mid_iter = self.mid_weights.iter();
55        let mid_out = repeat_array(|| {
56            if let Some(neuron) = mid_iter.next() {
57                let quarter = (neuron.len() - 2) / 4;
58                let mut sum = 0.0;
59                let mut i = 0;
60                for x in (1..self.view_dist).step_by(2) {
61                    for y in (1..self.view_dist).step_by(2) {
62                        if let Some(true) = track.get(Vector::new(x, y)) {
63                            sum += neuron[i];
64                        }
65                        if let Some(true) = track.get(Vector::new(-x, y)) {
66                            sum += neuron[i + 1 * quarter];
67                        }
68                        if let Some(true) = track.get(Vector::new(-x, -y)) {
69                            sum += neuron[i + 2 * quarter];
70                        }
71                        if let Some(true) = track.get(Vector::new(x, -y)) {
72                            sum += neuron[i + 3 * quarter];
73                        }
74                        i += 1;
75                    }
76                }
77                sum += vel.x as f32 * neuron[neuron.len() - 2];
78                sum += vel.y as f32 * neuron[neuron.len() - 1];
79                sum
80            } else {
81                unreachable!()
82            }
83        });
84        assert!(mid_iter.next().is_none());
85        let mut out = vec![
86            compute_out(&self.out_weights[0], &mid_out),
87            compute_out(&self.out_weights[1], &mid_out),
88            compute_out(&self.out_weights[2], &mid_out),
89            compute_out(&self.out_weights[3], &mid_out),
90            compute_out(&self.out_weights[4], &mid_out),
91        ]
92        .into_iter();
93        let mut max = out.next().unwrap();
94        let mut max_i = 0;
95        for (i, choice) in out.enumerate() {
96            if choice > max {
97                max = choice;
98                max_i = i;
99            }
100        }
101        match max_i {
102            0 => Vector::new(1, 0),
103            1 => Vector::new(0, 1),
104            2 => Vector::new(-1, 0),
105            3 => Vector::new(0, -1),
106            4 => Vector::ORIGIN,
107            _ => unreachable!(),
108        }
109    }
110}
111
112fn pos_round_up_2(num: i32) -> i32 {
113    (num + 1) & !1
114}
115
116fn random_f32(rng: &mut Rng) -> f32 {
117    rng.forward() as f32 / Rng::RAND_MAX as f32 * 2.0 - 1.0
118}
119
120fn repeat_array<T, F: FnMut() -> T>(mut f: F) -> [T; N_MID_WEIGHTS] {
121    // TODO: This is dumb.
122    [
123        f(),
124        f(),
125        f(),
126        f(),
127        f(),
128        f(),
129        f(),
130        f(),
131        f(),
132        f(),
133        f(),
134        f(),
135        f(),
136        f(),
137        f(),
138        f(),
139        f(),
140        f(),
141        f(),
142        f(),
143        f(),
144        f(),
145        f(),
146        f(),
147        f(),
148        f(),
149        f(),
150        f(),
151        f(),
152        f(),
153        f(),
154        f(),
155    ]
156}
157
158fn compute_out(neuron: &[f32; N_MID_WEIGHTS], inputs: &[f32; N_MID_WEIGHTS]) -> f32 {
159    neuron.into_iter().zip(inputs).map(|(&w, &i)| w * i).sum()
160}