changes xd
This commit is contained in:
+124
-11
@@ -1,8 +1,11 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO.Pipes;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Snake.Model;
|
||||
|
||||
public class SnakeLevel{
|
||||
public static readonly TimeSpan TickTimeSpan = TimeSpan.FromMilliseconds(500);
|
||||
public int Size {get; }
|
||||
|
||||
public enum LevelBlock{
|
||||
@@ -23,6 +26,7 @@ public class SnakeLevel{
|
||||
|
||||
public enum GameState{
|
||||
Running,
|
||||
Paused,
|
||||
Dead
|
||||
}
|
||||
|
||||
@@ -31,26 +35,74 @@ public class SnakeLevel{
|
||||
public Point SnakeHead {get; private set;}
|
||||
private readonly List<Point> _snake;
|
||||
// Head is not in snake
|
||||
// Last is closest to the head
|
||||
// First is closest to the head
|
||||
public ReadOnlyCollection<Point> Snake => _snake.AsReadOnly();
|
||||
public int SnakeLength => Snake.Count + 1;
|
||||
private readonly List<Point> _eggs;
|
||||
public ReadOnlyCollection<Point> Eggs => _eggs.AsReadOnly();
|
||||
public SnakeDirection SnakeHeadDirection {get; private set;}
|
||||
public GameState State {get; private set;}
|
||||
public int NewEggRound { get; }
|
||||
public int EggLimit { get; }
|
||||
private int _round;
|
||||
|
||||
public SnakeLevel(int size, IEnumerable<Point> obstacles, int snake_start_length){
|
||||
private PeriodicTimer _timer;
|
||||
public int Score { get; private set; }
|
||||
|
||||
public event EventHandler? GameUpdate;
|
||||
public event EventHandler<GameState>? GameStateUpdate;
|
||||
private GameState _state;
|
||||
public GameState State
|
||||
{
|
||||
get => _state;
|
||||
private set
|
||||
{
|
||||
_state = value;
|
||||
GameStateUpdate?.Invoke(this, _state);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private SnakeDirection LastDirection = SnakeDirection.Down;
|
||||
private SnakeDirection _SnakeHeadDirection;
|
||||
public SnakeDirection SnakeHeadDirection
|
||||
{
|
||||
get => _SnakeHeadDirection;
|
||||
set
|
||||
{
|
||||
switch (value, LastDirection)
|
||||
{
|
||||
case { value: SnakeDirection.Up or SnakeDirection.Down, LastDirection: SnakeDirection.Left or SnakeDirection.Right}:
|
||||
case { value: SnakeDirection.Left or SnakeDirection.Right, LastDirection: SnakeDirection.Up or SnakeDirection.Down }:
|
||||
_SnakeHeadDirection = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public SnakeLevel(int size, IEnumerable<Point> obstacles, int snake_start_length, int new_egg_round, int egg_limit, TimeProvider time_provider){
|
||||
this.Size = size;
|
||||
this.NewEggRound = new_egg_round;
|
||||
this._round = NewEggRound;
|
||||
this.EggLimit = egg_limit;
|
||||
|
||||
_obstacles = new List<Point>(obstacles);
|
||||
_eggs = [];
|
||||
_snake = [];
|
||||
|
||||
SnakeHead = (size / 2, snake_start_length-1);
|
||||
for(int i=0; i<snake_start_length-1; i++){
|
||||
for(int i= snake_start_length - 2; i>=0; i--){
|
||||
_snake.Add((size / 2, i));
|
||||
}
|
||||
|
||||
SnakeHeadDirection = SnakeDirection.Down;
|
||||
_SnakeHeadDirection = SnakeDirection.Down;
|
||||
LastDirection = SnakeDirection.Down;
|
||||
|
||||
_timer = new PeriodicTimer(TickTimeSpan, time_provider);
|
||||
|
||||
_state = GameState.Paused;
|
||||
}
|
||||
|
||||
public SnakeLevel(int size, IEnumerable<Point> obstacles, int snake_start_length, int new_egg_round, int egg_limit) : this(size, obstacles, snake_start_length, new_egg_round, egg_limit, TimeProvider.System)
|
||||
{
|
||||
}
|
||||
|
||||
public LevelBlock this[Point p]{
|
||||
@@ -93,18 +145,79 @@ public class SnakeLevel{
|
||||
return;
|
||||
}
|
||||
|
||||
var first = Snake[0];
|
||||
Point last = _snake.Last();
|
||||
|
||||
for(int i=_snake.Count-1; i>0; i--){
|
||||
_snake[i-1] = _snake[i];
|
||||
for (int i = Snake.Count - 1; i > 0; i--)
|
||||
{
|
||||
_snake[i] = _snake[i - 1];
|
||||
}
|
||||
_snake[^1] = SnakeHead;
|
||||
_snake[0] = SnakeHead;
|
||||
|
||||
if(this[new_snake_head] is LevelBlock.Egg){
|
||||
_snake.Insert(0, first);
|
||||
_snake.Add(last);
|
||||
_eggs.Remove(new_snake_head);
|
||||
Score++;
|
||||
}
|
||||
|
||||
SnakeHead = new_snake_head;
|
||||
|
||||
if (Eggs.Count < EggLimit && --_round == 0)
|
||||
{
|
||||
_round = NewEggRound;
|
||||
int avail_pos = Size * Size - Eggs.Count - Obstacles.Count - SnakeLength;
|
||||
if (avail_pos > 0)
|
||||
{
|
||||
int pos = Random.Shared.Next(0, avail_pos);
|
||||
Point p = (0, 0);
|
||||
for (int i = 0; i < pos; i++)
|
||||
{
|
||||
do
|
||||
{
|
||||
p = (p.X + 1, p.Y);
|
||||
if (p.X >= Size)
|
||||
{
|
||||
p = (0, p.Y + 1);
|
||||
}
|
||||
} while (this[p] is not LevelBlock.Empty);
|
||||
}
|
||||
_eggs.Add(p);
|
||||
}
|
||||
}
|
||||
|
||||
LastDirection = SnakeHeadDirection;
|
||||
}
|
||||
|
||||
private async Task TickerTask()
|
||||
{
|
||||
while(State == GameState.Running && await _timer.WaitForNextTickAsync())
|
||||
{
|
||||
Tick();
|
||||
GameUpdate?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
if(State == GameState.Paused)
|
||||
{
|
||||
State = GameState.Running;
|
||||
Task.Run(TickerTask);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Game is not paused");
|
||||
}
|
||||
}
|
||||
|
||||
public void Pause()
|
||||
{
|
||||
if(State == GameState.Running)
|
||||
{
|
||||
State = GameState.Paused;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Game is not running");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user