This commit is contained in:
sparshg 2022-10-11 01:13:05 +05:30
parent 1f0b6e06e0
commit 666c9a8b8e
5 changed files with 48 additions and 21 deletions

View File

@ -89,7 +89,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.5),
); );
} }
} }

View File

@ -16,11 +16,21 @@ async fn main() {
..Default::default() ..Default::default()
}; };
set_camera(&cam); set_camera(&cam);
let mut pop = Population::new(5); let mut pop = Population::new(100);
let mut speedup = false;
loop { loop {
clear_background(BLACK); clear_background(BLACK);
pop.update(); if is_key_pressed(KeyCode::S) {
pop.draw(); speedup = !speedup;
}
if speedup {
for _ in 0..100 {
pop.update();
}
} else {
pop.update();
pop.draw();
}
next_frame().await next_frame().await
} }
// let mut world = World::new(); // let mut world = World::new();

View File

@ -14,11 +14,12 @@ pub struct Player {
last_shot: f32, last_shot: f32,
shot_interval: f32, shot_interval: f32,
pub brain: Option<NN>, pub brain: Option<NN>,
search_radius: f32, asteroids_data: Vec<f32>,
proximity_asteroids: Vec<f32>,
max_asteroids: usize, max_asteroids: usize,
debug: bool, debug: bool,
alive: bool, alive: bool,
pub lifespan: u32,
pub shots: u32,
} }
impl Player { impl Player {
@ -30,7 +31,6 @@ impl Player {
// Change scaling when passing inputs if this is changed // Change scaling when passing inputs if this is changed
drag: 0.001, drag: 0.001,
shot_interval: 0.3, shot_interval: 0.3,
search_radius: 300.,
alive: true, alive: true,
debug: false, debug: false,
..Default::default() ..Default::default()
@ -50,8 +50,11 @@ impl Player {
} }
pub fn check_player_collision(&mut self, asteroid: &mut Asteroid) -> bool { pub fn check_player_collision(&mut self, asteroid: &mut Asteroid) -> bool {
self.proximity_asteroids self.asteroids_data.extend([
.extend([asteroid.pos.x, asteroid.pos.y, asteroid.radius]); asteroid.pos.x / screen_width() + 0.5,
asteroid.pos.y / screen_height() + 0.5,
asteroid.radius / 50.,
]);
if asteroid.check_collision(self.pos, 8.) { if asteroid.check_collision(self.pos, 8.) {
self.alive = false; self.alive = false;
return true; return true;
@ -71,10 +74,11 @@ impl Player {
} }
pub fn update(&mut self) { pub fn update(&mut self) {
self.lifespan += 1;
let mut mag = 0.; let mut mag = 0.;
let mut keys = vec![false, false, false, false]; let mut keys = vec![false, false, false, false];
self.proximity_asteroids.resize(self.max_asteroids, 0.); self.asteroids_data.resize(self.max_asteroids, 0.);
let mut inputs = vec![ let mut inputs = vec![
self.pos.x / screen_width() + 0.5, self.pos.x / screen_width() + 0.5,
self.pos.y / screen_height() + 0.5, self.pos.y / screen_height() + 0.5,
@ -82,7 +86,7 @@ impl Player {
self.vel.y / 11., self.vel.y / 11.,
self.rot / TAU as f32, self.rot / TAU as f32,
]; ];
inputs.append(self.proximity_asteroids.as_mut()); inputs.append(self.asteroids_data.as_mut());
if let Some(brain) = &self.brain { if let Some(brain) = &self.brain {
keys = brain keys = brain
.feed_forward(inputs) .feed_forward(inputs)
@ -105,6 +109,7 @@ impl Player {
if is_key_down(KeyCode::Space) || keys[3] { if is_key_down(KeyCode::Space) || keys[3] {
if self.shot_interval + self.last_shot < get_time() as f32 { if self.shot_interval + self.last_shot < get_time() as f32 {
self.last_shot = get_time() as f32; self.last_shot = get_time() as f32;
self.shots += 1;
self.bullets.push(Bullet { self.bullets.push(Bullet {
pos: self.pos + self.dir.rotate(vec2(20., 0.)), pos: self.pos + self.dir.rotate(vec2(20., 0.)),
vel: self.dir.rotate(vec2(8.5, 0.)) + self.vel, vel: self.dir.rotate(vec2(8.5, 0.)) + self.vel,
@ -151,7 +156,7 @@ impl Player {
} }
if self.debug { if self.debug {
for a in self.proximity_asteroids.chunks(3) { for a in self.asteroids_data.chunks(3) {
draw_circle_lines(a[0], a[1], a[2], 1., GRAY); draw_circle_lines(a[0], a[1], a[2], 1., GRAY);
draw_line(self.pos.x, self.pos.y, a[0], a[1], 1., GRAY) draw_line(self.pos.x, self.pos.y, a[0], a[1], 1., GRAY)
} }

View File

@ -14,7 +14,7 @@ impl Population {
Self { Self {
size, size,
worlds: (0..size) worlds: (0..size)
.map(|_| World::simulate(NN::new(vec![33, 10, 4]))) .map(|_| World::simulate(NN::new(vec![33, 16, 4])))
.collect(), .collect(),
..Default::default() ..Default::default()
} }
@ -30,6 +30,7 @@ impl Population {
} }
if !alive { if !alive {
self.gen += 1; self.gen += 1;
println!("{}", self.gen);
self.next_gen(); self.next_gen();
} }
} }
@ -50,18 +51,19 @@ impl Population {
} }
pub fn next_gen(&mut self) { pub fn next_gen(&mut self) {
let total = self.worlds.iter().fold(0, |acc, x| acc + x.score); let total = self.worlds.iter().fold(0., |acc, x| acc + x.fitness());
self.worlds.sort_by(|a, b| b.score.cmp(&a.score)); // self.worlds.sort_by(|a, b| b.fitness().cmp(&a.fitness()));
let mut new_worlds = (0..self.size / 10) let mut new_worlds = Vec::new();
.map(|i| World::simulate(self.worlds[i].see_brain().to_owned())) // (0..self.size / 10)
.collect::<Vec<_>>(); // .map(|i| World::simulate(self.worlds[i].see_brain().to_owned()))
// .collect::<Vec<_>>();
while new_worlds.len() < self.size { while new_worlds.len() < self.size {
let rands = (gen_range(0, total + 1), gen_range(0, total + 1)); let rands = (gen_range(0., total), gen_range(0., total));
let mut sum = 0; let mut sum = 0.;
let (mut a, mut b) = (None, None); let (mut a, mut b) = (None, None);
for world in &self.worlds { for world in &self.worlds {
sum += world.score; sum += world.fitness();
if sum >= rands.0 { if sum >= rands.0 {
a = Some(world.see_brain()); a = Some(world.see_brain());
} }

View File

@ -35,6 +35,16 @@ impl World {
self.player.brain.as_ref().unwrap() self.player.brain.as_ref().unwrap()
} }
pub fn fitness(&self) -> f32 {
self.score as f32
+ self.player.lifespan as f32 * 0.01
+ if self.player.shots > 0 {
self.score as f32 / self.player.shots as f32 * 10.
} else {
0.
}
}
pub fn update(&mut self) { pub fn update(&mut self) {
self.player.update(); self.player.update();
let mut to_add: Vec<Asteroid> = Vec::new(); let mut to_add: Vec<Asteroid> = Vec::new();