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
|
use rand::Rng;
use crate::game::{Game, GameLog, GameLogger, PointLogger, Status, Field};
use crate::doublebuffer::DoubleBuffer;
#[derive(Debug, Clone)]
pub struct Layer {
/// vector of (vectors of weights onto the past layer)
nodes: Vec<Vec<f32>>,
}
#[derive(Debug, Clone)]
pub struct Nn {
layers: Vec<Layer>
}
fn randaround(x: f32) -> f32 {
rand::thread_rng().gen_range(-x, x)
}
impl Nn {
pub fn new_empty(layers: &[u32]) -> Self {
Self {
layers: layers.iter().take(layers.len() - 1).zip(layers.iter().skip(1)).map(|(&n1, &n2)| Layer {
nodes: std::iter::repeat(std::iter::repeat(1.0).take(n1 as usize).collect()).take(n2 as usize).collect()
}).collect(),
}
}
pub fn new_random(layers: &[u32]) -> Self {
Self {
layers: layers.iter().take(layers.len() - 1).zip(layers.iter().skip(1)).map(|(&n1, &n2)| Layer {
nodes: std::iter::repeat_with(|| (0..(n1 as usize)).map(|_| randaround(1.0)).collect()).take(n2 as usize).collect()
}).collect(),
}
}
pub fn add_noise(&mut self, hard_noise: f32, fine_noise: f32, w: f32, r: f32) {
let complete = randaround(1.0).abs() < r;
for Layer { nodes: layer_mappings } in self.layers.iter_mut() {
for layer_mapping in layer_mappings.iter_mut() {
layer_mapping.iter_mut().for_each(|v| {
if complete {
*v = randaround(hard_noise);
} else {
*v += if randaround(1.0).abs() < w
{ randaround(hard_noise) } else { randaround(fine_noise) }
}
});
}
}
}
pub fn new_by_game_res<F: Fn(&[u32]) -> Self>(cols: u32, rows: u32, f: &F) -> Self {
// fields + 1xplayer_y + 1xplayer_v
let input_layer_size = cols * rows + 1 + 1;
f(&[input_layer_size,
rows * cols,
cols,
1])
}
fn status_to_layer(status: &Status, _cols: u32, rows: u32) -> Vec<f32> {
[status.player[1] as f32 / rows as f32, status.player_v as f32].iter()
.map(|&x| x)
.chain(
status.fields.iter().map(|f| match f {
Field::Air => 0.0,
Field::Wall => 1.0,
Field::Spike => -1.0,
})
).collect()
}
pub fn execute<G: Game>(&self, game: G) -> u64 {
self.execute_with_logger::<G, PointLogger>(game)
}
pub fn execute_logged<G: Game>(&self, game: G) -> GameLog {
self.execute_with_logger::<G, GameLog>(game)
}
fn execute_with_logger<G: Game, L: GameLogger>(&self, mut game: G) -> L::Output {
let (cols, rows) = game.size();
let mut log = L::new_empty(cols, rows);
log.append(&game.status());
while let Some(status) = game.update() {
log.append(&status);
let input_layer = Self::status_to_layer(&status, cols, rows);
let mut db = DoubleBuffer::new(input_layer, vec![]);
for Layer {nodes: layer_mappings} in self.layers.iter().skip(1) {
*db.second_mut() = layer_mappings.iter().map(|layer_mapping| {
layer_mapping.iter().zip(db.first().iter())
.map(|(w, v)| v * w)
.sum()
}).collect();
db.switch();
}
//println!("out: {:?} | threshold: {}", db.first(), cols);
if db.first()[0] >= cols as f32 {
game.jump();
}
}
log.extract()
}
}
|