hlayers, mut_rate ui bridged

This commit is contained in:
sparshg 2023-01-12 03:01:03 +05:30
parent 39941c8425
commit 8d317346f8
5 changed files with 109 additions and 64 deletions

View File

@ -61,13 +61,13 @@ async fn main() {
let mut speedup = 1; let mut speedup = 1;
let mut paused = false; let mut paused = false;
let mut bias = false; let mut bias = false;
let mut size = 100; let mut size: u32 = 100;
let mut pop = Population::new(size as usize); let mut hlayers: Vec<usize> = vec![6, 6, 0];
let mut x = 0.; let mut prev_hlayers = hlayers.clone();
let mut xy = "".to_string(); let mut mut_rate = 0.05;
let mut l1: usize = 6; let mut prev_mut_rate = 0.05;
let mut l2: usize = 6; let mut pop = Population::new(size as usize, hlayers.clone(), mut_rate);
let mut l3: usize = 0; let mut activ: usize = 0;
let ui_thick = 34.; let ui_thick = 34.;
let nums = &[ let nums = &[
@ -115,7 +115,7 @@ async fn main() {
.build(); .build();
let group_style = root_ui() let group_style = root_ui()
.style_builder() .style_builder()
.color(Color::new(1., 0., 0., 1.)) .color(Color::new(1., 0., 0., 0.))
.build(); .build();
let editbox_style = root_ui() let editbox_style = root_ui()
.style_builder() .style_builder()
@ -129,11 +129,7 @@ async fn main() {
], ],
}) })
.background_margin(RectOffset::new(1., 1., 1., 1.)) .background_margin(RectOffset::new(1., 1., 1., 1.))
// .margin(RectOffset::new(10., 10., 8., 8.))
.text_color(WHITE) .text_color(WHITE)
// .color_hovered(WHITE)
// .color_inactive(WHITE)
// .color(WHITE)
.build(); .build();
let combobox_style = root_ui() let combobox_style = root_ui()
.style_builder() .style_builder()
@ -147,9 +143,6 @@ async fn main() {
], ],
}) })
.background_margin(RectOffset::new(1., 1., 1., 1.)) .background_margin(RectOffset::new(1., 1., 1., 1.))
// .margin(RectOffset::new(1., 1., 1., 1.))
// .text_color_hovered(WHITE)
// .text_color(WHITE)
.color_hovered(WHITE) .color_hovered(WHITE)
.color_selected_hovered(WHITE) .color_selected_hovered(WHITE)
.color_inactive(WHITE) .color_inactive(WHITE)
@ -174,11 +167,31 @@ async fn main() {
.style_builder() .style_builder()
.text_color(WHITE) .text_color(WHITE)
.font_size(16) .font_size(16)
// .margin(RectOffset::new(5., 5., 4., 0.))
.text_color_hovered(LIGHTGRAY) .text_color_hovered(LIGHTGRAY)
.text_color_clicked(WHITE) .text_color_clicked(WHITE)
.build(); .build();
skin2.button_style = root_ui()
.style_builder()
.background(Image {
width: 3,
height: 3,
bytes: vec![
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0,
0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255,
],
})
.background_margin(RectOffset::new(1., 1., 1., 1.))
.color_hovered(RED)
.color_clicked(BLUE)
.text_color(WHITE)
.text_color_hovered(WHITE)
.text_color_clicked(WHITE)
.margin(RectOffset::new(4., 4., 2., 2.))
.color_inactive(WHITE)
.build();
root_ui().push_skin(&skin);
loop { loop {
clear_background(BLACK); clear_background(BLACK);
set_camera(&gamecam); set_camera(&gamecam);
@ -245,9 +258,8 @@ async fn main() {
vec2(WIDTH + 2. * th, th), vec2(WIDTH + 2. * th, th),
vec2(ui_width, ui_height), vec2(ui_width, ui_height),
|ui| { |ui| {
ui.push_skin(&skin); widgets::Group::new(hash!(), vec2(ui_width, ui_thick))
widgets::Group::new(hash!(), Vec2::new(ui_width, ui_thick)) .position(vec2(0., 0.))
.position(Vec2::new(0., 0.))
.ui(ui, |ui| { .ui(ui, |ui| {
ui.label(None, &format!("Generation: {}", pop.gen)); ui.label(None, &format!("Generation: {}", pop.gen));
ui.same_line(242.); ui.same_line(242.);
@ -255,8 +267,19 @@ async fn main() {
if let Some(path) = open_file_dialog("Load Model", "model.json", None) { if let Some(path) = open_file_dialog("Load Model", "model.json", None) {
let brain = NN::import(&path); let brain = NN::import(&path);
size = 1; size = 1;
pop = Population::new(1); hlayers = brain
pop.worlds[0] = World::simulate(Some(brain)); .config
.iter()
.take(brain.config.len() - 1)
.skip(1)
.map(|x| x - 1)
.collect::<Vec<_>>();
hlayers.resize(3, 0);
prev_hlayers = hlayers.clone();
mut_rate = brain.mut_rate;
prev_mut_rate = brain.mut_rate;
pop = Population::new(size as usize, hlayers.clone(), mut_rate);
pop.worlds[0] = World::simulate(brain);
} }
} }
ui.same_line(0.); ui.same_line(0.);
@ -282,15 +305,18 @@ async fn main() {
paused = !paused; paused = !paused;
}; };
}); });
widgets::Group::new(hash!(), Vec2::new(ui_width, ui_thick)) widgets::Group::new(hash!(), vec2(ui_width, ui_thick))
.position(Vec2::new(0., ui_height - ui_thick)) .position(vec2(0., ui_height - ui_thick))
.ui(ui, |ui| { .ui(ui, |ui| {
ui.label(Some(vec2(0., 2.)), "«Population»"); ui.label(Some(vec2(0., 2.)), "Population:");
widgets::Group::new(hash!(), Vec2::new(100., ui_thick)) widgets::Group::new(hash!(), vec2(200., ui_thick))
.position(Vec2::new(140., 0.)) .position(vec2(80., 0.))
.ui(ui, |ui| { .ui(ui, |ui| {
ui.drag(hash!(), "", Some((1, 300)), &mut size); ui.drag(hash!(), "", Some((1, 300)), &mut size);
}); });
ui.push_skin(&skin2);
ui.label(Some(vec2(230., ui_thick * 0.5 - 7.)), "«Drag»");
ui.pop_skin();
ui.same_line(279.); ui.same_line(279.);
if widgets::Button::new(if pop.debug { "Debug:ON " } else { "Debug:OFF" }) if widgets::Button::new(if pop.debug { "Debug:ON " } else { "Debug:OFF" })
.ui(ui) .ui(ui)
@ -310,29 +336,39 @@ async fn main() {
}; };
ui.same_line(0.); ui.same_line(0.);
if widgets::Button::new(restart).ui(ui) { if widgets::Button::new(restart).ui(ui) {
pop = Population::new(size as usize); pop = Population::new(size as usize, hlayers.clone(), mut_rate);
}; };
}); });
ui.pop_skin();
ui.push_skin(&skin2); ui.push_skin(&skin2);
widgets::Group::new( widgets::Group::new(
hash!(), hash!(),
Vec2::new(ui_width * 0.2, ui_height * 0.8 - 2. * th - 2. * ui_thick), vec2(ui_width * 0.2, ui_height * 0.8 - 2. * th - 2. * ui_thick),
) )
.position(Vec2::new(ui_width * 0.8, ui_height * 0.2 + ui_thick + th)) .position(vec2(ui_width * 0.8 - th, ui_height * 0.2 + ui_thick + th))
.ui(ui, |ui| { .ui(ui, |ui| {
// ui.input_text(hash!(), "vec2(100., 100.)", &mut xy); // ui.input_text(hash!(), "vec2(100., 100.)", &mut xy);
ui.label(None, "Hidden Layers Neuron"); ui.label(None, "Hidden Layers");
ui.label(None, "Config"); ui.label(None, "Neurons Config");
ui.label(None, " ");
ui.combo_box(hash!(), "Layer 1", nums, &mut l1); ui.combo_box(hash!(), "Layer 1", nums, &mut hlayers[0]);
ui.combo_box(hash!(), "Layer 2", nums, &mut l2); ui.combo_box(hash!(), "Layer 2", nums, &mut hlayers[1]);
ui.combo_box(hash!(), "Layer 3", nums, &mut l3); ui.combo_box(hash!(), "Layer 3", nums, &mut hlayers[2]);
if prev_hlayers != hlayers {
pop = Population::new(size as usize, hlayers.clone(), mut_rate);
prev_hlayers = hlayers.clone();
}
ui.label(None, " "); ui.label(None, " ");
ui.label(None, "Mutation Rate"); ui.label(None, "Mutation Rate");
// ui.(hash!(), "", 0.0..0.2, &mut x); ui.drag(hash!(), "«Drag»", Some((0., 1.)), &mut mut_rate);
if prev_mut_rate != mut_rate {
pop.change_mut(mut_rate);
prev_mut_rate = mut_rate;
}
ui.label(None, " ");
ui.label(None, "Activation Func");
ui.combo_box(hash!(), "«Select»", &["ReLU", "Sigm"], &mut activ);
}); });
ui.pop_skin();
}, },
); );
next_frame().await; next_frame().await;

