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