217 lines
8.1 KiB
C#
217 lines
8.1 KiB
C#
|
|
using Chessistics.Engine.Model;
|
||
|
|
using Chessistics.Engine.Rules;
|
||
|
|
using Chessistics.Tests.Helpers;
|
||
|
|
using Xunit;
|
||
|
|
|
||
|
|
namespace Chessistics.Tests.Rules;
|
||
|
|
|
||
|
|
public class MoveValidatorTests
|
||
|
|
{
|
||
|
|
private BoardState EmptyBoard(int size = 5)
|
||
|
|
=> new BoardBuilder(size, size)
|
||
|
|
.WithProduction(0, 0, "P", CargoType.Wood, 2)
|
||
|
|
.WithDemand(size - 1, 0, "D", CargoType.Wood, 1, 99)
|
||
|
|
.WithStock(PieceKind.Rook, 10)
|
||
|
|
.WithStock(PieceKind.Bishop, 10)
|
||
|
|
.WithStock(PieceKind.Knight, 10)
|
||
|
|
.BuildState();
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void Rook_CanMove_1or2_Orthogonal()
|
||
|
|
{
|
||
|
|
var board = EmptyBoard();
|
||
|
|
var moves = MoveValidator.GetLegalEndCells(PieceKind.Rook, new Coords(2, 2), board);
|
||
|
|
|
||
|
|
// 4 directions x 2 distances = 8 cells
|
||
|
|
Assert.Equal(8, moves.Count);
|
||
|
|
Assert.Contains(new Coords(2, 3), moves); // up 1
|
||
|
|
Assert.Contains(new Coords(2, 4), moves); // up 2
|
||
|
|
Assert.Contains(new Coords(2, 1), moves); // down 1
|
||
|
|
// (2,0) is the production cell - it's Empty type, so should be reachable
|
||
|
|
Assert.Contains(new Coords(3, 2), moves); // right 1
|
||
|
|
Assert.Contains(new Coords(4, 2), moves); // right 2
|
||
|
|
Assert.Contains(new Coords(1, 2), moves); // left 1
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void Rook_BlockedByWall()
|
||
|
|
{
|
||
|
|
var board = new BoardBuilder(5, 5)
|
||
|
|
.WithProduction(0, 0, "P", CargoType.Wood, 2)
|
||
|
|
.WithDemand(4, 0, "D", CargoType.Wood, 1, 99)
|
||
|
|
.WithWall(1, 0)
|
||
|
|
.WithStock(PieceKind.Rook, 5)
|
||
|
|
.BuildState();
|
||
|
|
|
||
|
|
// Rook at (0, 0) is on a Production cell - start shouldn't be a wall
|
||
|
|
// Let's place rook at (0, 1) looking right - wall at (1,0) doesn't block vertical
|
||
|
|
// Test: rook at (0,0) looking right: wall at (1,0) blocks
|
||
|
|
var moves = MoveValidator.GetLegalEndCells(PieceKind.Rook, new Coords(0, 1), board);
|
||
|
|
|
||
|
|
// Right direction: (1,1) and (2,1) are fine (wall is at 1,0 not 1,1)
|
||
|
|
Assert.Contains(new Coords(1, 1), moves);
|
||
|
|
Assert.Contains(new Coords(2, 1), moves);
|
||
|
|
|
||
|
|
// Rook at (2,0) going left: (1,0) is wall, blocked
|
||
|
|
var moves2 = MoveValidator.GetLegalEndCells(PieceKind.Rook, new Coords(2, 0), board);
|
||
|
|
Assert.DoesNotContain(new Coords(1, 0), moves2);
|
||
|
|
Assert.DoesNotContain(new Coords(0, 0), moves2); // blocked by wall on the way
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void Rook_NotBlockedByPiece_InEdit()
|
||
|
|
{
|
||
|
|
var board = EmptyBoard();
|
||
|
|
// Place a piece at (2,3) — in edit mode, pieces do NOT block sliding
|
||
|
|
board.Pieces.Add(new PieceState(99, PieceKind.Rook, new Coords(2, 3), new Coords(2, 4), 0));
|
||
|
|
|
||
|
|
var moves = MoveValidator.GetLegalEndCells(PieceKind.Rook, new Coords(2, 2), board);
|
||
|
|
// Pieces share relay points — collisions are detected at runtime
|
||
|
|
Assert.Contains(new Coords(2, 3), moves);
|
||
|
|
Assert.Contains(new Coords(2, 4), moves);
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void Rook_CannotLandOnWall()
|
||
|
|
{
|
||
|
|
var board = new BoardBuilder(5, 5)
|
||
|
|
.WithProduction(0, 0, "P", CargoType.Wood, 2)
|
||
|
|
.WithDemand(4, 0, "D", CargoType.Wood, 1, 99)
|
||
|
|
.WithWall(3, 2)
|
||
|
|
.WithStock(PieceKind.Rook, 5)
|
||
|
|
.BuildState();
|
||
|
|
|
||
|
|
var moves = MoveValidator.GetLegalEndCells(PieceKind.Rook, new Coords(2, 2), board);
|
||
|
|
Assert.DoesNotContain(new Coords(3, 2), moves);
|
||
|
|
Assert.DoesNotContain(new Coords(4, 2), moves); // blocked by wall in path
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void Bishop_DiagonalOnly()
|
||
|
|
{
|
||
|
|
var board = EmptyBoard();
|
||
|
|
var moves = MoveValidator.GetLegalEndCells(PieceKind.Bishop, new Coords(2, 2), board);
|
||
|
|
|
||
|
|
// 4 diagonal directions x 2 distances = 8 cells
|
||
|
|
Assert.Equal(8, moves.Count);
|
||
|
|
Assert.Contains(new Coords(3, 3), moves);
|
||
|
|
Assert.Contains(new Coords(4, 4), moves);
|
||
|
|
Assert.Contains(new Coords(1, 1), moves);
|
||
|
|
Assert.Contains(new Coords(1, 3), moves);
|
||
|
|
Assert.Contains(new Coords(3, 1), moves);
|
||
|
|
|
||
|
|
// Should NOT contain orthogonal moves
|
||
|
|
Assert.DoesNotContain(new Coords(2, 3), moves);
|
||
|
|
Assert.DoesNotContain(new Coords(3, 2), moves);
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void Bishop_BlockedByWall()
|
||
|
|
{
|
||
|
|
var board = new BoardBuilder(5, 5)
|
||
|
|
.WithProduction(0, 0, "P", CargoType.Wood, 2)
|
||
|
|
.WithDemand(4, 0, "D", CargoType.Wood, 1, 99)
|
||
|
|
.WithWall(3, 3)
|
||
|
|
.WithStock(PieceKind.Bishop, 5)
|
||
|
|
.BuildState();
|
||
|
|
|
||
|
|
var moves = MoveValidator.GetLegalEndCells(PieceKind.Bishop, new Coords(2, 2), board);
|
||
|
|
Assert.DoesNotContain(new Coords(3, 3), moves); // wall
|
||
|
|
Assert.DoesNotContain(new Coords(4, 4), moves); // blocked by wall in path
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void Knight_LShape()
|
||
|
|
{
|
||
|
|
var board = EmptyBoard();
|
||
|
|
var moves = MoveValidator.GetLegalEndCells(PieceKind.Knight, new Coords(2, 2), board);
|
||
|
|
|
||
|
|
// Up to 8 L-shaped destinations
|
||
|
|
Assert.Equal(8, moves.Count);
|
||
|
|
Assert.Contains(new Coords(3, 4), moves);
|
||
|
|
Assert.Contains(new Coords(4, 3), moves);
|
||
|
|
Assert.Contains(new Coords(4, 1), moves);
|
||
|
|
Assert.Contains(new Coords(3, 0), moves);
|
||
|
|
Assert.Contains(new Coords(1, 0), moves);
|
||
|
|
Assert.Contains(new Coords(0, 1), moves);
|
||
|
|
Assert.Contains(new Coords(0, 3), moves);
|
||
|
|
Assert.Contains(new Coords(1, 4), moves);
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void Knight_JumpsOverWalls()
|
||
|
|
{
|
||
|
|
var board = new BoardBuilder(5, 5)
|
||
|
|
.WithProduction(0, 0, "P", CargoType.Wood, 2)
|
||
|
|
.WithDemand(4, 0, "D", CargoType.Wood, 1, 99)
|
||
|
|
.WithWall(1, 2)
|
||
|
|
.WithWall(2, 1)
|
||
|
|
.WithWall(2, 3)
|
||
|
|
.WithWall(3, 2)
|
||
|
|
.WithStock(PieceKind.Knight, 5)
|
||
|
|
.BuildState();
|
||
|
|
|
||
|
|
// Knight at (2,2) surrounded by walls — should still jump over all of them
|
||
|
|
var moves = MoveValidator.GetLegalEndCells(PieceKind.Knight, new Coords(2, 2), board);
|
||
|
|
Assert.Contains(new Coords(3, 4), moves);
|
||
|
|
Assert.Contains(new Coords(4, 3), moves);
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void Knight_JumpsOverPieces()
|
||
|
|
{
|
||
|
|
var board = EmptyBoard();
|
||
|
|
// Place pieces adjacent to knight — they don't block L-shape jumps
|
||
|
|
board.Pieces.Add(new PieceState(90, PieceKind.Rook, new Coords(2, 3), new Coords(3, 3), 0));
|
||
|
|
board.Pieces.Add(new PieceState(91, PieceKind.Rook, new Coords(3, 2), new Coords(3, 1), 0));
|
||
|
|
|
||
|
|
var moves = MoveValidator.GetLegalEndCells(PieceKind.Knight, new Coords(2, 2), board);
|
||
|
|
// Knight should reach all 8 L-shaped cells regardless of pieces in between
|
||
|
|
Assert.Contains(new Coords(3, 4), moves);
|
||
|
|
Assert.Contains(new Coords(4, 3), moves);
|
||
|
|
Assert.Contains(new Coords(4, 1), moves);
|
||
|
|
Assert.Contains(new Coords(1, 4), moves);
|
||
|
|
Assert.Equal(8, moves.Count);
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void Knight_CannotLandOnWall()
|
||
|
|
{
|
||
|
|
var board = new BoardBuilder(5, 5)
|
||
|
|
.WithProduction(0, 0, "P", CargoType.Wood, 2)
|
||
|
|
.WithDemand(4, 0, "D", CargoType.Wood, 1, 99)
|
||
|
|
.WithWall(3, 4)
|
||
|
|
.WithStock(PieceKind.Knight, 5)
|
||
|
|
.BuildState();
|
||
|
|
|
||
|
|
var moves = MoveValidator.GetLegalEndCells(PieceKind.Knight, new Coords(2, 2), board);
|
||
|
|
Assert.DoesNotContain(new Coords(3, 4), moves); // wall at target
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void StartCell_CannotBeWall()
|
||
|
|
{
|
||
|
|
var board = new BoardBuilder(5, 5)
|
||
|
|
.WithProduction(0, 0, "P", CargoType.Wood, 2)
|
||
|
|
.WithDemand(4, 0, "D", CargoType.Wood, 1, 99)
|
||
|
|
.WithWall(2, 2)
|
||
|
|
.WithStock(PieceKind.Rook, 5)
|
||
|
|
.BuildState();
|
||
|
|
|
||
|
|
var moves = MoveValidator.GetLegalEndCells(PieceKind.Rook, new Coords(2, 2), board);
|
||
|
|
Assert.Empty(moves);
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void EndCell_CanOverlapWithPiece()
|
||
|
|
{
|
||
|
|
var board = EmptyBoard();
|
||
|
|
board.Pieces.Add(new PieceState(99, PieceKind.Rook, new Coords(3, 2), new Coords(4, 2), 0));
|
||
|
|
|
||
|
|
var moves = MoveValidator.GetLegalEndCells(PieceKind.Rook, new Coords(2, 2), board);
|
||
|
|
// Pieces can share relay points — collisions are detected at runtime
|
||
|
|
Assert.Contains(new Coords(3, 2), moves);
|
||
|
|
Assert.Contains(new Coords(4, 2), moves);
|
||
|
|
}
|
||
|
|
}
|