Check mate implementation
This commit is contained in:
@@ -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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user