Chessistics/chessistics-tests/Rules/MoveValidatorTests.cs

217 lines
8.1 KiB
C#
Raw Permalink Normal View History

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)
.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)
.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)
.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)
.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)
.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)
.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)
.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);
}
}