67 lines
1.8 KiB
C#
67 lines
1.8 KiB
C#
namespace Snake.Core;
|
|
|
|
public sealed class SnakeGame
|
|
{
|
|
public SnakeGame(int width, int height, Random? random = null)
|
|
{
|
|
_random = random ?? Random.Shared;
|
|
Board = new Board(width, height);
|
|
|
|
var start = new Position(width / 2, height / 2);
|
|
Snake = new Snake(start, length: 3, Direction.Right);
|
|
Food = new Food(Board, Snake.Segments, _random);
|
|
}
|
|
|
|
private readonly Random _random;
|
|
|
|
public Board Board { get; }
|
|
|
|
public Snake Snake { get; }
|
|
|
|
public Food Food { get; }
|
|
|
|
public int Score { get; private set; }
|
|
|
|
public bool IsGameOver { get; private set; }
|
|
|
|
public const int PointsPerLevel = 5;
|
|
|
|
public int Level => 1 + Score / PointsPerLevel;
|
|
|
|
public static int GetTickIntervalMs(int score, int baseIntervalMs = 120, int minIntervalMs = 50) =>
|
|
Math.Max(minIntervalMs, baseIntervalMs - (1 + score / PointsPerLevel - 1) * 10);
|
|
|
|
public void SetDirection(Direction direction) => Snake.SetDirection(direction);
|
|
|
|
public GameTickResult Tick()
|
|
{
|
|
if (IsGameOver)
|
|
return GameTickResult.GameOver;
|
|
|
|
var newHead = Snake.PeekNextHead();
|
|
var ateFood = newHead == Food.Position;
|
|
|
|
if (!Board.IsWithinBounds(newHead) || Snake.Occupies(newHead, excludeTail: !ateFood))
|
|
{
|
|
IsGameOver = true;
|
|
return GameTickResult.GameOver;
|
|
}
|
|
Snake.Move(grow: ateFood);
|
|
|
|
if (ateFood)
|
|
{
|
|
Score++;
|
|
if (Snake.Segments.Count >= Board.Width * Board.Height)
|
|
{
|
|
IsGameOver = true;
|
|
return GameTickResult.AteFood;
|
|
}
|
|
|
|
Food.Respawn(Snake.Segments);
|
|
return GameTickResult.AteFood;
|
|
}
|
|
|
|
return GameTickResult.Moved;
|
|
}
|
|
}
|