diff --git a/models/model.json b/models/model.json new file mode 100644 index 0000000..8539cbd --- /dev/null +++ b/models/model.json @@ -0,0 +1 @@ +{"config":[6,7,7,4],"weights":[[[-0.5567123,0.23674688,-0.8115287,0.73920447,-0.9627226,0.98842543,-0.08672536,0.11889564,0.19367097,0.84720945,0.10916865,0.19691469,0.34381783,-1.1452736,-0.7501932,0.65345323,1.1373248,-0.2888124,0.288057,0.09440576,-0.061547264,0.35609803,0.14600815,0.4276784,-0.8315937,-0.5220405,-0.7070066,-0.41821334,0.88325745,1.179611,-0.38369912,0.8185778,0.1276589,0.11540664,-0.2861217,-0.88901085],6,6],[[0.64678603,0.11032932,-0.17325084,0.4482577,-0.4668608,-0.061782226,-0.23166645,-1.189321,0.38457078,-0.040191226,-1.0519018,0.53179306,-0.27904406,0.18169245,-0.028529042,0.4248598,0.6224678,-0.48197106,-0.8517104,0.626093,-0.53116995,0.74109083,-0.4775906,-0.6105986,-0.11459249,0.54738194,0.53385884,0.05052872,0.56253725,0.6168962,0.3087382,1.4871372,-0.058942188,-0.13154379,0.6763109,-0.72106224,-0.13756883,-0.10921177,-0.12797734,-0.12984648,0.47288033,0.06618643],6,7],[[0.24218078,0.1842654,0.27074534,0.50006706,0.9494213,-0.7030016,-0.1101043,0.5054117,0.18234585,-1.429309,-0.14925024,0.47471818,-1.079322,1.0112062,-0.5279594,-0.13144909,1.0667706,-0.85650563,0.076754875,1.3830073,-0.50329316,0.61952496,-0.94159657,-0.27969155,-0.6343474,0.08405438,1.0401202,-1.3237122],4,7]],"activ_func":"ReLU","mut_rate":0.05} \ No newline at end of file diff --git a/src/asteroids.rs b/src/asteroids.rs index bc8b6f7..afdd673 100644 --- a/src/asteroids.rs +++ b/src/asteroids.rs @@ -17,7 +17,6 @@ pub struct Asteroid { rot: f32, omega: f32, pub alive: bool, - pub color: Color, } impl Asteroid { @@ -48,7 +47,6 @@ impl Asteroid { omega: gen_range(0.8, 3.5) * if gen_range(0., 1.) > 0.5 { -1. } else { 1. }, rot: 0., alive: true, - color: Color::new(1., 1., 1., 0.2), } } @@ -81,7 +79,7 @@ impl Asteroid { } } - pub fn draw(&self) { + pub fn draw(&self, color: Color) { draw_poly_lines( self.pos.x, self.pos.y, @@ -91,9 +89,9 @@ impl Asteroid { match self.size { AsteroidSize::Large => 2., AsteroidSize::Medium => 1.2, - AsteroidSize::Small => 0.8, + AsteroidSize::Small => 1., }, - self.color, + color, ); } } diff --git a/src/main.rs b/src/main.rs index 6b3498a..e85bef9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -63,23 +63,18 @@ async fn main() { let mut bias = false; let mut size = 100; let mut pop = Population::new(size as usize); + let mut x = 0.; + let mut xy = "".to_string(); + let mut l1: usize = 6; + let mut l2: usize = 6; + let mut l3: usize = 0; let ui_thick = 34.; + let nums = &[ + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", + ]; let skin = { - let boxed = 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.)); - let window_style = root_ui() .style_builder() .background(Image { @@ -90,7 +85,18 @@ async fn main() { .background_margin(RectOffset::new(0., 0., 0., 0.)) .color_inactive(WHITE) .build(); - let button_style = boxed + let 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) @@ -104,11 +110,51 @@ async fn main() { .text_color(WHITE) .font_size(24) .margin(RectOffset::new(5., 5., 4., 4.)) - .color_inactive(WHITE) + // .text_color_hovered(LIGHTGRAY) + // .text_color_clicked(WHITE) .build(); let group_style = root_ui() .style_builder() - .color(Color::new(0., 0., 0., 0.)) + .color(Color::new(1., 0., 0., 1.)) + .build(); + let editbox_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.)) + // .margin(RectOffset::new(10., 10., 8., 8.)) + .text_color(WHITE) + // .color_hovered(WHITE) + // .color_inactive(WHITE) + // .color(WHITE) + .build(); + let combobox_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.)) + // .margin(RectOffset::new(1., 1., 1., 1.)) + // .text_color_hovered(WHITE) + // .text_color(WHITE) + .color_hovered(WHITE) + .color_selected_hovered(WHITE) + .color_inactive(WHITE) + .color_clicked(WHITE) + .color(WHITE) .build(); Skin { @@ -116,13 +162,23 @@ async fn main() { button_style, label_style, group_style, - + editbox_style, + combobox_style, margin: 0., ..root_ui().default_skin() } }; - root_ui().push_skin(&skin); + let mut skin2 = skin.clone(); + skin2.label_style = root_ui() + .style_builder() + .text_color(WHITE) + .font_size(16) + // .margin(RectOffset::new(5., 5., 4., 0.)) + .text_color_hovered(LIGHTGRAY) + .text_color_clicked(WHITE) + .build(); + loop { clear_background(BLACK); set_camera(&gamecam); @@ -157,29 +213,29 @@ async fn main() { ); set_camera(&netcam); - pop.worlds[0].player.draw_brain( + pop.worlds[pop.track].player.draw_brain( screen_width() - WIDTH - 3. * th, (screen_height() - 3. * th) * 0.5, bias, ); set_camera(&statcam); - pop.worlds[0].draw_stats( + pop.worlds[pop.track].draw_stats( screen_width() - WIDTH - 3. * th, (screen_height() - 7. * th) * 0.5 - 2. * ui_thick, - ); - if is_mouse_button_pressed(MouseButton::Left) && mouse_position().0 < WIDTH + th { - let (x, y) = mouse_position(); - for i in 0..pop.worlds.len() { - if (pop.worlds[i].player.pos - vec2(x - th - WIDTH * 0.5, y - th - HEIGHT * 0.5)) - .length_squared() - < 256. - { - pop.worlds.swap(0, i); - pop.worlds[0].track(true); - pop.worlds[i].track(false); - break; + pop.worlds.iter().fold(1, |acc, w| { + acc + if w.fitness > pop.worlds[pop.track].fitness { + 1 + } else { + 0 } - } + }), + ); + if !pop.focus + && is_mouse_button_pressed(MouseButton::Left) + && mouse_position().0 < WIDTH + th + { + let (x, y) = mouse_position(); + pop.change_track(vec2(x - th - WIDTH * 0.5, y - th - HEIGHT * 0.5)); } let ui_width = screen_width() - WIDTH - 3. * th + 1.; @@ -189,6 +245,7 @@ async fn main() { vec2(WIDTH + 2. * th, th), vec2(ui_width, ui_height), |ui| { + ui.push_skin(&skin); widgets::Group::new(hash!(), Vec2::new(ui_width, ui_thick)) .position(Vec2::new(0., 0.)) .ui(ui, |ui| { @@ -205,7 +262,7 @@ async fn main() { ui.same_line(0.); if widgets::Button::new("Save Model").ui(ui) { if let Some(path) = save_file_dialog("Save Model", "model.json") { - pop.worlds[0].export_brain(&path); + pop.worlds[pop.track].export_brain(&path); } } ui.same_line(0.); @@ -234,8 +291,10 @@ async fn main() { .ui(ui, |ui| { ui.drag(hash!(), "", Some((1, 300)), &mut size); }); - ui.same_line(307.); - if widgets::Button::new("Debug").ui(ui) { + ui.same_line(279.); + if widgets::Button::new(if pop.debug { "Debug:ON " } else { "Debug:OFF" }) + .ui(ui) + { pop.debug = !pop.debug; }; ui.same_line(0.); @@ -244,7 +303,7 @@ async fn main() { bias = !bias; }; ui.same_line(0.); - if widgets::Button::new(if !pop.focus { "Show Best" } else { "Show All " }) + if widgets::Button::new(if !pop.focus { "Focus:OFF" } else { "Focus:ON " }) .ui(ui) { pop.focus = !pop.focus; @@ -254,6 +313,26 @@ async fn main() { pop = Population::new(size as usize); }; }); + ui.pop_skin(); + ui.push_skin(&skin2); + widgets::Group::new( + hash!(), + Vec2::new(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)) + .ui(ui, |ui| { + // ui.input_text(hash!(), "vec2(100., 100.)", &mut xy); + ui.label(None, "Hidden Layers Neuron"); + ui.label(None, "Config"); + ui.label(None, " "); + + ui.combo_box(hash!(), "Layer 1", nums, &mut l1); + ui.combo_box(hash!(), "Layer 2", nums, &mut l2); + ui.combo_box(hash!(), "Layer 3", nums, &mut l3); + ui.label(None, " "); + ui.label(None, "Mutation Rate"); + // ui.(hash!(), "", 0.0..0.2, &mut x); + }); }, ); next_frame().await; diff --git a/src/nn.rs b/src/nn.rs index f3e9b7e..6995f9d 100644 --- a/src/nn.rs +++ b/src/nn.rs @@ -60,7 +60,12 @@ impl NN { .weights .iter() .zip(b.weights.iter()) - .map(|(m1, m2)| m1.zip_map(m2, |ele1, ele2| if r::random() { ele1 } else { ele2 })) + .map(|(m1, m2)| { + m1.zip_map( + m2, + |ele1, ele2| if gen_range(0., 1.) < 0.5 { ele1 } else { ele2 }, + ) + }) .collect(), ..Default::default() } diff --git a/src/player.rs b/src/player.rs index cdbb7f0..b3880a9 100644 --- a/src/player.rs +++ b/src/player.rs @@ -20,7 +20,6 @@ pub struct Player { shot_interval: u8, pub brain: Option, alive: bool, - pub color: Option, pub lifespan: u32, pub shots: u32, } @@ -196,12 +195,7 @@ impl Player { // self.asteroid_data.clear(); } - pub fn draw(&self, debug: bool) { - let color = match self.color { - Some(c) => c, - // None => WHITE, - None => Color::new(1., 1., 1., 0.3), - }; + pub fn draw(&self, color: Color, debug: bool) { let p1 = self.pos + self.dir * 20.; let p2 = self.pos + self.dir.rotate(vec2(-18., -12.667)); let p3 = self.pos + self.dir.rotate(vec2(-18., 12.667)); @@ -218,12 +212,12 @@ impl Player { } if debug { if let Some(ast) = self.asteroid.as_ref() { - draw_circle_lines(ast.pos.x, ast.pos.y, ast.radius, 1., DARKBLUE); + draw_circle_lines(ast.pos.x, ast.pos.y, ast.radius, 1., RED); // let p = self.pos // + self.dir.rotate(Vec2::from_angle(self.asteroid_data[0].1)) // * self.asteroid_data[0].0 // * WIDTH; - draw_line(self.pos.x, self.pos.y, ast.pos.x, ast.pos.y, 1., DARKBLUE); + draw_line(self.pos.x, self.pos.y, ast.pos.x, ast.pos.y, 1., RED); } // Draw raycasts diff --git a/src/population.rs b/src/population.rs index 81cd710..3a5d879 100644 --- a/src/population.rs +++ b/src/population.rs @@ -9,6 +9,7 @@ pub struct Population { pub focus: bool, pub debug: bool, pub worlds: Vec, + pub track: usize, } impl Population { @@ -40,6 +41,20 @@ impl Population { } } + pub fn change_track(&mut self, pos: Vec2) { + for i in 0..self.worlds.len() { + if !self.worlds[i].over + && !self.worlds[i].track + && (self.worlds[i].player.pos - pos).length_squared() < 256. + { + self.worlds[self.track].track(false); + self.worlds[i].track(true); + self.track = i; + break; + } + } + } + pub fn draw(&self) { for world in self.worlds.iter().rev() { if self.focus { @@ -82,7 +97,6 @@ impl Population { let mut new_worlds = (0..std::cmp::max(1, self.size / 20)) .map(|i| World::simulate(Some(self.worlds[i].see_brain().to_owned()))) .collect::>(); - new_worlds[0].track(true); while new_worlds.len() < self.size { let rands = (gen_range(0., total), gen_range(0., total)); let mut sum = 0.; @@ -107,5 +121,7 @@ impl Population { new_worlds.push(World::simulate(Some(new_brain))); } self.worlds = new_worlds; + self.worlds[0].track(true); + self.track = 0; } } diff --git a/src/world.rs b/src/world.rs index 315fa93..a10e4ae 100644 --- a/src/world.rs +++ b/src/world.rs @@ -13,6 +13,7 @@ pub struct World { pub over: bool, pub fitness: f32, pub track: bool, + color: Color, } impl World { @@ -27,19 +28,18 @@ impl World { Asteroid::new(AsteroidSize::Large), Asteroid::new(AsteroidSize::Large), ], + color: Color::new(1., 1., 1., 0.4), ..Default::default() } } pub fn track(&mut self, track: bool) { - self.player.color = if track { Some(RED) } else { None }; - for asteroid in &mut self.asteroids { - asteroid.color = if track { - Color::new(1., 0., 0., 0.8) - } else { - Color::new(1., 1., 1., 0.2) - }; - } + self.track = track; + self.color = if track { + Color::new(0., 0.8, 0., 0.8) + } else { + Color::new(1., 1., 1., 0.4) + }; } pub fn see_brain(&self) -> &NN { @@ -112,9 +112,9 @@ impl World { } pub fn draw(&self, debug: bool) { - self.player.draw(debug); + self.player.draw(self.color, debug); for asteroid in &self.asteroids { - asteroid.draw(); + asteroid.draw(self.color); } draw_text( &format!("{:.2}", self.fitness), @@ -125,7 +125,7 @@ impl World { ); } - pub fn draw_stats(&self, width: f32, height: f32) { + pub fn draw_stats(&self, width: f32, height: f32, rank: usize) { draw_rectangle_lines(-width * 0.5, -height * 0.5, width, height, 2., WHITE); let scale = 2.5; @@ -197,5 +197,13 @@ impl World { 130., params, ); + let str = &format!("RANK #{}", rank); + let w = measure_text(str, None, 64, 0.5); + + draw_text_ex(str, -w.width * 0.5, -height * 0.35, { + let mut p = params.clone(); + p.font_size = 64; + p + }); } }