This commit is contained in:
2022-01-29 10:07:53 -06:00
parent 499e480851
commit f79a1312c7
4 changed files with 190 additions and 161 deletions

View File

@@ -75,181 +75,195 @@ namespace Shogi.Domain.UnitTests
board["D6"].Should().BeNull(); board["D6"].Should().BeNull();
} }
//[Fact] [Fact]
//public void PreventInvalidMoves_MoveToCurrentPosition() public void PreventInvalidMoves_MoveToCurrentPosition()
//{ {
// // Arrange // Arrange
// var shogi = new Shogi(); var board = new ShogiBoardState();
var shogi = new Shogi(board);
// // Act - P1 "moves" pawn to the position it already exists at. // Act - P1 "moves" pawn to the position it already exists at.
// var moveSuccess = shogi.Move(new Move("A3", "A3")); var act = () => shogi.Move("A3", "A3", false);
// // Assert // Assert
// moveSuccess.Should().BeFalse(); act.Should().Throw<InvalidOperationException>();
// shogi.Board["A3"].WhichPiece.Should().Be(WhichPiece.Pawn); board["A3"].Should().NotBeNull();
// shogi.Player1Hand.Should().BeEmpty(); board["A3"]!.WhichPiece.Should().Be(WhichPiece.Pawn);
// shogi.Player2Hand.Should().BeEmpty(); board.Player1Hand.Should().BeEmpty();
//} board.Player2Hand.Should().BeEmpty();
}
//[Fact] [Fact]
//public void PreventInvalidMoves_MoveSet() public void PreventInvalidMoves_MoveSet()
//{ {
// // Arrange // Arrange
// var shogi = new Shogi(); var board = new ShogiBoardState();
var shogi = new Shogi(board);
// // Act - Move Lance illegally // Act - Move Lance illegally
// var moveSuccess = shogi.Move(new Move("A1", "D5")); var act = () => shogi.Move("A1", "D5", false);
// // Assert // Assert
// moveSuccess.Should().BeFalse(); act.Should().Throw<InvalidOperationException>();
// shogi.Board["A1"].WhichPiece.Should().Be(WhichPiece.Lance); board["A1"].Should().NotBeNull();
// shogi.Board["A5"].Should().BeNull(); board["A1"]!.WhichPiece.Should().Be(WhichPiece.Lance);
// shogi.Player1Hand.Should().BeEmpty(); board["A5"].Should().BeNull();
// shogi.Player2Hand.Should().BeEmpty(); board.Player1Hand.Should().BeEmpty();
//} board.Player2Hand.Should().BeEmpty();
}
//[Fact] [Fact]
//public void PreventInvalidMoves_Ownership() public void PreventInvalidMoves_Ownership()
//{ {
// // Arrange // Arrange
// var shogi = new Shogi(); var board = new ShogiBoardState();
// shogi.WhoseTurn.Should().Be(WhichPlayer.Player1); var shogi = new Shogi(board);
// shogi.Board["A7"].Owner.Should().Be(WhichPlayer.Player2); board.WhoseTurn.Should().Be(WhichPlayer.Player1);
board["A7"].Should().NotBeNull();
board["A7"]!.Owner.Should().Be(WhichPlayer.Player2);
// // Act - Move Player2 Pawn when it is Player1 turn. // Act - Move Player2 Pawn when it is Player1 turn.
// var moveSuccess = shogi.Move(new Move("A7", "A6")); var act = () => shogi.Move("A7", "A6", false);
// // Assert // Assert
// moveSuccess.Should().BeFalse(); act.Should().Throw<InvalidOperationException>();
// shogi.Board["A7"].WhichPiece.Should().Be(WhichPiece.Pawn); board["A7"].Should().NotBeNull();
// shogi.Board["A6"].Should().BeNull(); board["A7"]!.WhichPiece.Should().Be(WhichPiece.Pawn);
//} board["A6"].Should().BeNull();
}
//[Fact] [Fact]
//public void PreventInvalidMoves_MoveThroughAllies() public void PreventInvalidMoves_MoveThroughAllies()
//{ {
// // Arrange // Arrange
// var shogi = new Shogi(); var board = new ShogiBoardState();
var shogi = new Shogi(board);
// // Act - Move P1 Lance through P1 Pawn. // Act - Move P1 Lance through P1 Pawn.
// var moveSuccess = shogi.Move(new Move("A1", "A5")); var act = () => shogi.Move("A1", "A5", false);
// // Assert // Assert
// moveSuccess.Should().BeFalse(); act.Should().Throw<InvalidOperationException>();
// shogi.Board["A1"].WhichPiece.Should().Be(WhichPiece.Lance); board["A1"].Should().NotBeNull();
// shogi.Board["A3"].WhichPiece.Should().Be(WhichPiece.Pawn); board["A1"]!.WhichPiece.Should().Be(WhichPiece.Lance);
// shogi.Board["A5"].Should().BeNull(); board["A3"].Should().NotBeNull();
//} board["A3"]!.WhichPiece.Should().Be(WhichPiece.Pawn);
board["A5"].Should().BeNull();
}
//[Fact] [Fact]
//public void PreventInvalidMoves_CaptureAlly() public void PreventInvalidMoves_CaptureAlly()
//{ {
// // Arrange // Arrange
// var shogi = new Shogi(); var board = new ShogiBoardState();
var shogi = new Shogi(board);
// // Act - P1 Knight tries to capture P1 Pawn. // Act - P1 Knight tries to capture P1 Pawn.
// var moveSuccess = shogi.Move(new Move("B1", "C3")); var act = () => shogi.Move("B1", "C3", false);
// // Arrange // Arrange
// moveSuccess.Should().BeFalse(); act.Should().Throw<InvalidOperationException>();
// shogi.Board["B1"].WhichPiece.Should().Be(WhichPiece.Knight); board["B1"].Should().NotBeNull();
// shogi.Board["C3"].WhichPiece.Should().Be(WhichPiece.Pawn); board["B1"]!.WhichPiece.Should().Be(WhichPiece.Knight);
// shogi.Player1Hand.Should().BeEmpty(); board["C3"].Should().NotBeNull();
// shogi.Player2Hand.Should().BeEmpty(); board["C3"]!.WhichPiece.Should().Be(WhichPiece.Pawn);
//} board.Player1Hand.Should().BeEmpty();
board.Player2Hand.Should().BeEmpty();
}
//[Fact] [Fact]
//public void PreventInvalidMoves_Check() public void PreventInvalidMoves_Check()
//{ {
// // Arrange // Arrange
// var moves = new[] var board = new ShogiBoardState();
// { var shogi = new Shogi(board);
// // P1 Pawn // P1 Pawn
// new Move("C3", "C4"), shogi.Move("C3", "C4", false);
// // P2 Pawn // P2 Pawn
// new Move("G7", "G6"), shogi.Move("G7", "G6", false);
// // P1 Bishop puts P2 in check // P1 Bishop puts P2 in check
// new Move("B2", "G7") shogi.Move("B2", "G7", false);
// }; board.InCheck.Should().Be(WhichPlayer.Player2);
// var shogi = new Shogi(moves);
// shogi.InCheck.Should().Be(WhichPlayer.Player2);
// // Act - P2 moves Lance while in check. // Act - P2 moves Lance while in check.
// var moveSuccess = shogi.Move(new Move("I9", "I8")); var act = () => shogi.Move("I9", "I8", false);
// // Assert // Assert
// moveSuccess.Should().BeFalse(); act.Should().Throw<InvalidOperationException>();
// shogi.InCheck.Should().Be(WhichPlayer.Player2); board.InCheck.Should().Be(WhichPlayer.Player2);
// shogi.Board["I9"].WhichPiece.Should().Be(WhichPiece.Lance); board["I9"].Should().NotBeNull();
// shogi.Board["I8"].Should().BeNull(); board["I9"]!.WhichPiece.Should().Be(WhichPiece.Lance);
//} board["I8"].Should().BeNull();
}
//[Fact] [Fact]
//public void PreventInvalidDrops_MoveSet() public void PreventInvalidDrops_MoveSet()
//{ {
// // Arrange // Arrange
// var moves = new[] var board = new ShogiBoardState();
// { var shogi = new Shogi(board);
// // P1 Pawn
// new Move("C3", "C4"),
// // P2 Pawn
// new Move("I7", "I6"),
// // P1 Bishop takes P2 Pawn.
// new Move("B2", "G7"),
// // P2 Gold, block check from P1 Bishop.
// new Move("F9", "F8"),
// // P1 Bishop takes P2 Bishop, promotes so it can capture P2 Knight and P2 Lance
// new Move("G7", "H8", true),
// // P2 Pawn again
// new Move("I6", "I5"),
// // P1 Bishop takes P2 Knight
// new Move("H8", "H9"),
// // P2 Pawn again
// new Move("I5", "I4"),
// // P1 Bishop takes P2 Lance
// new Move("H9", "I9"),
// // P2 Pawn captures P1 Pawn
// new Move("I4", "I3")
// };
// var shogi = new Shogi(moves);
// shogi.Player1Hand.Count.Should().Be(4);
// shogi.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Knight);
// shogi.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Lance);
// shogi.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Pawn);
// shogi.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Bishop);
// shogi.WhoseTurn.Should().Be(WhichPlayer.Player1);
// // Act | Assert - Illegally placing Knight from the hand in farthest row.
// shogi.Board["H9"].Should().BeNull();
// var dropSuccess = shogi.Move(new Move(WhichPiece.Knight, "H9"));
// dropSuccess.Should().BeFalse();
// shogi.Board["H9"].Should().BeNull();
// shogi.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Knight);
// // Act | Assert - Illegally placing Knight from the hand in second farthest row. // P1 Pawn
// shogi.Board["H8"].Should().BeNull(); shogi.Move("C3", "C4", false);
// dropSuccess = shogi.Move(new Move(WhichPiece.Knight, "H8")); // P2 Pawn
// dropSuccess.Should().BeFalse(); shogi.Move("I7", "I6", false);
// shogi.Board["H8"].Should().BeNull(); // P1 Bishop takes P2 Pawn.
// shogi.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Knight); shogi.Move("B2", "G7", false);
// P2 Gold, block check from P1 Bishop.
shogi.Move("F9", "F8", false);
// P1 Bishop takes P2 Bishop, promotes so it can capture P2 Knight and P2 Lance
shogi.Move("G7", "H8", true);
// P2 Pawn again
shogi.Move("I6", "I5", false);
// P1 Bishop takes P2 Knight
shogi.Move("H8", "H9", false);
// P2 Pawn again
shogi.Move("I5", "I4", false);
// P1 Bishop takes P2 Lance
shogi.Move("H9", "I9", false);
// P2 Pawn captures P1 Pawn
shogi.Move("I4", "I3", false);
// // Act | Assert - Illegally place Lance from the hand. board.Player1Hand.Count.Should().Be(4);
// shogi.Board["H9"].Should().BeNull(); board.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Knight);
// dropSuccess = shogi.Move(new Move(WhichPiece.Knight, "H9")); board.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Lance);
// dropSuccess.Should().BeFalse(); board.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Pawn);
// shogi.Board["H9"].Should().BeNull(); board.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Bishop);
// shogi.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Lance); board.WhoseTurn.Should().Be(WhichPlayer.Player1);
// // Act | Assert - Illegally place Pawn from the hand. // Act | Assert - Illegally placing Knight from the hand in farthest row.
// shogi.Board["H9"].Should().BeNull(); board["H9"].Should().BeNull();
// dropSuccess = shogi.Move(new Move(WhichPiece.Pawn, "H9")); shogi.Move()
// dropSuccess.Should().BeFalse(); var dropSuccess = shogi.Move(new Move(WhichPiece.Knight, "H9"));
// shogi.Board["H9"].Should().BeNull(); dropSuccess.Should().BeFalse();
// shogi.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Pawn); shogi.Board["H9"].Should().BeNull();
shogi.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Knight);
// // Act | Assert - Illegally place Pawn from the hand in a row which already has an unpromoted Pawn. // Act | Assert - Illegally placing Knight from the hand in second farthest row.
// // TODO shogi.Board["H8"].Should().BeNull();
//} dropSuccess = shogi.Move(new Move(WhichPiece.Knight, "H8"));
dropSuccess.Should().BeFalse();
shogi.Board["H8"].Should().BeNull();
shogi.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Knight);
// Act | Assert - Illegally place Lance from the hand.
shogi.Board["H9"].Should().BeNull();
dropSuccess = shogi.Move(new Move(WhichPiece.Knight, "H9"));
dropSuccess.Should().BeFalse();
shogi.Board["H9"].Should().BeNull();
shogi.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Lance);
// Act | Assert - Illegally place Pawn from the hand.
shogi.Board["H9"].Should().BeNull();
dropSuccess = shogi.Move(new Move(WhichPiece.Pawn, "H9"));
dropSuccess.Should().BeFalse();
shogi.Board["H9"].Should().BeNull();
shogi.Player1Hand.Should().ContainSingle(_ => _.WhichPiece == WhichPiece.Pawn);
// Act | Assert - Illegally place Pawn from the hand in a row which already has an unpromoted Pawn.
// TODO
}
//[Fact] //[Fact]
//public void PreventInvalidDrop_Check() //public void PreventInvalidDrop_Check()