View File

@ -7,7 +7,7 @@ extern crate rand as r;
#[derive(PartialEq, Debug, Clone, Copy, Default, Serialize, Deserialize)] #[derive(PartialEq, Debug, Clone, Copy, Default, Serialize, Deserialize)]
enum ActivationFunc { pub enum ActivationFunc {
Sigmoid, Sigmoid,
Tanh, Tanh,
#[default] #[default]
@ -18,13 +18,13 @@ enum ActivationFunc {
pub struct NN { pub struct NN {
pub config: Vec<usize>, pub config: Vec<usize>,
pub weights: Vec<DMatrix<f32>>, pub weights: Vec<DMatrix<f32>>,
activ_func: ActivationFunc, pub activ_func: ActivationFunc,
mut_rate: f32, pub mut_rate: f32,
} }
impl NN { impl NN {
// Vec of number of neurons in input, hidden 1, hidden 2, ..., output layers // Vec of number of neurons in input, hidden 1, hidden 2, ..., output layers
pub fn new(config: Vec<usize>) -> Self { pub fn new(config: Vec<usize>, mut_rate: f32) -> Self {
let mut rng = r::thread_rng(); let mut rng = r::thread_rng();
Self { Self {
@ -45,7 +45,7 @@ impl NN {
}) })
.collect(), .collect(),
mut_rate: 0.05, mut_rate,
..Default::default() ..Default::default()
} }
} }

View File

@ -25,8 +25,17 @@ pub struct Player {
} }
impl Player { impl Player {
pub fn new() -> Self { pub fn new(config: Option<Vec<usize>>, mut_rate: Option<f32>) -> Self {
Self { Self {
brain: match config {
Some(mut c) => {
c.retain(|&x| x != 0);
c.insert(0, 5);
c.push(4);
Some(NN::new(c, mut_rate.unwrap()))
}
_ => None,
},
dir: vec2(0., -1.), dir: vec2(0., -1.),
rot: 1.5 * PI, rot: 1.5 * PI,
@ -41,21 +50,6 @@ impl Player {
} }
} }
pub fn simulate(brain: Option<NN>) -> Self {
let mut p = Player::new();
if let Some(brain) = brain {
// assert_eq!(
// brain.config[0] - 1,
// 8 + 5,
// "NN input size must match max_asteroids"
// );
p.brain = Some(brain);
} else {
p.brain = Some(NN::new(vec![5, 6, 6, 4]));
}
p
}
pub fn check_player_collision(&mut self, asteroid: &Asteroid) -> bool { pub fn check_player_collision(&mut self, asteroid: &Asteroid) -> bool {
// To give more near asteroids data: // To give more near asteroids data:

View File

@ -10,13 +10,17 @@ pub struct Population {
pub debug: bool, pub debug: bool,
pub worlds: Vec<World>, pub worlds: Vec<World>,
pub track: usize, pub track: usize,
pub hlayers: Vec<usize>,
} }
impl Population { impl Population {
pub fn new(size: usize) -> Self { pub fn new(size: usize, hlayers: Vec<usize>, mut_rate: f32) -> Self {
Self { Self {
size, size,
worlds: (0..size).map(|_| World::simulate(None)).collect(), hlayers: hlayers.clone(),
worlds: (0..size)
.map(|_| World::new(Some(hlayers.clone()), Some(mut_rate)))
.collect(),
..Default::default() ..Default::default()
} }
} }
@ -55,6 +59,12 @@ impl Population {
} }
} }
pub fn change_mut(&mut self, mut_rate: f32) {
for world in &mut self.worlds {
world.player.brain.as_mut().unwrap().mut_rate = mut_rate;
}
}
pub fn draw(&self) { pub fn draw(&self) {
for world in self.worlds.iter().rev() { for world in self.worlds.iter().rev() {
if self.focus { if self.focus {
@ -95,7 +105,7 @@ impl Population {
} }
println!("Gen: {}, Fitness: {}", self.gen, self.worlds[0].fitness); println!("Gen: {}, Fitness: {}", self.gen, self.worlds[0].fitness);
let mut new_worlds = (0..std::cmp::max(1, self.size / 20)) let mut new_worlds = (0..std::cmp::max(1, self.size / 20))
.map(|i| World::simulate(Some(self.worlds[i].see_brain().to_owned()))) .map(|i| World::simulate(self.worlds[i].see_brain().to_owned()))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
while new_worlds.len() < self.size { while new_worlds.len() < self.size {
let rands = (gen_range(0., total), gen_range(0., total)); let rands = (gen_range(0., total), gen_range(0., total));
@ -118,7 +128,7 @@ impl Population {
} }
let mut new_brain = NN::crossover(a.unwrap(), b.unwrap()); let mut new_brain = NN::crossover(a.unwrap(), b.unwrap());
new_brain.mutate(); new_brain.mutate();
new_worlds.push(World::simulate(Some(new_brain))); new_worlds.push(World::simulate(new_brain));
} }
self.worlds = new_worlds; self.worlds = new_worlds;
self.worlds[0].track(true); self.worlds[0].track(true);

View File

@ -17,9 +17,9 @@ pub struct World {
} }
impl World { impl World {
pub fn simulate(brain: Option<NN>) -> Self { pub fn new(hlayers: Option<Vec<usize>>, mut_rate: Option<f32>) -> Self {
Self { Self {
player: Player::simulate(brain), player: Player::new(hlayers, mut_rate),
score: 1., score: 1.,
asteroids: vec![ asteroids: vec![
Asteroid::new_to(vec2(0., 0.), 1.5, AsteroidSize::Large), Asteroid::new_to(vec2(0., 0.), 1.5, AsteroidSize::Large),
@ -32,6 +32,11 @@ impl World {
..Default::default() ..Default::default()
} }
} }
pub fn simulate(brain: NN) -> Self {
let mut w = World::new(None, None);
w.player.brain = Some(brain);
w
}
pub fn track(&mut self, track: bool) { pub fn track(&mut self, track: bool) {
self.track = track; self.track = track;