visuals
This commit is contained in:
parent
02df5694f9
commit
3ce1fdb957
|
@ -1 +1 @@
|
|||
{"config":[5,9,9,4],"weights":[[[-0.14426763,0.30192375,-0.33760154,0.56687576,0.5898287,-0.074536264,-0.6543682,-0.8446751,0.044597864,0.4060799,0.09555614,0.13340633,0.22922766,0.67137265,0.9608935,0.6129314,-0.24052018,-0.38112265,-0.5038841,-0.12603956,-0.4028914,0.18523669,0.07864928,0.06674278,0.2717425,0.6340071,0.61368537,0.8703921,-0.38861758,0.5550103,-0.26274413,0.5074116,-0.7821254,0.049322072,-0.2819178,-0.54028326,-0.4513356,-0.5652218,0.50929916,-0.42176604],8,5],[[-0.8103107,0.8446312,-0.40203577,0.54887617,-0.44233263,0.31166792,-0.33348525,0.40876722,0.26672268,-0.712453,-0.21693909,-0.35327882,-0.7854557,0.43809295,0.59911966,-0.071552694,0.3788359,-0.4907685,0.7868428,0.63808143,-0.50622714,0.08628023,-0.8824939,0.24896917,0.63522625,-0.50140214,0.9587381,0.5064759,0.040097475,0.24041378,-0.12401252,0.10650039,-0.8819831,0.29062068,-0.26787168,0.45351043,-0.2870677,-0.24404618,0.8434694,0.30426964,0.31458378,-0.8161984,-0.12195361,0.8177855,-0.57765794,0.89029014,0.75471187,0.5454526,-0.2778288,0.5250077,-0.71220773,0.58331454,0.368407,-1.0235562,-0.057651043,0.6541481,0.49730933,0.23280966,0.9288963,0.42811918,-0.45282865,0.22473057,0.9463216,0.5010747,-0.30762756,-0.5731837,0.8379146,0.06879502,-0.23158616,-0.6971844,0.4713143,0.1294421],8,9],[[0.45169508,-0.31192523,-0.74151075,-0.40177822,0.9622052,0.47277915,-0.76076436,0.00037801266,-0.36617398,0.89722514,0.89538515,0.99763775,1.3664851,-0.09313524,-0.5705385,0.059523106,-0.4970879,0.06191349,0.61592185,0.63810134,-0.97980994,-0.673075,0.025918722,0.5754194,1.2249401,-0.1614248,0.8438246,-0.6717344,0.83650386,-2.2065213,-0.051995337,0.19302869,-0.9978042,0.5303961,-1.4841839,0.118329406],4,9]],"activ_func":"ReLU","mut_rate":0.04}
|
||||
{"config":[6,9,9,4],"weights":[[[0.3488082,-0.09199099,-0.11929926,-1.0631673,-0.23543529,0.12705088,-1.0842022,-1.1801648,1.3452269,-0.105297334,0.7070266,-0.49821422,-0.9919794,-0.4586555,0.38327622,1.2620807,-0.8927275,0.72946376,0.36548716,0.3453985,0.24704376,1.1178607,-0.73745847,-0.36780706,0.5647091,-0.29108286,1.710524,1.0728852,-0.8066526,-0.28913066,0.14346941,-1.0912626,0.36901304,0.7923526,-0.51800287,-0.72875357,0.8539478,-1.473583,0.68293977,0.18473642,0.0003245327,-0.58371824,0.48150238,0.3494165,-0.23288698,-1.0439657,-0.26875693,0.5452296],8,6],[[-2.3292994,-0.26192483,-0.90176463,2.324304,-1.9353858,-0.14891693,-0.52935755,0.76884156,0.1082592,-0.9176799,0.6898619,0.7002196,0.19165382,-0.00026388586,-2.0727108,-0.43361717,0.4825783,0.5469626,1.5679779,1.6802235,0.5569048,0.2322176,-1.2066526,0.7200245,-0.54737276,-0.15166411,0.19801892,0.040810376,1.3895321,-0.08859847,-1.2233515,-0.063391574,0.10386248,-1.1793425,0.47050527,-1.7380185,-1.7678633,0.42901033,-0.017297065,0.4843002,-1.3651237,-0.24331652,0.2636839,0.7167474,-1.2047871,2.1309357,-1.3384317,2.6571567,0.044456493,-1.8444118,-0.52083886,0.32806322,0.088446766,-0.009452653,0.20716749,-0.911177,-0.74860054,0.16590308,0.46789008,0.9035914,0.64725244,-0.30468005,0.27064824,0.39474502,2.02378,-1.4614658,-0.84020156,0.69931465,-0.51446456,0.24423209,1.2651527,-0.45960972],8,9],[[-0.585348,0.5383882,-0.97360545,0.032165576,-0.049561385,0.24148509,-0.8100511,-0.6426556,1.059696,0.85932785,0.6353762,-0.9978614,1.9525132,-0.10112733,-0.5321224,0.443344,-0.37738746,-0.99622214,-1.3957877,0.6381588,-0.47502336,1.0980062,0.047556207,-0.008916257,-0.8662841,-0.45772696,1.6571641,0.9795985,0.098027825,-1.6333683,0.58037895,1.2487193,-1.0500598,-0.44345784,-2.4462621,0.5654464],4,9]],"activ_func":"ReLU","mut_rate":0.05}
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{HEIGHT, WIDTH};
|
||||
use macroquad::{prelude::*, rand::gen_range};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum AsteroidSize {
|
||||
Large,
|
||||
|
@ -22,9 +22,9 @@ pub struct Asteroid {
|
|||
impl Asteroid {
|
||||
pub fn new(size: AsteroidSize) -> Self {
|
||||
let (sides, radius) = match size {
|
||||
AsteroidSize::Large => (gen_range(6, 10), gen_range(40., 50.)),
|
||||
AsteroidSize::Medium => (gen_range(5, 6), gen_range(30., 40.)),
|
||||
AsteroidSize::Small => (gen_range(3, 5), 20.),
|
||||
AsteroidSize::Large => (gen_range(6, 10), gen_range(50., 65.)),
|
||||
AsteroidSize::Medium => (gen_range(5, 6), gen_range(35., 50.)),
|
||||
AsteroidSize::Small => (gen_range(3, 5), 25.),
|
||||
};
|
||||
let mut r = vec2(
|
||||
if gen_range(0., 1.) > 0.5 { -1. } else { 1. },
|
||||
|
@ -33,10 +33,7 @@ impl Asteroid {
|
|||
if gen_range(0., 1.) > 0.5 {
|
||||
r = vec2(r.y, r.x);
|
||||
}
|
||||
r *= vec2(
|
||||
screen_width() * 0.5 + radius,
|
||||
screen_height() * 0.5 + radius,
|
||||
);
|
||||
r *= vec2(WIDTH * 0.5 + radius, HEIGHT * 0.5 + radius);
|
||||
Self {
|
||||
pos: r,
|
||||
vel: 0.001 * -r
|
||||
|
@ -74,10 +71,10 @@ impl Asteroid {
|
|||
pub fn update(&mut self) {
|
||||
self.pos += self.vel;
|
||||
self.rot += self.omega;
|
||||
if self.pos.x.abs() > screen_width() * 0.5 + self.radius {
|
||||
if self.pos.x.abs() > WIDTH * 0.5 + self.radius {
|
||||
self.pos.x *= -1.;
|
||||
}
|
||||
if self.pos.y.abs() > screen_height() * 0.5 + self.radius {
|
||||
if self.pos.y.abs() > HEIGHT * 0.5 + self.radius {
|
||||
self.pos.y *= -1.;
|
||||
}
|
||||
}
|
||||
|
@ -94,6 +91,7 @@ impl Asteroid {
|
|||
AsteroidSize::Medium => 1.2,
|
||||
AsteroidSize::Small => 0.8,
|
||||
},
|
||||
// WHITE,
|
||||
Color::new(1., 1., 1., 0.4),
|
||||
);
|
||||
}
|
||||
|
|
66
src/main.rs
66
src/main.rs
|
@ -7,17 +7,52 @@ mod world;
|
|||
use macroquad::prelude::*;
|
||||
use population::Population;
|
||||
|
||||
#[macroquad::main("Camera")]
|
||||
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)]
|
||||
async fn main() {
|
||||
rand::srand(macroquad::miniquad::date::now() as _);
|
||||
let cam = Camera2D {
|
||||
let th = (screen_height() - HEIGHT) * 0.5;
|
||||
|
||||
let gamecam = Camera2D {
|
||||
zoom: vec2(2. / screen_width(), -2. / screen_height()),
|
||||
offset: vec2((2. * th + WIDTH) / screen_width() - 1., 0.),
|
||||
..Default::default()
|
||||
};
|
||||
set_camera(&cam);
|
||||
let maincam = Camera2D {
|
||||
zoom: vec2(2. / screen_width(), -2. / screen_height()),
|
||||
offset: vec2(
|
||||
(th + WIDTH) / screen_width(),
|
||||
-((th + HEIGHT) * 0.5) / screen_height(),
|
||||
),
|
||||
..Default::default()
|
||||
};
|
||||
// let mut cam = Camera2D::from_display_rect(Rect {
|
||||
// x: 0.,
|
||||
// y: 0.,
|
||||
// w: 1600.,
|
||||
// h: 1200.,
|
||||
// });
|
||||
// cam.offset = vec2(1., -1.);
|
||||
// // {
|
||||
// zoom: vec2(2. / 800., -2. / 600.),
|
||||
// // offset: vec2(-19. / 60., 0.),
|
||||
// ..Default::default()
|
||||
// };
|
||||
let mut pop = Population::new(100);
|
||||
let mut speedup = false;
|
||||
loop {
|
||||
// set_camera(&cam);
|
||||
clear_background(BLACK);
|
||||
if is_key_pressed(KeyCode::S) {
|
||||
speedup = !speedup;
|
||||
|
@ -30,6 +65,29 @@ async fn main() {
|
|||
pop.update();
|
||||
pop.draw();
|
||||
}
|
||||
next_frame().await
|
||||
draw_rectangle_lines(-WIDTH * 0.5, -HEIGHT * 0.5, WIDTH, HEIGHT, 2., WHITE);
|
||||
|
||||
set_camera(&maincam);
|
||||
// draw_circle(0., 0., 20., RED);
|
||||
pop.worlds[0].see_brain().draw(
|
||||
screen_width() - WIDTH - 3. * th,
|
||||
(screen_height() - 3. * th) * 0.5,
|
||||
);
|
||||
set_camera(&gamecam);
|
||||
|
||||
// set_camera(&maincam);
|
||||
// draw_texture_ex(
|
||||
// target.texture,
|
||||
// 0.,
|
||||
// 0.,
|
||||
// Color::new(1., 1., 1., 0.3),
|
||||
// DrawTextureParams {
|
||||
// flip_y: true,
|
||||
// ..Default::default()
|
||||
// },
|
||||
// );
|
||||
// set_camera(&cam);
|
||||
|
||||
next_frame().await;
|
||||
}
|
||||
}
|
||||
|
|
59
src/nn.rs
59
src/nn.rs
|
@ -1,4 +1,4 @@
|
|||
use macroquad::rand::gen_range;
|
||||
use macroquad::{prelude::*, rand::gen_range};
|
||||
use nalgebra::*;
|
||||
use r::Rng;
|
||||
use rand_distr::StandardNormal;
|
||||
|
@ -17,7 +17,7 @@ enum ActivationFunc {
|
|||
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
|
||||
pub struct NN {
|
||||
pub config: Vec<usize>,
|
||||
weights: Vec<DMatrix<f32>>,
|
||||
pub weights: Vec<DMatrix<f32>>,
|
||||
activ_func: ActivationFunc,
|
||||
mut_rate: f32,
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ impl NN {
|
|||
})
|
||||
.collect(),
|
||||
|
||||
mut_rate: 0.04,
|
||||
mut_rate: 0.05,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
@ -71,8 +71,8 @@ impl NN {
|
|||
for ele in weight {
|
||||
if gen_range(0., 1.) < self.mut_rate {
|
||||
// *ele += gen_range(-1., 1.);
|
||||
*ele = gen_range(-1., 1.);
|
||||
// *ele = r::thread_rng().sample::<f32, StandardNormal>(StandardNormal);
|
||||
// *ele = gen_range(-1., 1.);
|
||||
*ele = r::thread_rng().sample::<f32, StandardNormal>(StandardNormal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -95,6 +95,55 @@ impl NN {
|
|||
y.column(0).data.into_slice().to_vec()
|
||||
}
|
||||
|
||||
pub fn draw(&self, width: f32, height: f32) {
|
||||
draw_rectangle_lines(-width * 0.5, -height * 0.5, width, height, 2., WHITE);
|
||||
|
||||
let width = width * 0.8;
|
||||
let height = height * 0.8;
|
||||
let vspace = height / (self.config.iter().max().unwrap() - 1) as f32;
|
||||
let mut p1s: Vec<(f32, f32)> = Vec::new();
|
||||
let mut p2s: Vec<(f32, f32)> = Vec::new();
|
||||
for (i, layer) in self
|
||||
.config
|
||||
.iter()
|
||||
.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 {
|
||||
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)))
|
||||
{
|
||||
draw_line(
|
||||
p1.0,
|
||||
p1.1,
|
||||
p2.0,
|
||||
p2.1,
|
||||
1.,
|
||||
Color::new(1., 1., 1., (self.weights[i - 1].index((j, k))).abs()),
|
||||
);
|
||||
}
|
||||
for p in &p1s {
|
||||
draw_circle(p.0, p.1, 10., WHITE);
|
||||
draw_circle(p.0, p.1, 9., BLACK);
|
||||
}
|
||||
}
|
||||
for p in &p2s {
|
||||
draw_circle(p.0, p.1, 10., WHITE);
|
||||
draw_circle(p.0, p.1, 9., BLACK);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn export(&self) -> String {
|
||||
serde_json::to_string(self).unwrap()
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::{f32::consts::PI, f64::consts::TAU, iter};
|
|||
|
||||
use macroquad::{prelude::*, rand::gen_range};
|
||||
|
||||
use crate::{asteroids::Asteroid, nn::NN};
|
||||
use crate::{asteroids::Asteroid, nn::NN, HEIGHT, WIDTH};
|
||||
#[derive(Default)]
|
||||
pub struct Player {
|
||||
pub pos: Vec2,
|
||||
|
@ -51,7 +51,7 @@ impl Player {
|
|||
// );
|
||||
p.brain = Some(brain);
|
||||
} else {
|
||||
p.brain = Some(NN::new(vec![4, 8, 8, 4]));
|
||||
p.brain = Some(NN::new(vec![5, 8, 8, 4]));
|
||||
}
|
||||
p
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ impl Player {
|
|||
// To give more near asteroids data:
|
||||
|
||||
// self.asteroid_data.push((
|
||||
// ((asteroid.pos - self.pos).length() - asteroid.radius) / screen_width(),
|
||||
// ((asteroid.pos - self.pos).length() - asteroid.radius) / WIDTH,
|
||||
// self.dir.angle_between(asteroid.pos - self.pos),
|
||||
// (asteroid.vel - self.vel).length(),
|
||||
// ));
|
||||
|
@ -120,9 +120,10 @@ impl Player {
|
|||
let mut keys = vec![false, false, false, false];
|
||||
if let Some(ast) = self.asteroid.as_ref() {
|
||||
let inputs = vec![
|
||||
(ast.pos - self.pos).length() / screen_width(),
|
||||
(ast.pos - self.pos).length() / WIDTH,
|
||||
self.dir.angle_between(ast.pos - self.pos),
|
||||
(ast.vel - self.vel).length(),
|
||||
(ast.vel - self.vel).x / 11.,
|
||||
(ast.vel - self.vel).y / 11.,
|
||||
self.rot / TAU as f32,
|
||||
];
|
||||
|
||||
|
@ -174,19 +175,18 @@ impl Player {
|
|||
|
||||
self.vel += self.acc * self.dir - self.drag * self.vel.length() * self.vel;
|
||||
self.pos += self.vel;
|
||||
if self.pos.x.abs() > screen_width() * 0.5 + 10. {
|
||||
if self.pos.x.abs() > WIDTH * 0.5 + 10. {
|
||||
self.pos.x *= -1.;
|
||||
}
|
||||
if self.pos.y.abs() > screen_height() * 0.5 + 10. {
|
||||
if self.pos.y.abs() > HEIGHT * 0.5 + 10. {
|
||||
self.pos.y *= -1.;
|
||||
}
|
||||
|
||||
for bullet in &mut self.bullets {
|
||||
bullet.update();
|
||||
}
|
||||
self.bullets.retain(|b| {
|
||||
b.alive && b.pos.x.abs() * 2. < screen_width() && b.pos.y.abs() * 2. < screen_height()
|
||||
});
|
||||
self.bullets
|
||||
.retain(|b| b.alive && b.pos.x.abs() * 2. < WIDTH && b.pos.y.abs() * 2. < HEIGHT);
|
||||
if self.debug {
|
||||
self.draw();
|
||||
}
|
||||
|
@ -197,6 +197,7 @@ impl Player {
|
|||
pub fn draw(&self) {
|
||||
let color = match self.color {
|
||||
Some(c) => c,
|
||||
// None => WHITE,
|
||||
None => Color::new(1., 1., 1., 0.3),
|
||||
};
|
||||
let p1 = self.pos + self.dir * 20.;
|
||||
|
@ -219,7 +220,7 @@ impl Player {
|
|||
// let p = self.pos
|
||||
// + self.dir.rotate(Vec2::from_angle(self.asteroid_data[0].1))
|
||||
// * self.asteroid_data[0].0
|
||||
// * screen_width();
|
||||
// * WIDTH;
|
||||
draw_line(self.pos.x, self.pos.y, ast.pos.x, ast.pos.y, 1., GRAY);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use macroquad::{prelude::*, rand::gen_range};
|
||||
|
||||
use crate::{nn::NN, world::World};
|
||||
use crate::{nn::NN, world::World, HEIGHT, WIDTH};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Population {
|
||||
|
@ -34,6 +34,9 @@ impl Population {
|
|||
if is_key_pressed(KeyCode::Z) {
|
||||
self.best = !self.best;
|
||||
}
|
||||
if is_key_pressed(KeyCode::Space) {
|
||||
self.worlds[0].export_brain();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw(&self) {
|
||||
|
@ -48,11 +51,30 @@ impl Population {
|
|||
}
|
||||
draw_text(
|
||||
&format!("Gen: {}", self.gen),
|
||||
-150. + screen_width() * 0.5,
|
||||
30. - screen_height() * 0.5,
|
||||
-150. + WIDTH * 0.5,
|
||||
30. - HEIGHT * 0.5,
|
||||
32.,
|
||||
WHITE,
|
||||
);
|
||||
|
||||
// draw black background outside the screen
|
||||
let th = (screen_height() - HEIGHT) * 0.5;
|
||||
draw_rectangle(-WIDTH * 0.5, -screen_height() * 0.5, WIDTH, th, BLACK);
|
||||
draw_rectangle(-WIDTH * 0.5, screen_height() * 0.5 - th, WIDTH, th, BLACK);
|
||||
draw_rectangle(
|
||||
-WIDTH * 0.5 - th,
|
||||
-screen_height() * 0.5,
|
||||
th,
|
||||
screen_height(),
|
||||
BLACK,
|
||||
);
|
||||
draw_rectangle(
|
||||
WIDTH * 0.5,
|
||||
-screen_height() * 0.5,
|
||||
screen_width() - WIDTH,
|
||||
screen_height(),
|
||||
BLACK,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn next_gen(&mut self) {
|
||||
|
|
|
@ -38,7 +38,7 @@ impl World {
|
|||
self.player.brain.as_ref().unwrap()
|
||||
}
|
||||
|
||||
pub fn export_brian(&self) {
|
||||
pub fn export_brain(&self) {
|
||||
let json = self.player.brain.as_ref().unwrap().export();
|
||||
std::fs::create_dir_all("models").expect("Unable to create directory");
|
||||
std::fs::write("models/brain.json", json).expect("Unable to write file");
|
||||
|
|
Loading…
Reference in New Issue