View File

@@ -43,16 +43,24 @@
public void Move(string from, string to, bool isPromotion) public void Move(string from, string to, bool isPromotion)
{ {
var fromVector = ShogiBoardState.FromBoardNotation(from); var tempBoard = new ShogiBoardState(board);
var toVector = ShogiBoardState.FromBoardNotation(to); var simulation = new StandardRules(tempBoard);
var moveResult = rules.Move(from, to, isPromotion); var moveResult = simulation.Move(from, to, isPromotion);
if (!moveResult.Success) if (!moveResult.Success)
{ {
throw new InvalidOperationException(moveResult.Reason); throw new InvalidOperationException(moveResult.Reason);
} }
var fromVector = ShogiBoardState.FromBoardNotation(from);
var toVector = ShogiBoardState.FromBoardNotation(to);
var otherPlayer = board.WhoseTurn == WhichPlayer.Player1 ? WhichPlayer.Player2 : WhichPlayer.Player1; var otherPlayer = board.WhoseTurn == WhichPlayer.Player1 ? WhichPlayer.Player2 : WhichPlayer.Player1;
if (rules.EvaluateCheckAfterMove(fromVector, toVector, otherPlayer)) if (simulation.IsPlayerInCheckAfterMove(fromVector, toVector, board.WhoseTurn))
{
throw new InvalidOperationException("Illegal move. This move places you in check.");
}
rules.Move(from, to, isPromotion);
if (rules.IsPlayerInCheckAfterMove(fromVector, toVector, otherPlayer))
{ {
board.InCheck = otherPlayer; board.InCheck = otherPlayer;
board.IsCheckmate = rules.EvaluateCheckmate(); board.IsCheckmate = rules.EvaluateCheckmate();
@@ -64,6 +72,10 @@
board.WhoseTurn = otherPlayer; board.WhoseTurn = otherPlayer;
} }
public void Move(WhichPiece pieceInHand, string to)
{
}
///// <summary> ///// <summary>
///// Attempts a given move. Returns false if the move is illegal. ///// Attempts a given move. Returns false if the move is illegal.
///// </summary> ///// </summary>

View File

@@ -42,6 +42,9 @@ namespace Shogi.Domain
{ {
board[kvp.Key] = kvp.Value == null ? null : new Piece(kvp.Value); board[kvp.Key] = kvp.Value == null ? null : new Piece(kvp.Value);
} }
WhoseTurn = other.WhoseTurn;
InCheck = other.InCheck;
IsCheckmate = other.IsCheckmate;
MoveHistory.AddRange(other.MoveHistory); MoveHistory.AddRange(other.MoveHistory);
Player1Hand.AddRange(other.Player1Hand); Player1Hand.AddRange(other.Player1Hand);
Player2Hand.AddRange(other.Player2Hand); Player2Hand.AddRange(other.Player2Hand);

View File

@@ -39,11 +39,11 @@ namespace Shogi.Domain
} }
/// <summary> /// <summary>
/// Move a piece from a board tile to another board tile. /// Move a piece from a board tile to another board tile ignorant of check or check-mate.
/// </summary> /// </summary>
/// <param name="fromNotation">The position of the piece being moved expressed in board notation.</param> /// <param name="fromNotation">The position of the piece being moved expressed in board notation.</param>
/// <param name="toNotation">The target position expressed in board notation.</param> /// <param name="toNotation">The target position expressed in board notation.</param>
/// <returns>A <see cref="MoveResult" /> describing the success or failure of the simulation.</returns> /// <returns>A <see cref="MoveResult" /> describing the success or failure of the move.</returns>
public MoveResult Move(string fromNotation, string toNotation, bool isPromotion = false) public MoveResult Move(string fromNotation, string toNotation, bool isPromotion = false)
{ {
var from = ShogiBoardState.FromBoardNotation(fromNotation); var from = ShogiBoardState.FromBoardNotation(fromNotation);
@@ -105,7 +105,7 @@ namespace Shogi.Domain
} }
/// <summary> /// <summary>
/// Move a piece from the hand to the board. /// Move a piece from the hand to the board ignorant if check or check-mate.
/// </summary> /// </summary>
/// <param name="pieceInHand"></param> /// <param name="pieceInHand"></param>
/// <param name="to">The target position expressed in board notation.</param> /// <param name="to">The target position expressed in board notation.</param>
@@ -184,7 +184,7 @@ namespace Shogi.Domain
return isCheck; return isCheck;
} }
public bool EvaluateCheckAfterMove(Vector2 from, Vector2 to, WhichPlayer whichPlayer) public bool IsPlayerInCheckAfterMove(Vector2 from, Vector2 to, WhichPlayer whichPlayer)
{ {
if (whichPlayer == board.InCheck) return true; // If we already know the player is in check, don't bother. if (whichPlayer == board.InCheck) return true; // If we already know the player is in check, don't bother.
@@ -265,7 +265,7 @@ namespace Shogi.Domain
var simulationResult = simulationBoard.Move(fromNotation, toNotation, false); var simulationResult = simulationBoard.Move(fromNotation, toNotation, false);
if (simulationResult.Success) if (simulationResult.Success)
{ {
if (!EvaluateCheckAfterMove(from, position, board.InCheck.Value)) if (!IsPlayerInCheckAfterMove(from, position, board.InCheck.Value))
{ {
isCheckmate = false; isCheckmate = false;
} }