Check mate implementation
This commit is contained in:
@@ -1,13 +1,10 @@
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Identity;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Shogi.Api.Application;
|
using Shogi.Api.Application;
|
||||||
using Shogi.Api.Extensions;
|
using Shogi.Api.Extensions;
|
||||||
using Shogi.Api.Identity;
|
|
||||||
using Shogi.Api.Repositories;
|
using Shogi.Api.Repositories;
|
||||||
using Shogi.Contracts.Api;
|
using Shogi.Contracts.Api;
|
||||||
using Shogi.Contracts.Types;
|
using Shogi.Contracts.Types;
|
||||||
using System.Security.Claims;
|
|
||||||
|
|
||||||
namespace Shogi.Api.Controllers;
|
namespace Shogi.Api.Controllers;
|
||||||
|
|
||||||
|
|||||||
@@ -6,17 +6,12 @@ namespace Shogi.Domain.ValueObjects;
|
|||||||
/// The board is always from Player1's perspective.
|
/// The board is always from Player1's perspective.
|
||||||
/// [0,0] is the lower-left position, [8,8] is the higher-right position
|
/// [0,0] is the lower-left position, [8,8] is the higher-right position
|
||||||
/// </summary>
|
/// </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 int[] zeroToEight = [0, 1, 2, 3, 4, 5, 6, 7, 8];
|
||||||
private static readonly Vector2 BoardSize = new(9, 9);
|
private static readonly Vector2 BoardSize = new(9, 9);
|
||||||
|
|
||||||
public ShogiBoard(BoardState initialState)
|
public BoardState BoardState { get; } = initialState;
|
||||||
{
|
|
||||||
BoardState = initialState;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BoardState BoardState { get; }
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -67,13 +62,29 @@ public sealed class ShogiBoard
|
|||||||
: inCheckResult.HasFlag(InCheckResult.Player1InCheck);
|
: inCheckResult.HasFlag(InCheckResult.Player1InCheck);
|
||||||
|
|
||||||
// Move is legal; mutate the real state.
|
// Move is legal; mutate the real state.
|
||||||
BoardState.Move(from, to, isPromotion);
|
|
||||||
if (playerPutOpponentInCheck)
|
if (playerPutOpponentInCheck)
|
||||||
{
|
{
|
||||||
BoardState.InCheck = BoardState.WhoseTurn == WhichPlayer.Player1
|
BoardState.InCheck = BoardState.WhoseTurn == WhichPlayer.Player1
|
||||||
? WhichPlayer.Player2
|
? WhichPlayer.Player2
|
||||||
: WhichPlayer.Player1;
|
: 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);
|
return new MoveResult(true);
|
||||||
}
|
}
|
||||||
@@ -154,24 +165,35 @@ public sealed class ShogiBoard
|
|||||||
: inCheckResult.HasFlag(InCheckResult.Player1InCheck);
|
: inCheckResult.HasFlag(InCheckResult.Player1InCheck);
|
||||||
|
|
||||||
// Move is legal; mutate the real state.
|
// Move is legal; mutate the real state.
|
||||||
BoardState.Move(pieceInHand, to);
|
|
||||||
if (playerPutOpponentInCheck)
|
if (playerPutOpponentInCheck)
|
||||||
{
|
{
|
||||||
BoardState.InCheck = BoardState.WhoseTurn == WhichPlayer.Player1
|
BoardState.InCheck = BoardState.WhoseTurn == WhichPlayer.Player1
|
||||||
? WhichPlayer.Player2
|
? WhichPlayer.Player2
|
||||||
: WhichPlayer.Player1;
|
: 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.
|
// A pawn, placed from the hand, cannot be the cause of checkmate.
|
||||||
// if (rules.IsOpponentInCheckMate() && pieceInHand != WhichPiece.Pawn)
|
if (BoardState.InCheck.HasValue && pieceInHand != WhichPiece.Pawn)
|
||||||
// {
|
{
|
||||||
// BoardState.IsCheckmate = true;
|
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);
|
return new MoveResult(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private GameOverResult EvaluateGameOver()
|
private GameOverResult EvaluateGameOver()
|
||||||
{
|
{
|
||||||
if (!BoardState.InCheck.HasValue)
|
if (!BoardState.InCheck.HasValue)
|
||||||
@@ -220,10 +242,17 @@ public sealed class ShogiBoard
|
|||||||
{
|
{
|
||||||
var list = new List<Vector2>(10);
|
var list = new List<Vector2>(10);
|
||||||
var position = path.Step + piecePosition;
|
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);
|
list.Add(position);
|
||||||
position += path.Step;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
@@ -292,7 +321,9 @@ public sealed class ShogiBoard
|
|||||||
{
|
{
|
||||||
return new MoveResult(false, $"There is no piece at position {from}.");
|
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())
|
if (!matchingPaths.Any())
|
||||||
{
|
{
|
||||||
return new MoveResult(false, "Piece cannot move like that.");
|
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.
|
// Assert that no pieces exist along the from -> to path.
|
||||||
var isPathObstructed = GetPositionsAlongPath(from, to, path)
|
var isPathObstructed = GetPositionsAlongPath(from, to, path)
|
||||||
|
.SkipLast(1)
|
||||||
.Any(pos => BoardState[pos] != null);
|
.Any(pos => BoardState[pos] != null);
|
||||||
if (isPathObstructed)
|
if (isPathObstructed)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -51,15 +51,15 @@ public static class Extensions
|
|||||||
for (var x = 0; x < 8; x++) builder.Append("- - ");
|
for (var x = 0; x < 8; x++) builder.Append("- - ");
|
||||||
builder.Append("- -");
|
builder.Append("- -");
|
||||||
builder.AppendLine();
|
builder.AppendLine();
|
||||||
builder.Append(" ");
|
|
||||||
builder.Append("Player 1");
|
|
||||||
|
|
||||||
builder.AppendLine();
|
|
||||||
builder.AppendLine();
|
|
||||||
// Print File ruler.
|
// Print File ruler.
|
||||||
builder.Append(" ");
|
builder.Append(" ");
|
||||||
builder.Append(" A B C D E F G H I ");
|
builder.Append(" A B C D E F G H I ");
|
||||||
|
|
||||||
|
builder.AppendLine();
|
||||||
|
builder.AppendLine();
|
||||||
|
builder.Append(" ");
|
||||||
|
builder.Append("Player 1");
|
||||||
|
|
||||||
return builder.ToString();
|
return builder.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -65,10 +65,11 @@ namespace UnitTests
|
|||||||
board["D5"].Should().BeNull();
|
board["D5"].Should().BeNull();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var act = () => shogi.Move("D5", "D6", false);
|
var moveResult = shogi.Move("D5", "D6", false);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
act.Should().Throw<InvalidOperationException>();
|
moveResult.Should().NotBeNull();
|
||||||
|
moveResult.IsSuccess.Should().BeFalse();
|
||||||
board["D5"].Should().BeNull();
|
board["D5"].Should().BeNull();
|
||||||
board["D6"].Should().BeNull();
|
board["D6"].Should().BeNull();
|
||||||
board.Player1Hand.Should().BeEmpty();
|
board.Player1Hand.Should().BeEmpty();
|
||||||
@@ -84,13 +85,13 @@ namespace UnitTests
|
|||||||
var expectedPiece = board["A3"];
|
var expectedPiece = board["A3"];
|
||||||
|
|
||||||
// Act - P1 "moves" pawn to the position it already exists at.
|
// Act - P1 "moves" pawn to the position it already exists at.
|
||||||
var act = () => shogi.Move("A3", "A3", false);
|
var moveResult = shogi.Move("A3", "A3", false);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
using (new AssertionScope())
|
using (new AssertionScope())
|
||||||
{
|
{
|
||||||
act.Should().Throw<InvalidOperationException>();
|
moveResult.Should().NotBeNull();
|
||||||
board["A3"].Should().Be(expectedPiece);
|
moveResult.IsSuccess.Should().BeFalse(); board["A3"].Should().Be(expectedPiece);
|
||||||
board.Player1Hand.Should().BeEmpty();
|
board.Player1Hand.Should().BeEmpty();
|
||||||
board.Player2Hand.Should().BeEmpty();
|
board.Player2Hand.Should().BeEmpty();
|
||||||
}
|
}
|
||||||
@@ -106,13 +107,13 @@ namespace UnitTests
|
|||||||
expectedPiece!.WhichPiece.Should().Be(WhichPiece.Lance);
|
expectedPiece!.WhichPiece.Should().Be(WhichPiece.Lance);
|
||||||
|
|
||||||
// Act - Move Lance illegally
|
// Act - Move Lance illegally
|
||||||
var act = () => shogi.Move("A1", "D5", false);
|
var moveResult = shogi.Move("A1", "D5", false);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
using (new AssertionScope())
|
using (new AssertionScope())
|
||||||
{
|
{
|
||||||
act.Should().Throw<InvalidOperationException>();
|
moveResult.Should().NotBeNull();
|
||||||
board["A1"].Should().Be(expectedPiece);
|
moveResult.IsSuccess.Should().BeFalse(); board["A1"].Should().Be(expectedPiece);
|
||||||
board["A5"].Should().BeNull();
|
board["A5"].Should().BeNull();
|
||||||
board.Player1Hand.Should().BeEmpty();
|
board.Player1Hand.Should().BeEmpty();
|
||||||
board.Player2Hand.Should().BeEmpty();
|
board.Player2Hand.Should().BeEmpty();
|
||||||
@@ -130,13 +131,13 @@ namespace UnitTests
|
|||||||
board.WhoseTurn.Should().Be(WhichPlayer.Player1);
|
board.WhoseTurn.Should().Be(WhichPlayer.Player1);
|
||||||
|
|
||||||
// Act - Move Player2 Pawn when it is Player1 turn.
|
// Act - Move Player2 Pawn when it is Player1 turn.
|
||||||
var act = () => shogi.Move("A7", "A6", false);
|
var moveResult = shogi.Move("A7", "A6", false);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
using (new AssertionScope())
|
using (new AssertionScope())
|
||||||
{
|
{
|
||||||
act.Should().Throw<InvalidOperationException>();
|
moveResult.Should().NotBeNull();
|
||||||
board["A7"].Should().Be(expectedPiece);
|
moveResult.IsSuccess.Should().BeFalse(); board["A7"].Should().Be(expectedPiece);
|
||||||
board["A6"].Should().BeNull();
|
board["A6"].Should().BeNull();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -152,13 +153,13 @@ namespace UnitTests
|
|||||||
lance!.Owner.Should().Be(pawn!.Owner);
|
lance!.Owner.Should().Be(pawn!.Owner);
|
||||||
|
|
||||||
// Act - Move P1 Lance through P1 Pawn.
|
// Act - Move P1 Lance through P1 Pawn.
|
||||||
var act = () => shogi.Move("A1", "A5", false);
|
var moveResult = shogi.Move("A1", "A5", false);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
using (new AssertionScope())
|
using (new AssertionScope())
|
||||||
{
|
{
|
||||||
act.Should().Throw<InvalidOperationException>();
|
moveResult.Should().NotBeNull();
|
||||||
board["A1"].Should().Be(lance);
|
moveResult.IsSuccess.Should().BeFalse(); board["A1"].Should().Be(lance);
|
||||||
board["A3"].Should().Be(pawn);
|
board["A3"].Should().Be(pawn);
|
||||||
board["A5"].Should().BeNull();
|
board["A5"].Should().BeNull();
|
||||||
}
|
}
|
||||||
@@ -175,13 +176,13 @@ namespace UnitTests
|
|||||||
knight!.Owner.Should().Be(pawn!.Owner);
|
knight!.Owner.Should().Be(pawn!.Owner);
|
||||||
|
|
||||||
// Act - P1 Knight tries to capture P1 Pawn.
|
// Act - P1 Knight tries to capture P1 Pawn.
|
||||||
var act = () => shogi.Move("B1", "C3", false);
|
var moveResult = shogi.Move("B1", "C3", false);
|
||||||
|
|
||||||
// Arrange
|
// Arrange
|
||||||
using (new AssertionScope())
|
using (new AssertionScope())
|
||||||
{
|
{
|
||||||
act.Should().Throw<InvalidOperationException>();
|
moveResult.Should().NotBeNull();
|
||||||
board["B1"].Should().Be(knight);
|
moveResult.IsSuccess.Should().BeFalse(); board["B1"].Should().Be(knight);
|
||||||
board["C3"].Should().Be(pawn);
|
board["C3"].Should().Be(pawn);
|
||||||
board.Player1Hand.Should().BeEmpty();
|
board.Player1Hand.Should().BeEmpty();
|
||||||
board.Player2Hand.Should().BeEmpty();
|
board.Player2Hand.Should().BeEmpty();
|
||||||
@@ -204,13 +205,13 @@ namespace UnitTests
|
|||||||
var lance = board["I9"];
|
var lance = board["I9"];
|
||||||
|
|
||||||
// Act - P2 moves Lance while in check.
|
// Act - P2 moves Lance while in check.
|
||||||
var act = () => shogi.Move("I9", "I8", false);
|
var moveResult = shogi.Move("I9", "I8", false);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
using (new AssertionScope())
|
using (new AssertionScope())
|
||||||
{
|
{
|
||||||
act.Should().Throw<InvalidOperationException>();
|
moveResult.Should().NotBeNull();
|
||||||
board.InCheck.Should().Be(WhichPlayer.Player2);
|
moveResult.IsSuccess.Should().BeFalse(); board.InCheck.Should().Be(WhichPlayer.Player2);
|
||||||
board["I9"].Should().Be(lance);
|
board["I9"].Should().Be(lance);
|
||||||
board["I8"].Should().BeNull();
|
board["I8"].Should().BeNull();
|
||||||
}
|
}
|
||||||
@@ -251,29 +252,33 @@ namespace UnitTests
|
|||||||
|
|
||||||
// Act | Assert - Illegally placing Knight from the hand in farthest rank.
|
// Act | Assert - Illegally placing Knight from the hand in farthest rank.
|
||||||
board["H9"].Should().BeNull();
|
board["H9"].Should().BeNull();
|
||||||
var act = () => shogi.Move(WhichPiece.Knight, "H9");
|
var moveResult = shogi.Move(WhichPiece.Knight, "H9");
|
||||||
act.Should().Throw<InvalidOperationException>();
|
moveResult.Should().NotBeNull();
|
||||||
|
moveResult.IsSuccess.Should().BeFalse();
|
||||||
board["H9"].Should().BeNull();
|
board["H9"].Should().BeNull();
|
||||||
board.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Knight);
|
board.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Knight);
|
||||||
|
|
||||||
// Act | Assert - Illegally placing Knight from the hand in second farthest row.
|
// Act | Assert - Illegally placing Knight from the hand in second farthest row.
|
||||||
board["H8"].Should().BeNull();
|
board["H8"].Should().BeNull();
|
||||||
act = () => shogi.Move(WhichPiece.Knight, "H8");
|
moveResult = shogi.Move(WhichPiece.Knight, "H8");
|
||||||
act.Should().Throw<InvalidOperationException>();
|
moveResult.Should().NotBeNull();
|
||||||
|
moveResult.IsSuccess.Should().BeFalse();
|
||||||
board["H8"].Should().BeNull();
|
board["H8"].Should().BeNull();
|
||||||
board.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Knight);
|
board.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Knight);
|
||||||
|
|
||||||
// Act | Assert - Illegally place Lance from the hand.
|
// Act | Assert - Illegally place Lance from the hand.
|
||||||
board["H9"].Should().BeNull();
|
board["H9"].Should().BeNull();
|
||||||
act = () => shogi.Move(WhichPiece.Knight, "H9");
|
moveResult = shogi.Move(WhichPiece.Knight, "H9");
|
||||||
act.Should().Throw<InvalidOperationException>();
|
moveResult.Should().NotBeNull();
|
||||||
|
moveResult.IsSuccess.Should().BeFalse();
|
||||||
board["H9"].Should().BeNull();
|
board["H9"].Should().BeNull();
|
||||||
board.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Lance);
|
board.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Lance);
|
||||||
|
|
||||||
// Act | Assert - Illegally place Pawn from the hand.
|
// Act | Assert - Illegally place Pawn from the hand.
|
||||||
board["H9"].Should().BeNull();
|
board["H9"].Should().BeNull();
|
||||||
act = () => shogi.Move(WhichPiece.Pawn, "H9");
|
moveResult = shogi.Move(WhichPiece.Pawn, "H9");
|
||||||
act.Should().Throw<InvalidOperationException>();
|
moveResult.Should().NotBeNull();
|
||||||
|
moveResult.IsSuccess.Should().BeFalse();
|
||||||
board["H9"].Should().BeNull();
|
board["H9"].Should().BeNull();
|
||||||
board.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Pawn);
|
board.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Pawn);
|
||||||
|
|
||||||
@@ -305,11 +310,12 @@ namespace UnitTests
|
|||||||
shogi.BoardState["E5"].Should().BeNull();
|
shogi.BoardState["E5"].Should().BeNull();
|
||||||
|
|
||||||
// Act - P2 places a Bishop while in check.
|
// Act - P2 places a Bishop while in check.
|
||||||
var act = () => shogi.Move(WhichPiece.Bishop, "E5");
|
var moveResult = shogi.Move(WhichPiece.Bishop, "E5");
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
using var scope = new AssertionScope();
|
using var scope = new AssertionScope();
|
||||||
act.Should().Throw<InvalidOperationException>();
|
moveResult.Should().NotBeNull();
|
||||||
|
moveResult.IsSuccess.Should().BeFalse();
|
||||||
shogi.BoardState["E5"].Should().BeNull();
|
shogi.BoardState["E5"].Should().BeNull();
|
||||||
shogi.BoardState.InCheck.Should().Be(WhichPlayer.Player2);
|
shogi.BoardState.InCheck.Should().Be(WhichPlayer.Player2);
|
||||||
shogi.BoardState.Player2Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Bishop);
|
shogi.BoardState.Player2Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Bishop);
|
||||||
@@ -334,11 +340,12 @@ namespace UnitTests
|
|||||||
shogi.BoardState["I9"]!.Owner.Should().Be(WhichPlayer.Player2);
|
shogi.BoardState["I9"]!.Owner.Should().Be(WhichPlayer.Player2);
|
||||||
|
|
||||||
// Act - P1 tries to place a piece where an opponent's piece resides.
|
// Act - P1 tries to place a piece where an opponent's piece resides.
|
||||||
var act = () => shogi.Move(WhichPiece.Bishop, "I9");
|
var moveResult = shogi.Move(WhichPiece.Bishop, "I9");
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
using var scope = new AssertionScope();
|
using var scope = new AssertionScope();
|
||||||
act.Should().Throw<InvalidOperationException>();
|
moveResult.Should().NotBeNull();
|
||||||
|
moveResult.IsSuccess.Should().BeFalse();
|
||||||
shogi.BoardState.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Bishop);
|
shogi.BoardState.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Bishop);
|
||||||
shogi.BoardState["I9"].Should().NotBeNull();
|
shogi.BoardState["I9"].Should().NotBeNull();
|
||||||
shogi.BoardState["I9"]!.WhichPiece.Should().Be(WhichPiece.Lance);
|
shogi.BoardState["I9"]!.WhichPiece.Should().Be(WhichPiece.Lance);
|
||||||
@@ -439,12 +446,13 @@ namespace UnitTests
|
|||||||
// P2 King retreat
|
// P2 King retreat
|
||||||
shogi.Move("E8", "E9", false);
|
shogi.Move("E8", "E9", false);
|
||||||
|
|
||||||
|
console.WriteLine(shogi.ToStringStateAsAscii());
|
||||||
|
|
||||||
|
|
||||||
// Act - P1 Pawn wins by checkmate.
|
// Act - P1 Pawn wins by checkmate.
|
||||||
shogi.Move("E7", "E8", false);
|
shogi.Move("E7", "E8", false);
|
||||||
|
|
||||||
// Assert - checkmate
|
// Assert - checkmate
|
||||||
console.WriteLine(shogi.ToStringStateAsAscii());
|
|
||||||
console.WriteLine(string.Join(",", shogi.BoardState.Player1Hand.Select(p => p.WhichPiece.ToString())));
|
|
||||||
board.IsCheckmate.Should().BeTrue();
|
board.IsCheckmate.Should().BeTrue();
|
||||||
board.InCheck.Should().Be(WhichPlayer.Player2);
|
board.InCheck.Should().Be(WhichPlayer.Player2);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user