feat: initial project structure with Snake.Core, CLI and Avalonia skeleton
This commit is contained in:
80
Snake.Core/Snake.cs
Normal file
80
Snake.Core/Snake.cs
Normal file
@@ -0,0 +1,80 @@
|
||||
namespace Snake.Core;
|
||||
|
||||
public sealed class Snake
|
||||
{
|
||||
private readonly LinkedList<Position> _segments = new();
|
||||
|
||||
public Snake(Position start, int length, Direction direction)
|
||||
{
|
||||
if (length < 1)
|
||||
throw new ArgumentOutOfRangeException(nameof(length), "Length must be at least 1.");
|
||||
|
||||
Direction = direction;
|
||||
|
||||
var offset = DirectionToOffset(direction);
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
_segments.AddLast(new Position(
|
||||
start.X - offset.X * i,
|
||||
start.Y - offset.Y * i));
|
||||
}
|
||||
}
|
||||
|
||||
public Direction Direction { get; private set; }
|
||||
|
||||
public Position Head => _segments.First!.Value;
|
||||
|
||||
public IReadOnlyCollection<Position> Segments => _segments;
|
||||
|
||||
public void SetDirection(Direction direction)
|
||||
{
|
||||
if (direction == Direction)
|
||||
return;
|
||||
|
||||
if (AreOpposite(Direction, direction))
|
||||
return;
|
||||
|
||||
Direction = direction;
|
||||
}
|
||||
|
||||
public Position PeekNextHead()
|
||||
{
|
||||
var offset = DirectionToOffset(Direction);
|
||||
return new Position(Head.X + offset.X, Head.Y + offset.Y);
|
||||
}
|
||||
|
||||
public Position Move(bool grow = false)
|
||||
{
|
||||
var newHead = PeekNextHead();
|
||||
|
||||
_segments.AddFirst(newHead);
|
||||
|
||||
if (!grow)
|
||||
_segments.RemoveLast();
|
||||
|
||||
return newHead;
|
||||
}
|
||||
|
||||
public bool Occupies(Position position) =>
|
||||
_segments.Contains(position);
|
||||
|
||||
private static Position DirectionToOffset(Direction direction) =>
|
||||
direction switch
|
||||
{
|
||||
Direction.Up => new Position(0, -1),
|
||||
Direction.Down => new Position(0, 1),
|
||||
Direction.Left => new Position(-1, 0),
|
||||
Direction.Right => new Position(1, 0),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(direction))
|
||||
};
|
||||
|
||||
private static bool AreOpposite(Direction current, Direction next) =>
|
||||
(current, next) switch
|
||||
{
|
||||
(Direction.Up, Direction.Down) => true,
|
||||
(Direction.Down, Direction.Up) => true,
|
||||
(Direction.Left, Direction.Right) => true,
|
||||
(Direction.Right, Direction.Left) => true,
|
||||
_ => false
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user