using System.Collections.ObjectModel; namespace Snake.Model; public class SnakeLevel{ public int Size {get; } public enum LevelBlock{ Empty, Obstacle, Egg, Snake, SnakeHead, OutOfBounds } public enum SnakeDirection{ Up, Down, Left, Right } public enum GameState{ Running, Dead } private readonly List _obstacles; public ReadOnlyCollection Obstacles => _obstacles.AsReadOnly(); public Point SnakeHead {get; private set;} private readonly List _snake; // Head is not in snake // Last is closest to the head public ReadOnlyCollection Snake => _snake.AsReadOnly(); public int SnakeLength => Snake.Count + 1; private readonly List _eggs; public ReadOnlyCollection Eggs => _eggs.AsReadOnly(); public SnakeDirection SnakeHeadDirection {get; private set;} public GameState State {get; private set;} public SnakeLevel(int size, IEnumerable obstacles, int snake_start_length){ this.Size = size; _obstacles = new List(obstacles); _eggs = []; _snake = []; SnakeHead = (size / 2, snake_start_length-1); for(int i=0; i=Size || p.Y >= Size){ return LevelBlock.OutOfBounds; } return LevelBlock.Empty; } } public void Tick(){ Point new_snake_head = (0,0); switch(SnakeHeadDirection){ case SnakeDirection.Up: new_snake_head = (SnakeHead.X, SnakeHead.Y - 1); break; case SnakeDirection.Down: new_snake_head = (SnakeHead.X, SnakeHead.Y + 1); break; case SnakeDirection.Left: new_snake_head = (SnakeHead.X - 1, SnakeHead.Y); break; case SnakeDirection.Right: new_snake_head = (SnakeHead.X + 1, SnakeHead.Y); break; } if(this[new_snake_head] is LevelBlock.Obstacle or LevelBlock.Snake or LevelBlock.OutOfBounds){ State = GameState.Dead; return; } var first = Snake[0]; for(int i=_snake.Count-1; i>0; i--){ _snake[i-1] = _snake[i]; } _snake[^1] = SnakeHead; if(this[new_snake_head] is LevelBlock.Egg){ _snake.Insert(0, first); _eggs.Remove(new_snake_head); } SnakeHead = new_snake_head; } }