2023-01-13 07:49:45 +00:00
|
|
|
#![windows_subsystem = "windows"]
|
|
|
|
|
2022-10-08 13:15:07 +00:00
|
|
|
mod asteroids;
|
2022-10-09 18:14:22 +00:00
|
|
|
mod nn;
|
2022-10-08 13:15:07 +00:00
|
|
|
mod player;
|
2022-10-09 20:11:24 +00:00
|
|
|
mod population;
|
2022-10-08 15:27:05 +00:00
|
|
|
mod world;
|
2022-10-08 13:15:07 +00:00
|
|
|
|
2023-01-12 09:55:26 +00:00
|
|
|
use nn::{ActivationFunc, NN};
|
2023-01-08 20:09:10 +00:00
|
|
|
use tinyfiledialogs::*;
|
|
|
|
|
2023-01-07 21:59:59 +00:00
|
|
|
use macroquad::{
|
|
|
|
prelude::*,
|
|
|
|
ui::{hash, root_ui, widgets, Skin},
|
|
|
|
};
|
2023-01-12 18:53:40 +00:00
|
|
|
use population::{AutoSwitch, Population};
|
2023-01-08 20:09:10 +00:00
|
|
|
use world::World;
|
2022-10-08 13:15:07 +00:00
|
|
|
|
2023-01-06 22:47:57 +00:00
|
|
|
pub const WIDTH: f32 = 800.;
|
|
|
|
pub const HEIGHT: f32 = 780.;
|
|
|
|
|
|
|
|
fn window_conf() -> Conf {
|
|
|
|
Conf {
|
|
|
|
window_title: "Asteroids".to_string(),
|
|
|
|
// fullscreen: true,
|
|
|
|
window_width: 1400,
|
|
|
|
window_height: 800,
|
|
|
|
..Default::default()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#[macroquad::main(window_conf)]
|
2022-10-08 13:15:07 +00:00
|
|
|
async fn main() {
|
|
|
|
rand::srand(macroquad::miniquad::date::now() as _);
|
2023-01-12 21:37:52 +00:00
|
|
|
|
|
|
|
let pause = Texture2D::from_file_with_format(include_bytes!("../assets/pause.png"), None);
|
|
|
|
let play = Texture2D::from_file_with_format(include_bytes!("../assets/play.png"), None);
|
|
|
|
let fast = Texture2D::from_file_with_format(include_bytes!("../assets/fast.png"), None);
|
|
|
|
let slow = Texture2D::from_file_with_format(include_bytes!("../assets/slow.png"), None);
|
|
|
|
let restart = Texture2D::from_file_with_format(include_bytes!("../assets/restart.png"), None);
|
2023-01-06 22:47:57 +00:00
|
|
|
let th = (screen_height() - HEIGHT) * 0.5;
|
|
|
|
|
|
|
|
let gamecam = Camera2D {
|
2022-10-09 05:40:56 +00:00
|
|
|
zoom: vec2(2. / screen_width(), -2. / screen_height()),
|
2023-01-06 22:47:57 +00:00
|
|
|
offset: vec2((2. * th + WIDTH) / screen_width() - 1., 0.),
|
2022-10-08 13:15:07 +00:00
|
|
|
..Default::default()
|
|
|
|
};
|
2023-01-08 19:07:35 +00:00
|
|
|
let netcam = Camera2D {
|
2023-01-06 22:47:57 +00:00
|
|
|
zoom: vec2(2. / screen_width(), -2. / screen_height()),
|
|
|
|
offset: vec2(
|
|
|
|
(th + WIDTH) / screen_width(),
|
|
|
|
-((th + HEIGHT) * 0.5) / screen_height(),
|
|
|
|
),
|
|
|
|
..Default::default()
|
|
|
|
};
|
2023-01-08 19:07:35 +00:00
|
|
|
let statcam = Camera2D {
|
|
|
|
zoom: vec2(2. / screen_width(), -2. / screen_height()),
|
|
|
|
offset: vec2(
|
|
|
|
(th + WIDTH) / screen_width(),
|
|
|
|
((th + HEIGHT) * 0.5) / screen_height(),
|
|
|
|
),
|
|
|
|
..Default::default()
|
|
|
|
};
|
|
|
|
|
2023-01-08 20:40:34 +00:00
|
|
|
let mut speedup = 1;
|
2023-01-07 21:59:59 +00:00
|
|
|
let mut paused = false;
|
2023-01-08 19:07:35 +00:00
|
|
|
let mut bias = false;
|
2023-01-12 20:02:58 +00:00
|
|
|
let mut human = false;
|
2023-01-11 21:31:03 +00:00
|
|
|
let mut size: u32 = 100;
|
2023-01-12 20:02:58 +00:00
|
|
|
let mut world: World = World::new(None, None, None);
|
2023-01-12 09:55:26 +00:00
|
|
|
|
2023-01-11 21:31:03 +00:00
|
|
|
let mut hlayers: Vec<usize> = vec![6, 6, 0];
|
|
|
|
let mut prev_hlayers = hlayers.clone();
|
2023-01-12 09:55:26 +00:00
|
|
|
|
2023-01-11 21:31:03 +00:00
|
|
|
let mut mut_rate = 0.05;
|
|
|
|
let mut prev_mut_rate = 0.05;
|
2023-01-12 09:55:26 +00:00
|
|
|
|
2023-01-11 21:31:03 +00:00
|
|
|
let mut activ: usize = 0;
|
2023-01-12 09:55:26 +00:00
|
|
|
let mut prev_activ: usize = 0;
|
|
|
|
let activs = [
|
|
|
|
ActivationFunc::ReLU,
|
|
|
|
ActivationFunc::Sigmoid,
|
|
|
|
ActivationFunc::Tanh,
|
|
|
|
];
|
2023-01-12 20:02:58 +00:00
|
|
|
let mut auto_switch = Some(AutoSwitch::BestAlive);
|
2023-01-12 09:55:26 +00:00
|
|
|
|
2023-01-12 18:53:40 +00:00
|
|
|
let mut pop = Population::new(
|
|
|
|
size as usize,
|
|
|
|
auto_switch,
|
|
|
|
hlayers.clone(),
|
|
|
|
mut_rate,
|
|
|
|
activs[activ],
|
|
|
|
);
|
2023-01-08 19:07:35 +00:00
|
|
|
|
|
|
|
let ui_thick = 34.;
|
2023-01-11 18:56:03 +00:00
|
|
|
let nums = &[
|
|
|
|
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16",
|
|
|
|
];
|
2023-01-07 21:59:59 +00:00
|
|
|
|
|
|
|
let skin = {
|
|
|
|
let window_style = root_ui()
|
|
|
|
.style_builder()
|
|
|
|
.background(Image {
|
|
|
|
width: 1,
|
|
|
|
height: 1,
|
|
|
|
bytes: vec![0; 4],
|
|
|
|
})
|
|
|
|
.background_margin(RectOffset::new(0., 0., 0., 0.))
|
2023-01-08 19:07:35 +00:00
|
|
|
.color_inactive(WHITE)
|
2023-01-07 21:59:59 +00:00
|
|
|
.build();
|
2023-01-11 18:56:03 +00:00
|
|
|
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.))
|
2023-01-07 21:59:59 +00:00
|
|
|
.color_hovered(RED)
|
|
|
|
.color_clicked(BLUE)
|
|
|
|
.text_color(WHITE)
|
|
|
|
.text_color_hovered(WHITE)
|
|
|
|
.text_color_clicked(WHITE)
|
|
|
|
.margin(RectOffset::new(10., 10., 8., 8.))
|
2023-01-08 19:07:35 +00:00
|
|
|
.color_inactive(WHITE)
|
2023-01-07 21:59:59 +00:00
|
|
|
.build();
|
|
|
|
let label_style = root_ui()
|
|
|
|
.style_builder()
|
|
|
|
.text_color(WHITE)
|
|
|
|
.font_size(24)
|
|
|
|
.margin(RectOffset::new(5., 5., 4., 4.))
|
2023-01-11 18:56:03 +00:00
|
|
|
// .text_color_hovered(LIGHTGRAY)
|
|
|
|
// .text_color_clicked(WHITE)
|
2023-01-08 19:07:35 +00:00
|
|
|
.build();
|
|
|
|
let group_style = root_ui()
|
|
|
|
.style_builder()
|
2023-01-11 21:31:03 +00:00
|
|
|
.color(Color::new(1., 0., 0., 0.))
|
2023-01-11 18:56:03 +00:00
|
|
|
.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.))
|
|
|
|
.text_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.))
|
|
|
|
.color_hovered(WHITE)
|
|
|
|
.color_selected_hovered(WHITE)
|
|
|
|
.color_inactive(WHITE)
|
|
|
|
.color_clicked(WHITE)
|
|
|
|
.color(WHITE)
|
2023-01-07 21:59:59 +00:00
|
|
|
.build();
|
|
|
|
|
|
|
|
Skin {
|
|
|
|
window_style,
|
|
|
|
button_style,
|
|
|
|
label_style,
|
2023-01-08 19:07:35 +00:00
|
|
|
group_style,
|
2023-01-11 18:56:03 +00:00
|
|
|
editbox_style,
|
|
|
|
combobox_style,
|
2023-01-07 21:59:59 +00:00
|
|
|
margin: 0.,
|
|
|
|
..root_ui().default_skin()
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-01-11 18:56:03 +00:00
|
|
|
let mut skin2 = skin.clone();
|
|
|
|
skin2.label_style = root_ui()
|
|
|
|
.style_builder()
|
|
|
|
.text_color(WHITE)
|
|
|
|
.font_size(16)
|
|
|
|
.text_color_hovered(LIGHTGRAY)
|
|
|
|
.text_color_clicked(WHITE)
|
|
|
|
.build();
|
2023-01-11 21:31:03 +00:00
|
|
|
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.))
|
2023-01-12 18:53:40 +00:00
|
|
|
.color_hovered(GREEN)
|
|
|
|
.color_clicked(GREEN)
|
2023-01-11 21:31:03 +00:00
|
|
|
.text_color(WHITE)
|
|
|
|
.text_color_hovered(WHITE)
|
2023-01-12 18:53:40 +00:00
|
|
|
.text_color_clicked(GREEN)
|
2023-01-11 21:31:03 +00:00
|
|
|
.margin(RectOffset::new(4., 4., 2., 2.))
|
|
|
|
.color_inactive(WHITE)
|
|
|
|
.build();
|
2023-01-11 18:56:03 +00:00
|
|
|
|
2023-01-12 18:53:40 +00:00
|
|
|
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();
|
|
|
|
|
2023-01-11 21:31:03 +00:00
|
|
|
root_ui().push_skin(&skin);
|
2022-10-08 13:15:07 +00:00
|
|
|
loop {
|
2022-10-10 10:13:06 +00:00
|
|
|
clear_background(BLACK);
|
2023-01-08 19:07:35 +00:00
|
|
|
set_camera(&gamecam);
|
2023-01-08 20:40:34 +00:00
|
|
|
if !paused {
|
|
|
|
for _ in 0..speedup {
|
2023-01-12 20:02:58 +00:00
|
|
|
if !human {
|
|
|
|
pop.update()
|
|
|
|
} else if !world.over {
|
|
|
|
world.update()
|
|
|
|
};
|
2023-01-07 21:59:59 +00:00
|
|
|
}
|
2022-10-10 19:43:05 +00:00
|
|
|
}
|
2023-01-12 20:02:58 +00:00
|
|
|
if human {
|
|
|
|
world.draw(pop.debug);
|
|
|
|
pop.draw_borders();
|
|
|
|
} else {
|
|
|
|
pop.draw();
|
|
|
|
}
|
2023-01-06 22:47:57 +00:00
|
|
|
draw_rectangle_lines(-WIDTH * 0.5, -HEIGHT * 0.5, WIDTH, HEIGHT, 2., WHITE);
|
2023-01-07 21:59:59 +00:00
|
|
|
draw_rectangle_lines(
|
|
|
|
WIDTH * 0.5 + th,
|
|
|
|
-HEIGHT * 0.5,
|
|
|
|
screen_width() - WIDTH - 3. * th,
|
2023-01-08 19:07:35 +00:00
|
|
|
ui_thick,
|
2023-01-07 21:59:59 +00:00
|
|
|
2.,
|
|
|
|
WHITE,
|
|
|
|
);
|
|
|
|
draw_rectangle_lines(
|
|
|
|
WIDTH * 0.5 + th,
|
2023-01-08 19:07:35 +00:00
|
|
|
-HEIGHT * 0.5 + (screen_height() - 3. * th) * 0.5 - ui_thick,
|
2023-01-07 21:59:59 +00:00
|
|
|
screen_width() - WIDTH - 3. * th,
|
2023-01-08 19:07:35 +00:00
|
|
|
ui_thick,
|
2023-01-07 21:59:59 +00:00
|
|
|
2.,
|
|
|
|
WHITE,
|
|
|
|
);
|
2023-01-06 22:47:57 +00:00
|
|
|
|
2023-01-08 19:07:35 +00:00
|
|
|
set_camera(&netcam);
|
2023-01-11 18:56:03 +00:00
|
|
|
pop.worlds[pop.track].player.draw_brain(
|
2023-01-06 22:47:57 +00:00
|
|
|
screen_width() - WIDTH - 3. * th,
|
|
|
|
(screen_height() - 3. * th) * 0.5,
|
2023-01-08 19:07:35 +00:00
|
|
|
bias,
|
|
|
|
);
|
|
|
|
set_camera(&statcam);
|
2023-01-12 20:02:58 +00:00
|
|
|
let w = if human {
|
|
|
|
&world
|
|
|
|
} else {
|
|
|
|
&pop.worlds[pop.track]
|
|
|
|
};
|
|
|
|
w.draw_stats(
|
2023-01-08 19:07:35 +00:00
|
|
|
screen_width() - WIDTH - 3. * th,
|
|
|
|
(screen_height() - 7. * th) * 0.5 - 2. * ui_thick,
|
2023-01-11 18:56:03 +00:00
|
|
|
pop.worlds.iter().fold(1, |acc, w| {
|
|
|
|
acc + if w.fitness > pop.worlds[pop.track].fitness {
|
|
|
|
1
|
|
|
|
} else {
|
|
|
|
0
|
|
|
|
}
|
|
|
|
}),
|
2023-01-06 22:47:57 +00:00
|
|
|
);
|
2023-01-11 18:56:03 +00:00
|
|
|
if !pop.focus
|
|
|
|
&& is_mouse_button_pressed(MouseButton::Left)
|
|
|
|
&& mouse_position().0 < WIDTH + th
|
|
|
|
{
|
2023-01-09 19:25:18 +00:00
|
|
|
let (x, y) = mouse_position();
|
2023-01-11 18:56:03 +00:00
|
|
|
pop.change_track(vec2(x - th - WIDTH * 0.5, y - th - HEIGHT * 0.5));
|
2023-01-09 19:25:18 +00:00
|
|
|
}
|
2023-01-07 21:59:59 +00:00
|
|
|
|
2023-01-08 19:07:35 +00:00
|
|
|
let ui_width = screen_width() - WIDTH - 3. * th + 1.;
|
|
|
|
let ui_height = (screen_height() - 3. * th) * 0.5;
|
2023-01-07 21:59:59 +00:00
|
|
|
root_ui().window(
|
|
|
|
hash!(),
|
|
|
|
vec2(WIDTH + 2. * th, th),
|
2023-01-08 19:07:35 +00:00
|
|
|
vec2(ui_width, ui_height),
|
2023-01-07 21:59:59 +00:00
|
|
|
|ui| {
|
2023-01-11 21:31:03 +00:00
|
|
|
widgets::Group::new(hash!(), vec2(ui_width, ui_thick))
|
|
|
|
.position(vec2(0., 0.))
|
2023-01-08 19:07:35 +00:00
|
|
|
.ui(ui, |ui| {
|
|
|
|
ui.label(None, &format!("Generation: {}", pop.gen));
|
2023-01-12 09:55:26 +00:00
|
|
|
ui.push_skin(&skin2);
|
|
|
|
ui.label(vec2(200., 8.), &format!("{: >4}x", speedup));
|
|
|
|
ui.pop_skin();
|
2023-01-08 20:40:34 +00:00
|
|
|
ui.same_line(242.);
|
2023-01-08 20:09:10 +00:00
|
|
|
if widgets::Button::new("Load Model").ui(ui) {
|
2023-01-08 20:40:34 +00:00
|
|
|
if let Some(path) = open_file_dialog("Load Model", "model.json", None) {
|
2023-01-08 20:09:10 +00:00
|
|
|
let brain = NN::import(&path);
|
|
|
|
size = 1;
|
2023-01-11 21:31:03 +00:00
|
|
|
hlayers = brain
|
|
|
|
.config
|
|
|
|
.iter()
|
|
|
|
.take(brain.config.len() - 1)
|
|
|
|
.skip(1)
|
|
|
|
.map(|x| x - 1)
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
hlayers.resize(3, 0);
|
|
|
|
mut_rate = brain.mut_rate;
|
2023-01-12 09:55:26 +00:00
|
|
|
activ = activs.iter().position(|&x| x == brain.activ_func).unwrap();
|
|
|
|
|
|
|
|
prev_hlayers = hlayers.clone();
|
|
|
|
prev_mut_rate = mut_rate;
|
|
|
|
prev_activ = activ;
|
|
|
|
|
|
|
|
pop = Population::new(
|
|
|
|
size as usize,
|
2023-01-12 18:53:40 +00:00
|
|
|
auto_switch,
|
2023-01-12 09:55:26 +00:00
|
|
|
hlayers.clone(),
|
|
|
|
mut_rate,
|
|
|
|
activs[activ],
|
|
|
|
);
|
2023-01-11 21:31:03 +00:00
|
|
|
pop.worlds[0] = World::simulate(brain);
|
2023-01-08 20:09:10 +00:00
|
|
|
}
|
|
|
|
}
|
2023-01-08 19:07:35 +00:00
|
|
|
ui.same_line(0.);
|
2023-01-08 20:09:10 +00:00
|
|
|
if widgets::Button::new("Save Model").ui(ui) {
|
2023-01-08 20:40:34 +00:00
|
|
|
if let Some(path) = save_file_dialog("Save Model", "model.json") {
|
2023-01-11 18:56:03 +00:00
|
|
|
pop.worlds[pop.track].export_brain(&path);
|
2023-01-08 20:09:10 +00:00
|
|
|
}
|
|
|
|
}
|
2023-01-08 19:07:35 +00:00
|
|
|
ui.same_line(0.);
|
2023-01-14 10:44:05 +00:00
|
|
|
if widgets::Button::new(slow).ui(ui) || is_key_pressed(KeyCode::Z) {
|
2023-01-08 20:40:34 +00:00
|
|
|
speedup = std::cmp::max(speedup / 10, 1);
|
|
|
|
};
|
|
|
|
ui.same_line(0.);
|
2023-01-14 10:44:05 +00:00
|
|
|
if widgets::Button::new("1x").ui(ui) || is_key_pressed(KeyCode::X) {
|
2023-01-08 20:40:34 +00:00
|
|
|
speedup = 1;
|
|
|
|
};
|
|
|
|
ui.same_line(0.);
|
2023-01-14 10:44:05 +00:00
|
|
|
if widgets::Button::new(fast).ui(ui) || is_key_pressed(KeyCode::C) {
|
2023-01-08 20:40:34 +00:00
|
|
|
speedup = std::cmp::min(speedup * 10, 1000);
|
2023-01-08 19:07:35 +00:00
|
|
|
};
|
|
|
|
ui.same_line(0.);
|
2023-01-14 10:44:05 +00:00
|
|
|
if widgets::Button::new(if paused { play } else { pause }).ui(ui)
|
|
|
|
|| is_key_pressed(KeyCode::P)
|
|
|
|
{
|
2023-01-08 19:07:35 +00:00
|
|
|
paused = !paused;
|
|
|
|
};
|
|
|
|
});
|
2023-01-11 21:31:03 +00:00
|
|
|
widgets::Group::new(hash!(), vec2(ui_width, ui_thick))
|
|
|
|
.position(vec2(0., ui_height - ui_thick))
|
2023-01-08 19:07:35 +00:00
|
|
|
.ui(ui, |ui| {
|
2023-01-11 21:31:03 +00:00
|
|
|
ui.label(Some(vec2(0., 2.)), "Population:");
|
|
|
|
widgets::Group::new(hash!(), vec2(200., ui_thick))
|
|
|
|
.position(vec2(80., 0.))
|
2023-01-08 19:07:35 +00:00
|
|
|
.ui(ui, |ui| {
|
2023-01-09 19:25:18 +00:00
|
|
|
ui.drag(hash!(), "", Some((1, 300)), &mut size);
|
2023-01-08 19:07:35 +00:00
|
|
|
});
|
2023-01-11 21:31:03 +00:00
|
|
|
ui.push_skin(&skin2);
|
|
|
|
ui.label(Some(vec2(230., ui_thick * 0.5 - 7.)), "«Drag»");
|
|
|
|
ui.pop_skin();
|
2023-01-11 18:56:03 +00:00
|
|
|
ui.same_line(279.);
|
|
|
|
if widgets::Button::new(if pop.debug { "Debug:ON " } else { "Debug:OFF" })
|
|
|
|
.ui(ui)
|
2023-01-14 10:44:05 +00:00
|
|
|
|| is_key_pressed(KeyCode::D)
|
2023-01-11 18:56:03 +00:00
|
|
|
{
|
2023-01-09 19:25:18 +00:00
|
|
|
pop.debug = !pop.debug;
|
|
|
|
};
|
2023-01-08 19:26:00 +00:00
|
|
|
ui.same_line(0.);
|
2023-01-08 19:07:35 +00:00
|
|
|
if widgets::Button::new(if bias { "Hide Bias" } else { "Show Bias" }).ui(ui)
|
2023-01-14 10:44:05 +00:00
|
|
|
|| is_key_pressed(KeyCode::B)
|
2023-01-08 19:07:35 +00:00
|
|
|
{
|
|
|
|
bias = !bias;
|
|
|
|
};
|
|
|
|
ui.same_line(0.);
|
2023-01-11 18:56:03 +00:00
|
|
|
if widgets::Button::new(if !pop.focus { "Focus:OFF" } else { "Focus:ON " })
|
2023-01-08 19:07:35 +00:00
|
|
|
.ui(ui)
|
2023-01-14 10:44:05 +00:00
|
|
|
|| is_key_pressed(KeyCode::F)
|
2023-01-08 19:07:35 +00:00
|
|
|
{
|
2023-01-09 19:25:18 +00:00
|
|
|
pop.focus = !pop.focus;
|
2023-01-08 19:07:35 +00:00
|
|
|
};
|
|
|
|
ui.same_line(0.);
|
2023-01-14 10:44:05 +00:00
|
|
|
if widgets::Button::new(restart).ui(ui) || is_key_pressed(KeyCode::R) {
|
2023-01-12 20:02:58 +00:00
|
|
|
if human {
|
|
|
|
world = World::new(None, None, None);
|
|
|
|
} else {
|
|
|
|
pop = Population::new(
|
|
|
|
size as usize,
|
|
|
|
auto_switch,
|
|
|
|
hlayers.clone(),
|
|
|
|
mut_rate,
|
|
|
|
activs[activ],
|
|
|
|
);
|
|
|
|
}
|
2023-01-08 19:07:35 +00:00
|
|
|
};
|
|
|
|
});
|
2023-01-11 18:56:03 +00:00
|
|
|
ui.push_skin(&skin2);
|
|
|
|
widgets::Group::new(
|
|
|
|
hash!(),
|
2023-01-12 20:02:58 +00:00
|
|
|
vec2(ui_width * 0.2, ui_height * 0.85 - 2. * th - 2. * ui_thick),
|
2023-01-11 18:56:03 +00:00
|
|
|
)
|
2023-01-12 20:02:58 +00:00
|
|
|
.position(vec2(ui_width * 0.82, ui_height * 0.15 + ui_thick + th))
|
2023-01-12 18:53:40 +00:00
|
|
|
.ui(ui, |ui| {
|
|
|
|
ui.label(None, "Track Ship:");
|
2023-01-12 20:02:58 +00:00
|
|
|
ui.label(None, "(or click a");
|
|
|
|
ui.label(None, "ship in game)");
|
2023-01-12 18:53:40 +00:00
|
|
|
|
|
|
|
if ui.button(None, "Best Alive") {
|
|
|
|
pop.track_best(false);
|
|
|
|
}
|
|
|
|
if ui.button(None, "Current #1") {
|
|
|
|
pop.track_best(true);
|
2023-01-12 20:02:58 +00:00
|
|
|
auto_switch = Some(AutoSwitch::Best);
|
|
|
|
pop.auto_switch = auto_switch;
|
2023-01-12 18:53:40 +00:00
|
|
|
}
|
|
|
|
if ui.button(None, "LastGen #1") {
|
|
|
|
pop.track_prev_best();
|
2023-01-12 20:02:58 +00:00
|
|
|
auto_switch = None;
|
|
|
|
pop.auto_switch = auto_switch;
|
2023-01-12 18:53:40 +00:00
|
|
|
}
|
|
|
|
ui.label(None, " ");
|
|
|
|
ui.label(None, "Auto Switch");
|
|
|
|
ui.label(None, "When Dead to:");
|
|
|
|
|
2023-01-12 20:02:58 +00:00
|
|
|
if auto_switch == Some(AutoSwitch::BestAlive) {
|
2023-01-12 18:53:40 +00:00
|
|
|
ui.push_skin(&skin3);
|
2023-01-12 20:02:58 +00:00
|
|
|
ui.button(None, "Best Alive");
|
2023-01-12 18:53:40 +00:00
|
|
|
ui.pop_skin();
|
|
|
|
} else {
|
2023-01-12 20:02:58 +00:00
|
|
|
if ui.button(None, "Best Alive") {
|
|
|
|
auto_switch = Some(AutoSwitch::BestAlive);
|
2023-01-12 18:53:40 +00:00
|
|
|
pop.auto_switch = auto_switch;
|
|
|
|
}
|
|
|
|
}
|
2023-01-12 20:02:58 +00:00
|
|
|
if auto_switch == Some(AutoSwitch::Best) {
|
2023-01-12 18:53:40 +00:00
|
|
|
ui.push_skin(&skin3);
|
2023-01-12 20:02:58 +00:00
|
|
|
ui.button(None, "Current #1");
|
2023-01-12 18:53:40 +00:00
|
|
|
ui.pop_skin();
|
|
|
|
} else {
|
2023-01-12 20:02:58 +00:00
|
|
|
if ui.button(None, "Current #1") {
|
|
|
|
auto_switch = Some(AutoSwitch::Best);
|
2023-01-12 18:53:40 +00:00
|
|
|
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!(),
|
2023-01-12 20:02:58 +00:00
|
|
|
vec2(ui_width * 0.2, ui_height * 0.85 - 2. * th - 2. * ui_thick),
|
2023-01-12 18:53:40 +00:00
|
|
|
)
|
2023-01-12 20:02:58 +00:00
|
|
|
.position(vec2(ui_width * 0.6 - th, ui_height * 0.15 + ui_thick + th))
|
2023-01-11 18:56:03 +00:00
|
|
|
.ui(ui, |ui| {
|
2023-01-12 20:02:58 +00:00
|
|
|
ui.label(None, " ");
|
|
|
|
ui.push_skin(&skin);
|
|
|
|
if ui.button(
|
|
|
|
None,
|
|
|
|
if human {
|
|
|
|
" Train AI "
|
|
|
|
} else {
|
|
|
|
"Play As Human"
|
|
|
|
},
|
|
|
|
) {
|
|
|
|
human = !human;
|
|
|
|
if human {
|
|
|
|
world = World::new(None, None, None);
|
|
|
|
} else {
|
|
|
|
pop = Population::new(
|
|
|
|
size as usize,
|
|
|
|
auto_switch,
|
|
|
|
hlayers.clone(),
|
|
|
|
mut_rate,
|
|
|
|
activs[activ],
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ui.pop_skin();
|
|
|
|
ui.label(None, "Mutation Rate");
|
|
|
|
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, "Activation Func");
|
|
|
|
ui.combo_box(hash!(), "«Select»", &["ReLU", "Sigm", "Tanh"], &mut activ);
|
|
|
|
if prev_activ != activ {
|
|
|
|
pop.change_activ(activs[activ]);
|
|
|
|
prev_activ = activ;
|
|
|
|
}
|
|
|
|
ui.label(None, " ");
|
2023-01-11 21:31:03 +00:00
|
|
|
ui.label(None, "Hidden Layers");
|
|
|
|
ui.label(None, "Neurons Config");
|
2023-01-11 18:56:03 +00:00
|
|
|
|
2023-01-11 21:31:03 +00:00
|
|
|
ui.combo_box(hash!(), "Layer 1", nums, &mut hlayers[0]);
|
|
|
|
ui.combo_box(hash!(), "Layer 2", nums, &mut hlayers[1]);
|
|
|
|
ui.combo_box(hash!(), "Layer 3", nums, &mut hlayers[2]);
|
|
|
|
if prev_hlayers != hlayers {
|
2023-01-12 09:55:26 +00:00
|
|
|
pop = Population::new(
|
|
|
|
size as usize,
|
2023-01-12 18:53:40 +00:00
|
|
|
auto_switch,
|
2023-01-12 09:55:26 +00:00
|
|
|
hlayers.clone(),
|
|
|
|
mut_rate,
|
|
|
|
activs[activ],
|
|
|
|
);
|
2023-01-11 21:31:03 +00:00
|
|
|
prev_hlayers = hlayers.clone();
|
|
|
|
}
|
2023-01-11 18:56:03 +00:00
|
|
|
});
|
2023-01-11 21:31:03 +00:00
|
|
|
ui.pop_skin();
|
2023-01-07 21:59:59 +00:00
|
|
|
},
|
|
|
|
);
|
2023-01-06 22:47:57 +00:00
|
|
|
next_frame().await;
|
2022-10-08 13:15:07 +00:00
|
|
|
}
|
|
|
|
}
|