snakepipe 2.2.1

A snake game based on stdin/stdout following unix philosophy
Documentation
use serde::Serialize;
use std::collections::LinkedList;

use crate::gamestate::physics::{Direction, Position};

#[derive(Debug, Serialize)]
pub struct Snake {
    direction: Direction,
    head: Position,
    tail: LinkedList<Position>,
    #[serde(skip)]
    updated_tail_pos: bool,
    #[serde(skip)]
    initial_length: u32,
}

impl Snake {
    pub fn new(head: Position, snake_length: u32) -> Self {
        let (x, y) = (head.x, head.y);
        let mut tail = LinkedList::new();

        for i in 1..(snake_length + 1) {
            tail.push_back(Position { x, y: y - i as i32 });
        }

        Self {
            direction: Direction::Down,
            head: Position { x, y },
            tail,
            updated_tail_pos: false,
            initial_length: snake_length,
        }
    }

    pub fn update(&mut self, height: u32, width: u32) {
        if self.tail.len() > 0 {
            self.tail.push_front(self.head.clone());
            self.tail.pop_back();
        }

        match self.direction {
            Direction::Up => self.head.y -= 1,
            Direction::Right => self.head.x += 1,
            Direction::Down => self.head.y += 1,
            Direction::Left => self.head.x -= 1,
        }

        if self.head.x >= height as i32 {
            self.head.x = 0;
        } else if self.head.y >= width as i32 {
            self.head.y = 0;
        } else if self.head.y < 0 {
            self.head.y = (width - 1) as i32;
        } else if self.head.x < 0 {
            self.head.x = (height - 1) as i32;
        }

        self.updated_tail_pos = true;
    }

    pub fn set_dir(&mut self, dir: Direction) {
        if dir == self.direction.opposite() || !self.updated_tail_pos {
            return;
        }

        self.direction = dir;
        self.updated_tail_pos = false;
    }

    pub fn get_head_pos(&self) -> &Position {
        &self.head
    }

    pub fn get_len(&self) -> usize {
        &self.tail.len() - self.initial_length as usize
    }

    pub fn is_tail_overlapping(&self) -> bool {
        for pos in self.tail.iter() {
            if *pos == self.head {
                return true;
            }
        }

        false
    }

    pub fn will_tail_overlap(&self) -> bool {
        let next = self.next_head_pos();

        for pos in self.tail.iter() {
            if *pos == next {
                return true;
            }
        }

        false
    }

    pub fn grow(&mut self) {
        let last = match self.tail.back() {
            Some(pos) => pos.clone(),
            None => self.head.clone(),
        };

        self.tail.push_back(last);
    }

    fn next_head_pos(&self) -> Position {
        let mut pos = self.head.clone();

        match self.direction {
            Direction::Up => pos.y -= 1,
            Direction::Left => pos.x -= 1,
            Direction::Down => pos.y += 1,
            Direction::Right => pos.x += 1,
        }

        pos
    }
}