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); }