From 621d78be606c22d737c5a664b469525e3862f901 Mon Sep 17 00:00:00 2001 From: platane Date: Mon, 24 Mar 2025 21:23:37 +0100 Subject: [PATCH] . --- packages/solver-r/src/snake_compact.rs | 176 +++++++++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 packages/solver-r/src/snake_compact.rs diff --git a/packages/solver-r/src/snake_compact.rs b/packages/solver-r/src/snake_compact.rs new file mode 100644 index 0000000..872fb25 --- /dev/null +++ b/packages/solver-r/src/snake_compact.rs @@ -0,0 +1,176 @@ +use crate::grid::Point; + +#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] +pub enum Direction { + Left = 0, + Right = 1, + Up = 2, + Down = 3, +} + +fn get_direction_vector(dir: Direction) -> Point { + match dir { + Direction::Down => Point { x: 0, y: -1 }, + Direction::Up => Point { x: 0, y: 1 }, + Direction::Left => Point { x: -1, y: 0 }, + Direction::Right => Point { x: 1, y: 0 }, + } +} +fn get_direction_from_vector(v: &Point) -> Direction { + match v { + Point { x: 0, y: -1 } => Direction::Down, + Point { x: 0, y: 1 } => Direction::Up, + Point { x: -1, y: 0 } => Direction::Left, + Point { x: 1, y: 0 } => Direction::Right, + _ => panic!(), + } +} + +#[derive(Clone)] +pub struct SnakeC { + pub head: Point, + pub body: Vec, +} +impl SnakeC { + pub fn get_cells(&self) -> Vec { + let mut e = self.head.clone(); + let mut out = Vec::new(); + + out.push(e.clone()); + for dir in self.body.iter() { + let v = get_direction_vector(*dir); + e.x -= v.x; + e.y -= v.y; + out.push(e.clone()); + } + + out + } + + pub fn is_head_self_colliding(&self) -> bool { + self.get_cells()[1..].contains(&self.head) + } + + pub fn advance(&mut self, dir: Direction) -> () { + let v = get_direction_vector(dir); + + self.head.x += v.x; + self.head.y += v.y; + + self.body.pop(); + self.body.insert(0, dir); + } +} + +impl From> for SnakeC { + fn from(value: Vec) -> Self { + let head = value.get(0).unwrap().clone(); + let body = value + .windows(2) + .map(|w| { + let v = Point { + x: w[0].x - w[1].x, + y: w[0].y - w[1].y, + }; + get_direction_from_vector(&v) + }) + .collect(); + + Self { head, body } + } +} + +#[test] +fn it_should_get_the_snake_cell() { + let s = SnakeC { + head: Point { x: 10, y: 5 }, + body: vec![Direction::Up, Direction::Up, Direction::Left], + }; + + assert_eq!( + s.get_cells(), + vec![ + // + Point { x: 10, y: 5 }, + Point { x: 10, y: 4 }, + Point { x: 10, y: 3 }, + Point { x: 11, y: 3 }, + ] + ); +} + +#[test] +fn it_should_get_snake_from_point_list() { + let s = SnakeC::from(vec![ + // + Point { x: 10, y: 5 }, + Point { x: 10, y: 4 }, + Point { x: 10, y: 3 }, + Point { x: 11, y: 3 }, + Point { x: 12, y: 3 }, + Point { x: 12, y: 2 }, + ]); + + assert_eq!( + s.get_cells(), + vec![ + // + Point { x: 10, y: 5 }, + Point { x: 10, y: 4 }, + Point { x: 10, y: 3 }, + Point { x: 11, y: 3 }, + Point { x: 12, y: 3 }, + Point { x: 12, y: 2 }, + ] + ); +} + +#[test] +fn it_should_advance_snake() { + let mut s = SnakeC::from(vec![ + // + Point { x: 10, y: 3 }, + Point { x: 11, y: 3 }, + Point { x: 12, y: 3 }, + Point { x: 12, y: 2 }, + ]); + + s.advance(Direction::Up); + + assert_eq!( + s.get_cells(), + vec![ + // + Point { x: 10, y: 4 }, + Point { x: 10, y: 3 }, + Point { x: 11, y: 3 }, + Point { x: 12, y: 3 }, + ] + ); +} + +#[test] +fn it_should_detect_self_collision() { + let mut s = SnakeC::from(vec![ + // + Point { x: 0, y: 0 }, + Point { x: 0, y: 1 }, + Point { x: 0, y: 2 }, + Point { x: 0, y: 3 }, + Point { x: 0, y: 4 }, + Point { x: 0, y: 5 }, + Point { x: 0, y: 6 }, + ]); + + assert_eq!(s.is_head_self_colliding(), false); + + s.advance(Direction::Right); + s.advance(Direction::Up); + s.advance(Direction::Up); + + assert_eq!(s.is_head_self_colliding(), false); + + s.advance(Direction::Left); + + assert_eq!(s.is_head_self_colliding(), true); +}