ui bars
This commit is contained in:
parent
3ce1fdb957
commit
7dea9e0406
Binary file not shown.
After Width: | Height: | Size: 398 B |
143
src/main.rs
143
src/main.rs
|
@ -4,7 +4,12 @@ mod player;
|
|||
mod population;
|
||||
mod world;
|
||||
|
||||
use macroquad::prelude::*;
|
||||
use std::borrow::BorrowMut;
|
||||
|
||||
use macroquad::{
|
||||
prelude::*,
|
||||
ui::{hash, root_ui, widgets, Skin},
|
||||
};
|
||||
use population::Population;
|
||||
|
||||
pub const WIDTH: f32 = 800.;
|
||||
|
@ -22,6 +27,10 @@ fn window_conf() -> Conf {
|
|||
#[macroquad::main(window_conf)]
|
||||
async fn main() {
|
||||
rand::srand(macroquad::miniquad::date::now() as _);
|
||||
let pause = load_texture("pause.png").await.unwrap();
|
||||
let play = load_texture("play.png").await.unwrap();
|
||||
let fast = load_texture("fast.png").await.unwrap();
|
||||
let restart = load_texture("restart.png").await.unwrap();
|
||||
let th = (screen_height() - HEIGHT) * 0.5;
|
||||
|
||||
let gamecam = Camera2D {
|
||||
|
@ -51,29 +60,151 @@ async fn main() {
|
|||
// };
|
||||
let mut pop = Population::new(100);
|
||||
let mut speedup = false;
|
||||
let mut paused = false;
|
||||
let mut checkbox = false;
|
||||
let mut combobox = 0;
|
||||
let mut text = String::new();
|
||||
let mut number = 0.0;
|
||||
|
||||
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 {
|
||||
width: 1,
|
||||
height: 1,
|
||||
bytes: vec![0; 4],
|
||||
})
|
||||
.background_margin(RectOffset::new(0., 0., 0., 0.))
|
||||
.build();
|
||||
let button_style = boxed
|
||||
.color_hovered(RED)
|
||||
.color_clicked(BLUE)
|
||||
.text_color(WHITE)
|
||||
.text_color_hovered(WHITE)
|
||||
.text_color_clicked(WHITE)
|
||||
.margin(RectOffset::new(10., 10., 8., 8.))
|
||||
.build();
|
||||
let label_style = root_ui()
|
||||
.style_builder()
|
||||
.text_color(WHITE)
|
||||
.font_size(24)
|
||||
.margin(RectOffset::new(5., 5., 4., 4.))
|
||||
.build();
|
||||
|
||||
Skin {
|
||||
window_style,
|
||||
button_style,
|
||||
label_style,
|
||||
margin: 0.,
|
||||
..root_ui().default_skin()
|
||||
}
|
||||
};
|
||||
|
||||
root_ui().push_skin(&skin);
|
||||
loop {
|
||||
// set_camera(&cam);
|
||||
clear_background(BLACK);
|
||||
if is_key_pressed(KeyCode::S) {
|
||||
speedup = !speedup;
|
||||
}
|
||||
if speedup {
|
||||
for _ in 0..1000 {
|
||||
pop.update();
|
||||
if !paused {
|
||||
for _ in 0..1000 {
|
||||
pop.update();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pop.update();
|
||||
if !paused {
|
||||
pop.update();
|
||||
}
|
||||
pop.draw();
|
||||
}
|
||||
draw_rectangle_lines(-WIDTH * 0.5, -HEIGHT * 0.5, WIDTH, HEIGHT, 2., WHITE);
|
||||
draw_rectangle_lines(
|
||||
WIDTH * 0.5 + th,
|
||||
-HEIGHT * 0.5,
|
||||
screen_width() - WIDTH - 3. * th,
|
||||
34.,
|
||||
2.,
|
||||
WHITE,
|
||||
);
|
||||
draw_rectangle_lines(
|
||||
WIDTH * 0.5 + th,
|
||||
-HEIGHT * 0.5 + (screen_height() - 3. * th) * 0.5 - 34.,
|
||||
screen_width() - WIDTH - 3. * th,
|
||||
34.,
|
||||
2.,
|
||||
WHITE,
|
||||
);
|
||||
|
||||
set_camera(&maincam);
|
||||
// draw_circle(0., 0., 20., RED);
|
||||
pop.worlds[0].see_brain().draw(
|
||||
pop.worlds[0].player.draw_brain(
|
||||
screen_width() - WIDTH - 3. * th,
|
||||
(screen_height() - 3. * th) * 0.5,
|
||||
);
|
||||
|
||||
set_camera(&gamecam);
|
||||
root_ui().window(
|
||||
hash!(),
|
||||
vec2(WIDTH + 2. * th, th),
|
||||
vec2(screen_width() - WIDTH - 3. * th + 1., 34.),
|
||||
|ui| {
|
||||
ui.label(None, &format!("Generation: {}", pop.gen));
|
||||
ui.same_line(278.);
|
||||
widgets::Button::new("Load Model").ui(ui);
|
||||
ui.same_line(0.);
|
||||
widgets::Button::new("Save Model").ui(ui);
|
||||
ui.same_line(0.);
|
||||
if widgets::Button::new(fast).ui(ui) {
|
||||
speedup = !speedup;
|
||||
};
|
||||
ui.same_line(0.);
|
||||
if widgets::Button::new(restart).ui(ui) {
|
||||
pop = Population::new(100);
|
||||
};
|
||||
ui.same_line(0.);
|
||||
if widgets::Button::new(if paused { play } else { pause }).ui(ui) {
|
||||
paused = !paused;
|
||||
};
|
||||
},
|
||||
);
|
||||
root_ui().window(
|
||||
hash!(),
|
||||
vec2(WIDTH + 2. * th, (screen_height() - th) * 0.5 - 34.),
|
||||
vec2(screen_width() - WIDTH - 3. * th + 1., 34.),
|
||||
|ui| {
|
||||
ui.label(None, &format!("Generation: {}", pop.gen));
|
||||
ui.same_line(278.);
|
||||
widgets::Button::new("Load Model").ui(ui);
|
||||
ui.same_line(0.);
|
||||
widgets::Button::new("Save Model").ui(ui);
|
||||
ui.same_line(0.);
|
||||
if widgets::Button::new(fast).ui(ui) {
|
||||
speedup = !speedup;
|
||||
};
|
||||
ui.same_line(0.);
|
||||
if widgets::Button::new(restart).ui(ui) {
|
||||
pop = Population::new(100);
|
||||
};
|
||||
ui.same_line(0.);
|
||||
if widgets::Button::new(if paused { play } else { pause }).ui(ui) {
|
||||
paused = !paused;
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
// set_camera(&maincam);
|
||||
// draw_texture_ex(
|
||||
|
|
40
src/nn.rs
40
src/nn.rs
|
@ -78,10 +78,10 @@ impl NN {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn feed_forward(&self, inputs: Vec<f32>) -> Vec<f32> {
|
||||
pub fn feed_forward(&self, inputs: &Vec<f32>) -> Vec<f32> {
|
||||
// println!("inputs: {:?}", inputs);
|
||||
let mut y = DMatrix::from_vec(inputs.len(), 1, inputs);
|
||||
for i in 0..self.config.len() - 1 {
|
||||
let mut y = DMatrix::from_vec(inputs.len(), 1, inputs.to_vec());
|
||||
for i in 0..self.config.len() - 2 {
|
||||
y = (&self.weights[i] * y.insert_row(self.config[i] - 1, 1.)).map(|x| {
|
||||
match self.activ_func {
|
||||
ActivationFunc::ReLU => x.max(0.),
|
||||
|
@ -89,13 +89,14 @@ impl NN {
|
|||
ActivationFunc::Tanh => x.tanh(),
|
||||
}
|
||||
});
|
||||
// println!("w{}: {}", i, self.weights[i]);
|
||||
// println!("y: {}", y);
|
||||
}
|
||||
let i = self.config.len() - 2;
|
||||
y = (&self.weights[i] * y.insert_row(self.config[i] - 1, 1.))
|
||||
.map(|x| 1. / (1. + (-x).exp()));
|
||||
y.column(0).data.into_slice().to_vec()
|
||||
}
|
||||
|
||||
pub fn draw(&self, width: f32, height: f32) {
|
||||
pub fn draw(&self, width: f32, height: f32, inputs: &Vec<f32>) {
|
||||
draw_rectangle_lines(-width * 0.5, -height * 0.5, width, height, 2., WHITE);
|
||||
|
||||
let width = width * 0.8;
|
||||
|
@ -106,31 +107,34 @@ impl NN {
|
|||
for (i, layer) in self
|
||||
.config
|
||||
.iter()
|
||||
.take(self.config.len() - 1)
|
||||
.map(|x| x - 1)
|
||||
.chain(self.config.last().map(|&x| x))
|
||||
// .take(self.config.len() - 1)
|
||||
// .map(|x| x - 1)
|
||||
// .chain(self.config.last().map(|&x| x))
|
||||
.enumerate()
|
||||
{
|
||||
p1s = p2s;
|
||||
p2s = Vec::new();
|
||||
for neuron in 0..layer {
|
||||
for neuron in 0..*layer {
|
||||
p2s.push((
|
||||
i as f32 * width / (self.config.len() - 1) as f32 - width * 0.5,
|
||||
neuron as f32 * vspace - (vspace * (layer - 1) as f32) * 0.5,
|
||||
));
|
||||
}
|
||||
for (k, j, p1, p2) in p1s
|
||||
.iter()
|
||||
.enumerate()
|
||||
.flat_map(|(k, x)| p2s.iter().enumerate().map(move |(j, y)| (k, j, *x, *y)))
|
||||
{
|
||||
for (k, j, p1, p2) in p1s.iter().enumerate().flat_map(|(k, x)| {
|
||||
p2s.iter()
|
||||
.take(p2s.len() - if i == self.config.len() - 1 { 0 } else { 1 })
|
||||
.enumerate()
|
||||
.map(move |(j, y)| (k, j, *x, *y))
|
||||
}) {
|
||||
let weight = *self.weights[i - 1].index((j, k));
|
||||
let c = if weight < 0. { 0. } else { 1. };
|
||||
draw_line(
|
||||
p1.0,
|
||||
p1.1,
|
||||
p2.0,
|
||||
p2.1,
|
||||
1.,
|
||||
Color::new(1., 1., 1., (self.weights[i - 1].index((j, k))).abs()),
|
||||
Color::new(1., c, c, weight.abs()),
|
||||
);
|
||||
}
|
||||
for p in &p1s {
|
||||
|
@ -142,6 +146,10 @@ impl NN {
|
|||
draw_circle(p.0, p.1, 10., WHITE);
|
||||
draw_circle(p.0, p.1, 9., BLACK);
|
||||
}
|
||||
draw_rectangle(width * 0.45, height * 0.45, 10., 10., RED);
|
||||
draw_text("-ve", width * 0.45 + 20., height * 0.45 + 10., 20., WHITE);
|
||||
draw_rectangle(width * 0.45, height * 0.45 + 20., 10., 10., WHITE);
|
||||
draw_text("+ve", width * 0.45 + 20., height * 0.45 + 30., 20., WHITE);
|
||||
}
|
||||
|
||||
pub fn export(&self) -> String {
|
||||
|
|
|
@ -6,14 +6,16 @@ use crate::{asteroids::Asteroid, nn::NN, HEIGHT, WIDTH};
|
|||
#[derive(Default)]
|
||||
pub struct Player {
|
||||
pub pos: Vec2,
|
||||
pub vel: Vec2,
|
||||
vel: Vec2,
|
||||
acc: f32,
|
||||
pub dir: Vec2,
|
||||
rot: f32,
|
||||
drag: f32,
|
||||
bullets: Vec<Bullet>,
|
||||
asteroid: Option<Asteroid>,
|
||||
asteroid_data: Vec<(f32, f32, f32)>,
|
||||
inputs: Vec<f32>,
|
||||
outputs: Vec<bool>,
|
||||
// asteroid_data: Vec<(f32, f32, f32)>,
|
||||
last_shot: u8,
|
||||
shot_interval: u8,
|
||||
pub brain: Option<NN>,
|
||||
|
@ -36,6 +38,7 @@ impl Player {
|
|||
alive: true,
|
||||
debug: false,
|
||||
shots: 4,
|
||||
outputs: vec![false; 4],
|
||||
|
||||
..Default::default()
|
||||
}
|
||||
|
@ -51,7 +54,7 @@ impl Player {
|
|||
// );
|
||||
p.brain = Some(brain);
|
||||
} else {
|
||||
p.brain = Some(NN::new(vec![5, 8, 8, 4]));
|
||||
p.brain = Some(NN::new(vec![5, 6, 6, 4]));
|
||||
}
|
||||
p
|
||||
}
|
||||
|
@ -117,9 +120,9 @@ impl Player {
|
|||
self.lifespan += 1;
|
||||
self.last_shot += 1;
|
||||
self.acc = 0.;
|
||||
let mut keys = vec![false, false, false, false];
|
||||
self.outputs = vec![false; 4];
|
||||
if let Some(ast) = self.asteroid.as_ref() {
|
||||
let inputs = vec![
|
||||
self.inputs = vec![
|
||||
(ast.pos - self.pos).length() / WIDTH,
|
||||
self.dir.angle_between(ast.pos - self.pos),
|
||||
(ast.vel - self.vel).x / 11.,
|
||||
|
@ -140,21 +143,25 @@ impl Player {
|
|||
// );
|
||||
|
||||
if let Some(brain) = &self.brain {
|
||||
keys = brain.feed_forward(inputs).iter().map(|&x| x > 0.).collect();
|
||||
self.outputs = brain
|
||||
.feed_forward(&self.inputs)
|
||||
.iter()
|
||||
.map(|&x| x > 0.85)
|
||||
.collect();
|
||||
}
|
||||
}
|
||||
if is_key_down(KeyCode::Right) && self.debug || keys[0] {
|
||||
if is_key_down(KeyCode::Right) && self.debug || self.outputs[0] {
|
||||
self.rot = (self.rot + 0.1 + TAU as f32) % TAU as f32;
|
||||
self.dir = vec2(self.rot.cos(), self.rot.sin());
|
||||
}
|
||||
if is_key_down(KeyCode::Left) && self.debug || keys[1] {
|
||||
if is_key_down(KeyCode::Left) && self.debug || self.outputs[1] {
|
||||
self.rot = (self.rot - 0.1 + TAU as f32) % TAU as f32;
|
||||
self.dir = vec2(self.rot.cos(), self.rot.sin());
|
||||
}
|
||||
if is_key_down(KeyCode::Up) && self.debug || keys[2] {
|
||||
if is_key_down(KeyCode::Up) && self.debug || self.outputs[2] {
|
||||
self.acc = 0.14;
|
||||
}
|
||||
if is_key_down(KeyCode::Space) && self.debug || keys[3] {
|
||||
if is_key_down(KeyCode::Space) && self.debug || self.outputs[3] {
|
||||
if self.last_shot > self.shot_interval {
|
||||
self.last_shot = 0;
|
||||
self.shots += 1;
|
||||
|
@ -243,6 +250,12 @@ impl Player {
|
|||
bullet.draw();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw_brain(&self, width: f32, height: f32) {
|
||||
if let Some(brain) = &self.brain {
|
||||
brain.draw(width, height, &self.inputs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Bullet {
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::{nn::NN, world::World, HEIGHT, WIDTH};
|
|||
#[derive(Default)]
|
||||
pub struct Population {
|
||||
size: usize,
|
||||
gen: i32,
|
||||
pub gen: i32,
|
||||
best: bool,
|
||||
pub worlds: Vec<World>,
|
||||
}
|
||||
|
@ -49,13 +49,13 @@ impl Population {
|
|||
world.draw();
|
||||
}
|
||||
}
|
||||
draw_text(
|
||||
&format!("Gen: {}", self.gen),
|
||||
-150. + WIDTH * 0.5,
|
||||
30. - HEIGHT * 0.5,
|
||||
32.,
|
||||
WHITE,
|
||||
);
|
||||
// draw_text(
|
||||
// &format!("Gen: {}", self.gen),
|
||||
// -150. + WIDTH * 0.5,
|
||||
// 30. - HEIGHT * 0.5,
|
||||
// 32.,
|
||||
// WHITE,
|
||||
// );
|
||||
|
||||
// draw black background outside the screen
|
||||
let th = (screen_height() - HEIGHT) * 0.5;
|
||||
|
|
Loading…
Reference in New Issue