Check mate implementation

This commit is contained in:
2024-10-28 19:21:16 -05:00
parent a3d6065e95
commit a7e26f5210
4 changed files with 96 additions and 59 deletions

View File

@@ -6,17 +6,12 @@ namespace Shogi.Domain.ValueObjects;
/// The board is always from Player1's perspective.
/// [0,0] is the lower-left position, [8,8] is the higher-right position
/// </summary>
public sealed class ShogiBoard
public sealed class ShogiBoard(BoardState initialState)
{
private static readonly int[] zeroToEight = [0, 1, 2, 3, 4, 5, 6, 7, 8];
private static readonly Vector2 BoardSize = new(9, 9);
public ShogiBoard(BoardState initialState)
{
BoardState = initialState;
}
public BoardState BoardState { get; }
public BoardState BoardState { get; } = initialState;
/// <summary>
@@ -67,13 +62,29 @@ public sealed class ShogiBoard
: inCheckResult.HasFlag(InCheckResult.Player1InCheck);
// Move is legal; mutate the real state.
BoardState.Move(from, to, isPromotion);
if (playerPutOpponentInCheck)
{
BoardState.InCheck = BoardState.WhoseTurn == WhichPlayer.Player1
? WhichPlayer.Player2
: WhichPlayer.Player1;
}
else if (inCheckResult == InCheckResult.NobodyInCheck)
{
BoardState.InCheck = null;
}
BoardState.Move(from, to, isPromotion);
if (BoardState.InCheck.HasValue)
{
var gameOverResult = EvaluateGameOver();
BoardState.IsCheckmate = gameOverResult switch
{
GameOverResult.GameIsNotOver => false,
GameOverResult.Player1Wins => true,
GameOverResult.Player2Wins => true,
_ => throw new InvalidOperationException("Unexpected GameOverResult value.")
};
}
return new MoveResult(true);
}
@@ -154,24 +165,35 @@ public sealed class ShogiBoard
: inCheckResult.HasFlag(InCheckResult.Player1InCheck);
// Move is legal; mutate the real state.
BoardState.Move(pieceInHand, to);
if (playerPutOpponentInCheck)
{
BoardState.InCheck = BoardState.WhoseTurn == WhichPlayer.Player1
? WhichPlayer.Player2
: WhichPlayer.Player1;
}
else if (inCheckResult == InCheckResult.NobodyInCheck)
{
BoardState.InCheck = null;
}
BoardState.Move(pieceInHand, to);
// A pawn, placed from the hand, cannot be the cause of checkmate.
// if (rules.IsOpponentInCheckMate() && pieceInHand != WhichPiece.Pawn)
// {
// BoardState.IsCheckmate = true;
// }
if (BoardState.InCheck.HasValue && pieceInHand != WhichPiece.Pawn)
{
var gameOverResult = EvaluateGameOver();
BoardState.IsCheckmate = gameOverResult switch
{
GameOverResult.GameIsNotOver => false,
GameOverResult.Player1Wins => true,
GameOverResult.Player2Wins => true,
_ => throw new InvalidOperationException("Unexpected GameOverResult value.")
};
}
return new MoveResult(true);
}
private GameOverResult EvaluateGameOver()
{
if (!BoardState.InCheck.HasValue)
@@ -220,10 +242,17 @@ public sealed class ShogiBoard
{
var list = new List<Vector2>(10);
var position = path.Step + piecePosition;
while (position.IsInsideBoardBoundary())
if (path.Distance == YetToBeAssimilatedIntoDDD.Pathing.Distance.MultiStep)
{
while (position.IsInsideBoardBoundary())
{
list.Add(position);
position += path.Step;
}
} else if (position.IsInsideBoardBoundary())
{
list.Add(position);
position += path.Step;
}
return list;
@@ -292,7 +321,9 @@ public sealed class ShogiBoard
{
return new MoveResult(false, $"There is no piece at position {from}.");
}
var matchingPaths = piece.MoveSet.Where(p => p.NormalizedStep == Vector2.Normalize(to - from));
var clampedFromTo = Vector2.Clamp(to - from, -Vector2.One, Vector2.One);
var matchingPaths = piece.MoveSet.Where(p => p.Step == clampedFromTo);
if (!matchingPaths.Any())
{
return new MoveResult(false, "Piece cannot move like that.");
@@ -303,6 +334,7 @@ public sealed class ShogiBoard
{
// Assert that no pieces exist along the from -> to path.
var isPathObstructed = GetPositionsAlongPath(from, to, path)
.SkipLast(1)
.Any(pos => BoardState[pos] != null);
if (isPathObstructed)
{