This commit is contained in:
sparshg 2023-01-07 04:17:57 +05:30
parent 02df5694f9
commit 3ce1fdb957
7 changed files with 163 additions and 35 deletions

View File

@ -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}

View File

@ -1,5 +1,5 @@
use crate::{HEIGHT, WIDTH};
use macroquad::{prelude::*, rand::gen_range}; use macroquad::{prelude::*, rand::gen_range};
#[derive(Clone)] #[derive(Clone)]
pub enum AsteroidSize { pub enum AsteroidSize {
Large, Large,
@ -22,9 +22,9 @@ pub struct Asteroid {
impl Asteroid { impl Asteroid {
pub fn new(size: AsteroidSize) -> Self { pub fn new(size: AsteroidSize) -> Self {
let (sides, radius) = match size { let (sides, radius) = match size {
AsteroidSize::Large => (gen_range(6, 10), gen_range(40., 50.)), AsteroidSize::Large => (gen_range(6, 10), gen_range(50., 65.)),
AsteroidSize::Medium => (gen_range(5, 6), gen_range(30., 40.)), AsteroidSize::Medium => (gen_range(5, 6), gen_range(35., 50.)),
AsteroidSize::Small => (gen_range(3, 5), 20.), AsteroidSize::Small => (gen_range(3, 5), 25.),
}; };
let mut r = vec2( let mut r = vec2(
if gen_range(0., 1.) > 0.5 { -1. } else { 1. }, if gen_range(0., 1.) > 0.5 { -1. } else { 1. },
@ -33,10 +33,7 @@ impl Asteroid {
if gen_range(0., 1.) > 0.5 { if gen_range(0., 1.) > 0.5 {
r = vec2(r.y, r.x); r = vec2(r.y, r.x);
} }
r *= vec2( r *= vec2(WIDTH * 0.5 + radius, HEIGHT * 0.5 + radius);
screen_width() * 0.5 + radius,
screen_height() * 0.5 + radius,
);
Self { Self {
pos: r, pos: r,
vel: 0.001 * -r vel: 0.001 * -r
@ -74,10 +71,10 @@ impl Asteroid {
pub fn update(&mut self) { pub fn update(&mut self) {
self.pos += self.vel; self.pos += self.vel;
self.rot += self.omega; 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.; 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.; self.pos.y *= -1.;
} }
} }
@ -94,6 +91,7 @@ impl Asteroid {
AsteroidSize::Medium => 1.2, AsteroidSize::Medium => 1.2,
AsteroidSize::Small => 0.8, AsteroidSize::Small => 0.8,
}, },
// WHITE,
Color::new(1., 1., 1., 0.4), Color::new(1., 1., 1., 0.4),
); );
} }

View File

@ -7,17 +7,52 @@ mod world;
use macroquad::prelude::*; use macroquad::prelude::*;
use population::Population; 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() { async fn main() {
rand::srand(macroquad::miniquad::date::now() as _); 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()), zoom: vec2(2. / screen_width(), -2. / screen_height()),
offset: vec2((2. * th + WIDTH) / screen_width() - 1., 0.),
..Default::default() ..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 pop = Population::new(100);
let mut speedup = false; let mut speedup = false;
loop { loop {
// set_camera(&cam);
clear_background(BLACK); clear_background(BLACK);
if is_key_pressed(KeyCode::S) { if is_key_pressed(KeyCode::S) {
speedup = !speedup; speedup = !speedup;
@ -30,6 +65,29 @@ async fn main() {
pop.update(); pop.update();
pop.draw(); 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;
} }
} }

View File

@ -1,4 +1,4 @@
use macroquad::rand::gen_range; use macroquad::{prelude::*, rand::gen_range};
use nalgebra::*; use nalgebra::*;
use r::Rng; use r::Rng;
use rand_distr::StandardNormal; use rand_distr::StandardNormal;
@ -17,7 +17,7 @@ enum ActivationFunc {
#[derive(Clone, Debug, Default, Serialize, Deserialize)] #[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct NN { pub struct NN {
pub config: Vec<usize>, pub config: Vec<usize>,
weights: Vec<DMatrix<f32>>, pub weights: Vec<DMatrix<f32>>,
activ_func: ActivationFunc, activ_func: ActivationFunc,
mut_rate: f32, mut_rate: f32,
} }
@ -45,7 +45,7 @@ impl NN {
}) })
.collect(), .collect(),
mut_rate: 0.04, mut_rate: 0.05,
..Default::default() ..Default::default()
} }
} }
@ -71,8 +71,8 @@ impl NN {
for ele in weight { for ele in weight {
if gen_range(0., 1.) < self.mut_rate { if gen_range(0., 1.) < self.mut_rate {
// *ele += gen_range(-1., 1.); // *ele += gen_range(-1., 1.);
*ele = gen_range(-1., 1.); // *ele = gen_range(-1., 1.);
// *ele = r::thread_rng().sample::<f32, StandardNormal>(StandardNormal); *ele = r::thread_rng().sample::<f32, StandardNormal>(StandardNormal);
} }
} }
} }
@ -95,6 +95,55 @@ impl NN {
y.column(0).data.into_slice().to_vec() 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 { pub fn export(&self) -> String {
serde_json::to_string(self).unwrap() serde_json::to_string(self).unwrap()
} }

View File

@ -2,7 +2,7 @@ use std::{f32::consts::PI, f64::consts::TAU, iter};
use macroquad::{prelude::*, rand::gen_range}; use macroquad::{prelude::*, rand::gen_range};
use crate::{asteroids::Asteroid, nn::NN}; use crate::{asteroids::Asteroid, nn::NN, HEIGHT, WIDTH};
#[derive(Default)] #[derive(Default)]
pub struct Player { pub struct Player {
pub pos: Vec2, pub pos: Vec2,
@ -51,7 +51,7 @@ impl Player {
// ); // );
p.brain = Some(brain); p.brain = Some(brain);
} else { } else {
p.brain = Some(NN::new(vec![4, 8, 8, 4])); p.brain = Some(NN::new(vec![5, 8, 8, 4]));
} }
p p
} }
@ -60,7 +60,7 @@ impl Player {
// To give more near asteroids data: // To give more near asteroids data:
// self.asteroid_data.push(( // 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), // self.dir.angle_between(asteroid.pos - self.pos),
// (asteroid.vel - self.vel).length(), // (asteroid.vel - self.vel).length(),
// )); // ));
@ -120,9 +120,10 @@ impl Player {
let mut keys = vec![false, false, false, false]; let mut keys = vec![false, false, false, false];
if let Some(ast) = self.asteroid.as_ref() { if let Some(ast) = self.asteroid.as_ref() {
let inputs = vec![ let inputs = vec![
(ast.pos - self.pos).length() / screen_width(), (ast.pos - self.pos).length() / WIDTH,
self.dir.angle_between(ast.pos - self.pos), 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, 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.vel += self.acc * self.dir - self.drag * self.vel.length() * self.vel;
self.pos += 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.; 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.; self.pos.y *= -1.;
} }
for bullet in &mut self.bullets { for bullet in &mut self.bullets {
bullet.update(); bullet.update();
} }
self.bullets.retain(|b| { self.bullets
b.alive && b.pos.x.abs() * 2. < screen_width() && b.pos.y.abs() * 2. < screen_height() .retain(|b| b.alive && b.pos.x.abs() * 2. < WIDTH && b.pos.y.abs() * 2. < HEIGHT);
});
if self.debug { if self.debug {
self.draw(); self.draw();
} }
@ -197,6 +197,7 @@ impl Player {
pub fn draw(&self) { pub fn draw(&self) {
let color = match self.color { let color = match self.color {
Some(c) => c, Some(c) => c,
// None => WHITE,
None => Color::new(1., 1., 1., 0.3), None => Color::new(1., 1., 1., 0.3),
}; };
let p1 = self.pos + self.dir * 20.; let p1 = self.pos + self.dir * 20.;
@ -219,7 +220,7 @@ impl Player {
// let p = self.pos // let p = self.pos
// + self.dir.rotate(Vec2::from_angle(self.asteroid_data[0].1)) // + self.dir.rotate(Vec2::from_angle(self.asteroid_data[0].1))
// * self.asteroid_data[0].0 // * self.asteroid_data[0].0
// * screen_width(); // * WIDTH;
draw_line(self.pos.x, self.pos.y, ast.pos.x, ast.pos.y, 1., GRAY); draw_line(self.pos.x, self.pos.y, ast.pos.x, ast.pos.y, 1., GRAY);
} }

View File

@ -1,6 +1,6 @@
use macroquad::{prelude::*, rand::gen_range}; use macroquad::{prelude::*, rand::gen_range};
use crate::{nn::NN, world::World}; use crate::{nn::NN, world::World, HEIGHT, WIDTH};
#[derive(Default)] #[derive(Default)]
pub struct Population { pub struct Population {
@ -34,6 +34,9 @@ impl Population {
if is_key_pressed(KeyCode::Z) { if is_key_pressed(KeyCode::Z) {
self.best = !self.best; self.best = !self.best;
} }
if is_key_pressed(KeyCode::Space) {
self.worlds[0].export_brain();
}
} }
pub fn draw(&self) { pub fn draw(&self) {
@ -48,11 +51,30 @@ impl Population {
} }
draw_text( draw_text(
&format!("Gen: {}", self.gen), &format!("Gen: {}", self.gen),
-150. + screen_width() * 0.5, -150. + WIDTH * 0.5,
30. - screen_height() * 0.5, 30. - HEIGHT * 0.5,
32., 32.,
WHITE, 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) { pub fn next_gen(&mut self) {

View File

@ -38,7 +38,7 @@ impl World {
self.player.brain.as_ref().unwrap() 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(); let json = self.player.brain.as_ref().unwrap().export();
std::fs::create_dir_all("models").expect("Unable to create directory"); std::fs::create_dir_all("models").expect("Unable to create directory");
std::fs::write("models/brain.json", json).expect("Unable to write file"); std::fs::write("models/brain.json", json).expect("Unable to write file");