From 596db89430711608e3841e9b807271071255bc23 Mon Sep 17 00:00:00 2001 From: Andy Killorin <37423245+Speedy6451@users.noreply.github.com> Date: Mon, 9 Nov 2026 15:50:07 -0500 Subject: [PATCH] define mortality --- simulator/src/main.rs | 83 +++++++++++++++++++++++++++++-------------- 1 file changed, 57 insertions(+), 26 deletions(-) diff --git a/simulator/src/main.rs b/simulator/src/main.rs index 8af789f..34d4a08 100644 --- a/simulator/src/main.rs +++ b/simulator/src/main.rs @@ -2,6 +2,8 @@ use std::cmp::min; use std::collections::HashMap; use std::f32::consts::TAU; use std::ptr; +use std::sync::atomic::AtomicBool; +use std::sync::atomic::Ordering; use macroquad::prelude::*; use parry2d::math::Pose; @@ -16,19 +18,48 @@ use parry2d::shape::Shape; const VIEW_DIST: f32 = 180.0; const BOT_RADIUS: f32 = 16.0; +trait Mortal { + fn collider(&self) -> (&Pose, &dyn Shape); + fn kill(&self); + fn living(&self) -> bool; + + fn draw(&self); +} + struct Robot { pose: Pose, - alive: bool, + alive: AtomicBool, collider: Ball, sensor: Sensor, team: Color, } +impl Mortal for Robot { + fn draw(&self) { + let tl = self.pose.translation; + let tl2 = self.view_end(); + draw_circle(tl.x, tl.y, BOT_RADIUS, BLACK); + draw_line(tl.x, tl.y, tl2.x, tl2.y, 2.0, BLUE); + draw_circle(tl.x, tl.y, BOT_RADIUS-1.0, self.team); + } + + fn collider(&self) -> (&Pose, &dyn Shape) { + (&self.pose, &self.collider) + } + + fn kill (&self) { + self.alive.store(false, Ordering::Relaxed); + } + fn living(&self) -> bool { + self.alive.load(Ordering::Relaxed) + } +} + impl Robot { fn new(position: Vec2, team: Color) -> Self { let rand_angle = rand::gen_range(0, 1000) as f32 * TAU / 1000.0; let pose:Pose = Pose::from_parts(position.to_array().into(), Rot2::from_angle(rand_angle)); - Self { pose, alive: true, collider: Ball::new(BOT_RADIUS), sensor: Sensor::None, team} + Self { pose, alive: AtomicBool::new(true), collider: Ball::new(BOT_RADIUS), sensor: Sensor::None, team} } fn move_step(&mut self, forward: f32, right: f32) { @@ -40,21 +71,10 @@ impl Robot { Vec2::new(self.pose.rotation.re, self.pose.rotation.im) } - pub fn draw(&self) { - let tl = self.pose.translation; - let tl2 = self.view_end(); - draw_circle(tl.x, tl.y, BOT_RADIUS, BLACK); - draw_line(tl.x, tl.y, tl2.x, tl2.y, 2.0, BLUE); - draw_circle(tl.x, tl.y, BOT_RADIUS-1.0, self.team); - } - fn view_end(&self) -> Vec2 { self.pose.translation + self.ahead() * VIEW_DIST } - pub fn collider(&self) -> (&Pose, &dyn Shape) { - (&self.pose, &self.collider) - } fn detect<'a>(&self, things: impl Iterator) -> Option { let collider = Segment::new(self.pose.translation, self.view_end()); @@ -76,7 +96,7 @@ impl Robot { struct Food { pose: Pose, collider: Ball, - alive: bool, + alive: AtomicBool, } enum Sensor { @@ -86,22 +106,33 @@ enum Sensor { None } -impl Food { - fn new(position: Vec2) -> Self { - let pose:Pose = Pose::from_translation(position.to_array().into()); - Self { pose, alive: true, collider: Ball::new(BOT_RADIUS) } - } - - pub fn draw(&self) { +impl Mortal for Food { + fn draw(&self) { let tl = self.pose.translation; draw_circle(tl.x, tl.y, BOT_RADIUS, BLACK); draw_circle(tl.x, tl.y, BOT_RADIUS-1.0, GREEN); } - pub fn collider(&self) -> (&Pose, &dyn Shape) { + fn collider(&self) -> (&Pose, &dyn Shape) { (&self.pose, &self.collider) } + fn kill (&self) { + self.alive.store(false, Ordering::Relaxed); + } + + fn living(&self) -> bool { + self.alive.load(Ordering::Relaxed) + } +} + +impl Food { + fn new(position: Vec2) -> Self { + let pose:Pose = Pose::from_translation(position.to_array().into()); + Self { pose, alive: AtomicBool::new(true), collider: Ball::new(BOT_RADIUS) } + } + + fn detect<'a>(&self, things: impl Iterator) -> Option { things .map(|robot| contact(&self.pose, &self.collider, &robot.pose, &robot.collider, 0.0).unwrap().map(|a| (a,robot.team))).flatten() @@ -140,21 +171,21 @@ async fn run_simulation() -> (i32, i32) { let mut loo = 0; loop { - let rendered = loo %30 == 0; + let rendered = loo %100 == 0; clear_background(LIGHTGRAY); for food in &mut food{ if let Some(team) = food.detect(robots.iter()) { - if food.alive { + if food.living() { score.entry(color_hash(team)).and_modify(|s| *s +=1 ).or_insert(1); - food.alive = false; + food.kill(); } } if rendered { food.draw(); } // TODO: die upon collision with robot } - food = food.into_iter().filter(|f| f.alive).collect(); // remove dead food + food = food.into_iter().filter(Mortal::living).collect(); // remove dead food let mut sensors = Vec::new(); for robot in &*robots {