tracking ui

This commit is contained in:
sparshg 2023-01-13 00:23:40 +05:30
parent b7ad50da37
commit 0796eda239
3 changed files with 141 additions and 12 deletions

View File

@ -11,7 +11,7 @@ use macroquad::{
prelude::*, prelude::*,
ui::{hash, root_ui, widgets, Skin}, ui::{hash, root_ui, widgets, Skin},
}; };
use population::Population; use population::{AutoSwitch, Population};
use world::World; use world::World;
pub const WIDTH: f32 = 800.; pub const WIDTH: f32 = 800.;
@ -76,8 +76,15 @@ async fn main() {
ActivationFunc::Sigmoid, ActivationFunc::Sigmoid,
ActivationFunc::Tanh, ActivationFunc::Tanh,
]; ];
let mut auto_switch = Some(AutoSwitch::Best);
let mut pop = Population::new(size as usize, hlayers.clone(), mut_rate, activs[activ]); let mut pop = Population::new(
size as usize,
auto_switch,
hlayers.clone(),
mut_rate,
activs[activ],
);
let ui_thick = 34.; let ui_thick = 34.;
let nums = &[ let nums = &[
@ -192,15 +199,36 @@ async fn main() {
], ],
}) })
.background_margin(RectOffset::new(1., 1., 1., 1.)) .background_margin(RectOffset::new(1., 1., 1., 1.))
.color_hovered(RED) .color_hovered(GREEN)
.color_clicked(BLUE) .color_clicked(GREEN)
.text_color(WHITE) .text_color(WHITE)
.text_color_hovered(WHITE) .text_color_hovered(WHITE)
.text_color_clicked(WHITE) .text_color_clicked(GREEN)
.margin(RectOffset::new(4., 4., 2., 2.)) .margin(RectOffset::new(4., 4., 2., 2.))
.color_inactive(WHITE) .color_inactive(WHITE)
.build(); .build();
let mut skin3 = skin2.clone();
skin3.button_style = root_ui()
.style_builder()
.background(Image {
width: 3,
height: 3,
bytes: vec![
0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 0, 0, 255, 0,
255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255,
],
})
.background_margin(RectOffset::new(1., 1., 1., 1.))
.color_hovered(GREEN)
.color_clicked(GREEN)
.text_color(GREEN)
.text_color_hovered(GREEN)
.text_color_clicked(GREEN)
.margin(RectOffset::new(4., 4., 2., 2.))
.color_inactive(GREEN)
.build();
root_ui().push_skin(&skin); root_ui().push_skin(&skin);
loop { loop {
clear_background(BLACK); clear_background(BLACK);
@ -297,6 +325,7 @@ async fn main() {
pop = Population::new( pop = Population::new(
size as usize, size as usize,
auto_switch,
hlayers.clone(), hlayers.clone(),
mut_rate, mut_rate,
activs[activ], activs[activ],
@ -360,6 +389,7 @@ async fn main() {
if widgets::Button::new(restart).ui(ui) { if widgets::Button::new(restart).ui(ui) {
pop = Population::new( pop = Population::new(
size as usize, size as usize,
auto_switch,
hlayers.clone(), hlayers.clone(),
mut_rate, mut_rate,
activs[activ], activs[activ],
@ -371,9 +401,60 @@ async fn main() {
hash!(), hash!(),
vec2(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(ui_width * 0.8 - th, ui_height * 0.2 + ui_thick + th)) .position(vec2(ui_width * 0.6, ui_height * 0.23 + ui_thick + th))
.ui(ui, |ui| {
ui.label(None, "Track Ship:");
if ui.button(None, "Best Alive") {
pop.track_best(false);
}
if ui.button(None, "Current #1") {
pop.track_best(true);
}
if ui.button(None, "LastGen #1") {
pop.track_prev_best();
}
ui.label(None, " ");
ui.label(None, "Auto Switch");
ui.label(None, "When Dead to:");
if auto_switch == Some(AutoSwitch::Best) {
ui.push_skin(&skin3);
ui.button(None, "Current #1");
ui.pop_skin();
} else {
if ui.button(None, "Current #1") {
auto_switch = Some(AutoSwitch::Best);
pop.auto_switch = auto_switch;
}
}
if auto_switch == Some(AutoSwitch::BestAlive) {
ui.push_skin(&skin3);
ui.button(None, "Best Alive");
ui.pop_skin();
} else {
if ui.button(None, "Best Alive") {
auto_switch = Some(AutoSwitch::BestAlive);
pop.auto_switch = auto_switch;
}
}
if auto_switch.is_none() {
ui.push_skin(&skin3);
ui.button(None, "Do Nothing");
ui.pop_skin();
} else {
if ui.button(None, "Do Nothing") {
auto_switch = None;
pop.auto_switch = auto_switch;
}
}
});
widgets::Group::new(
hash!(),
vec2(ui_width * 0.2, ui_height * 0.8 - 2. * th - 2. * ui_thick),
)
.position(vec2(ui_width * 0.8 - th, ui_height * 0.22 + ui_thick + th))
.ui(ui, |ui| { .ui(ui, |ui| {
// ui.input_text(hash!(), "vec2(100., 100.)", &mut xy);
ui.label(None, "Hidden Layers"); ui.label(None, "Hidden Layers");
ui.label(None, "Neurons Config"); ui.label(None, "Neurons Config");
@ -383,6 +464,7 @@ async fn main() {
if prev_hlayers != hlayers { if prev_hlayers != hlayers {
pop = Population::new( pop = Population::new(
size as usize, size as usize,
auto_switch,
hlayers.clone(), hlayers.clone(),
mut_rate, mut_rate,
activs[activ], activs[activ],

View File

@ -6,6 +6,12 @@ use crate::{
HEIGHT, WIDTH, HEIGHT, WIDTH,
}; };
#[derive(Clone, Copy, PartialEq)]
pub enum AutoSwitch {
Best,
BestAlive,
}
#[derive(Default)] #[derive(Default)]
pub struct Population { pub struct Population {
size: usize, size: usize,
@ -15,16 +21,24 @@ pub struct Population {
pub worlds: Vec<World>, pub worlds: Vec<World>,
pub track: usize, pub track: usize,
pub hlayers: Vec<usize>, pub hlayers: Vec<usize>,
pub auto_switch: Option<AutoSwitch>,
} }
impl Population { impl Population {
pub fn new(size: usize, hlayers: Vec<usize>, mut_rate: f32, activ: ActivationFunc) -> Self { pub fn new(
size: usize,
auto_switch: Option<AutoSwitch>,
hlayers: Vec<usize>,
mut_rate: f32,
activ: ActivationFunc,
) -> Self {
Self { Self {
size, size,
hlayers: hlayers.clone(), hlayers: hlayers.clone(),
worlds: (0..size) worlds: (0..size)
.map(|_| World::new(Some(hlayers.clone()), Some(mut_rate), Some(activ))) .map(|_| World::new(Some(hlayers.clone()), Some(mut_rate), Some(activ)))
.collect(), .collect(),
auto_switch,
..Default::default() ..Default::default()
} }
} }
@ -37,6 +51,14 @@ impl Population {
world.update(); world.update();
} }
} }
if self.worlds[self.track].over {
if let Some(auto_switch) = self.auto_switch {
match auto_switch {
AutoSwitch::Best => self.track_best(true),
AutoSwitch::BestAlive => self.track_best(false),
}
}
}
if !alive { if !alive {
self.gen += 1; self.gen += 1;
self.next_gen(); self.next_gen();
@ -62,6 +84,25 @@ impl Population {
} }
} }
} }
pub fn track_best(&mut self, can_be_dead: bool) {
self.worlds[self.track].track(false);
let i = self
.worlds
.iter()
.enumerate()
.filter(|(_, w)| !w.over || can_be_dead)
.max_by(|(_, a), (_, b)| a.fitness.total_cmp(&b.fitness))
.map(|(i, _)| i);
if let Some(i) = i {
self.worlds[i].track(true);
self.track = i;
}
}
pub fn track_prev_best(&mut self) {
self.worlds[self.track].track(false);
self.worlds[0].track(true);
self.track = 0;
}
pub fn change_mut(&mut self, mut_rate: f32) { pub fn change_mut(&mut self, mut_rate: f32) {
for world in &mut self.worlds { for world in &mut self.worlds {

View File

@ -181,7 +181,7 @@ impl World {
draw_text_ex( draw_text_ex(
if self.over { "DEAD" } else { "ALIVE" }, if self.over { "DEAD" } else { "ALIVE" },
-width * 0.5 + 20., -width * 0.5 + 20.,
70., 55.,
{ {
let mut p = params.clone(); let mut p = params.clone();
p.color = if self.over { RED } else { GREEN }; p.color = if self.over { RED } else { GREEN };
@ -191,19 +191,25 @@ impl World {
draw_text_ex( draw_text_ex(
&format!("Hits: {}", self.score), &format!("Hits: {}", self.score),
-width * 0.5 + 20., -width * 0.5 + 20.,
90., 75.,
params, params,
); );
draw_text_ex( draw_text_ex(
&format!("Fired: {}", self.player.shots), &format!("Fired: {}", self.player.shots),
-width * 0.5 + 20., -width * 0.5 + 20.,
110., 95.,
params, params,
); );
draw_text_ex( draw_text_ex(
&format!("Fitness: {:.2}", self.fitness), &format!("Fitness: {:.2}", self.fitness),
-width * 0.5 + 20., -width * 0.5 + 20.,
130., 115.,
params,
);
draw_text_ex(
&format!("Lifetime: {:.2}", self.player.lifespan as f32 / 60.),
-width * 0.5 + 20.,
135.,
params, params,
); );
let str = &format!("RANK #{}", rank); let str = &format!("RANK #{}", rank);