using Shogi.BackEnd.Domains.ValueObjects; using Shogi.BackEnd.Domains.ValueObjects.Rules; namespace UnitTests; public class ShogiShould { [Fact] public void MoveAPieceToAnEmptyPosition() { // Arrange var shogi = MockShogiBoard(); var board = shogi.BoardState; Assert.Null(board["A4"]); var expectedPiece = board["A3"]; Assert.NotNull(expectedPiece); // Act shogi.Move("A3", "A4", false); // Assert Assert.Null(board["A3"]); Assert.Equal(expectedPiece, board["A4"]); } [Fact] public void AllowValidMoves_AfterCheck() { // Arrange var shogi = MockShogiBoard(); var board = shogi.BoardState; // P1 Pawn shogi.Move("C3", "C4", false); // P2 Pawn shogi.Move("G7", "G6", false); // P1 Bishop puts P2 in check shogi.Move("B2", "G7", false); Assert.Equal(WhichPlayer.Player2, board.InCheck); // Act - P2 is able to un-check theirself. /// P2 King moves out of check shogi.Move("E9", "E8", false); // Assert Assert.Null(board.InCheck); } [Fact] public void PreventInvalidMoves_MoveFromEmptyPosition() { // Arrange var shogi = MockShogiBoard(); var board = shogi.BoardState; Assert.Null(board["D5"]); // Act var moveResult = shogi.Move("D5", "D6", false); // Assert Assert.NotNull(moveResult); Assert.False(moveResult.IsSuccess); Assert.Null(board["D5"]); Assert.Null(board["D6"]); Assert.Empty(board.Player1Hand); Assert.Empty(board.Player2Hand); } [Fact] public void PreventInvalidMoves_MoveToCurrentPosition() { // Arrange var shogi = MockShogiBoard(); var board = shogi.BoardState; var expectedPiece = board["A3"]; // Act - P1 "moves" pawn to the position it already exists at. var moveResult = shogi.Move("A3", "A3", false); // Assert Assert.NotNull(moveResult); Assert.False(moveResult.IsSuccess); Assert.Equal(expectedPiece, board["A3"]); Assert.Empty(board.Player1Hand); Assert.Empty(board.Player2Hand); } [Fact] public void PreventInvalidMoves_MoveSet() { // Arrange var shogi = MockShogiBoard(); var board = shogi.BoardState; var expectedPiece = board["D1"]; Assert.Equal(WhichPiece.GoldGeneral, expectedPiece!.WhichPiece); // Act - Move General illegally var moveResult = shogi.Move("D1", "D5", false); // Assert Assert.NotNull(moveResult); Assert.False(moveResult.IsSuccess); Assert.Equal(expectedPiece, board["D1"]); Assert.Null(board["D5"]); Assert.Empty(board.Player1Hand); Assert.Empty(board.Player2Hand); } [Fact] public void PreventInvalidMoves_Ownership() { // Arrange var shogi = MockShogiBoard(); var board = shogi.BoardState; var expectedPiece = board["A7"]; Assert.Equal(WhichPlayer.Player2, expectedPiece!.Owner); Assert.Equal(WhichPlayer.Player1, board.WhoseTurn); // Act - Move Player2 Pawn when it is Player1 turn. var moveResult = shogi.Move("A7", "A6", false); // Assert Assert.NotNull(moveResult); Assert.False(moveResult.IsSuccess); Assert.Equal(expectedPiece, board["A7"]); Assert.Null(board["A6"]); } [Fact] public void PreventInvalidMoves_MoveThroughAllies() { // Arrange var shogi = MockShogiBoard(); var board = shogi.BoardState; var lance = board["A1"]; var pawn = board["A3"]; Assert.Equal(lance!.Owner, pawn!.Owner); // Act - Move P1 Lance through P1 Pawn. var moveResult = shogi.Move("A1", "A5", false); // Assert Assert.NotNull(moveResult); Assert.False(moveResult.IsSuccess); Assert.Equal(lance, board["A1"]); Assert.Equal(pawn, board["A3"]); Assert.Null(board["A5"]); } [Fact] public void PreventInvalidMoves_CaptureAlly() { // Arrange var shogi = MockShogiBoard(); var board = shogi.BoardState; var knight = board["B1"]; var pawn = board["C3"]; Assert.Equal(knight!.Owner, pawn!.Owner); // Act - P1 Knight tries to capture P1 Pawn. var moveResult = shogi.Move("B1", "C3", false); // Assert Assert.NotNull(moveResult); Assert.False(moveResult.IsSuccess); Assert.Equal(knight, board["B1"]); Assert.Equal(pawn, board["C3"]); Assert.Empty(board.Player1Hand); Assert.Empty(board.Player2Hand); } [Fact] public void PreventInvalidMoves_Check() { // Arrange var shogi = MockShogiBoard(); var board = shogi.BoardState; // P1 Pawn shogi.Move("C3", "C4", false); // P2 Pawn shogi.Move("G7", "G6", false); // P1 Bishop puts P2 in check shogi.Move("B2", "G7", false); Assert.Equal(WhichPlayer.Player2, board.InCheck); var lance = board["I9"]; // Act - P2 moves Lance while in check. var moveResult = shogi.Move("I9", "I8", false); // Assert Assert.NotNull(moveResult); Assert.False(moveResult.IsSuccess); Assert.Equal(WhichPlayer.Player2, board.InCheck); Assert.Equal(lance, board["I9"]); Assert.Null(board["I8"]); } [Fact] public void PreventInvalidDrops_MoveSet() { // Arrange var shogi = MockShogiBoard(); var board = shogi.BoardState; // P1 Pawn shogi.Move("C3", "C4", false); // P2 Pawn shogi.Move("I7", "I6", false); // P1 Bishop takes P2 Pawn. 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); Assert.Equal(4, board.Player1Hand.Count); Assert.Single(board.Player1Hand, p => p.WhichPiece == WhichPiece.Knight); Assert.Single(board.Player1Hand, p => p.WhichPiece == WhichPiece.Lance); Assert.Single(board.Player1Hand, p => p.WhichPiece == WhichPiece.Pawn); Assert.Single(board.Player1Hand, p => p.WhichPiece == WhichPiece.Bishop); Assert.Equal(WhichPlayer.Player1, board.WhoseTurn); // Act | Assert - Illegally placing Knight from the hand in farthest rank. Assert.Null(board["H9"]); var moveResult = shogi.Move(WhichPiece.Knight, "H9"); Assert.NotNull(moveResult); Assert.False(moveResult.IsSuccess); Assert.Null(board["H9"]); Assert.Single(board.Player1Hand, p => p.WhichPiece == WhichPiece.Knight); // Act | Assert - Illegally placing Knight from the hand in second farthest row. Assert.Null(board["H8"]); moveResult = shogi.Move(WhichPiece.Knight, "H8"); Assert.NotNull(moveResult); Assert.False(moveResult.IsSuccess); Assert.Null(board["H8"]); Assert.Single(board.Player1Hand, p => p.WhichPiece == WhichPiece.Knight); // Act | Assert - Illegally place Lance from the hand. Assert.Null(board["H9"]); moveResult = shogi.Move(WhichPiece.Knight, "H9"); Assert.NotNull(moveResult); Assert.False(moveResult.IsSuccess); Assert.Null(board["H9"]); Assert.Single(board.Player1Hand, p => p.WhichPiece == WhichPiece.Lance); // Act | Assert - Illegally place Pawn from the hand. Assert.Null(board["H9"]); moveResult = shogi.Move(WhichPiece.Pawn, "H9"); Assert.NotNull(moveResult); Assert.False(moveResult.IsSuccess); Assert.Null(board["H9"]); Assert.Single(board.Player1Hand, p => p.WhichPiece == WhichPiece.Pawn); // // Act | Assert - Illegally place Pawn from the hand in a row which already has an unpromoted Pawn. // // TODO } [Fact] public void PreventInvalidDrop_Check() { // Arrange var shogi = MockShogiBoard(); // P1 Pawn Assert.True(shogi.Move("C3", "C4", false).IsSuccess); // P2 Pawn Assert.True(shogi.Move("G7", "G6", false).IsSuccess); // P1 Pawn, arbitrary move. Assert.True(shogi.Move("A3", "A4", false).IsSuccess); // P2 Bishop takes P1 Bishop Assert.True(shogi.Move("H8", "B2", false).IsSuccess); // P1 Silver takes P2 Bishop Assert.True(shogi.Move("C1", "B2", false).IsSuccess); // P2 Pawn, arbtrary move Assert.True(shogi.Move("A7", "A6", false).IsSuccess); // P1 drop Bishop, place P2 in check Assert.True(shogi.Move(WhichPiece.Bishop, "G7").IsSuccess); Assert.Equal(WhichPlayer.Player2, shogi.BoardState.InCheck); Assert.Single(shogi.BoardState.Player2Hand, p => p.WhichPiece == WhichPiece.Bishop); Assert.Null(shogi.BoardState["E5"]); // Act - P2 places a Bishop while in check. var moveResult = shogi.Move(WhichPiece.Bishop, "E5"); // Assert Assert.NotNull(moveResult); Assert.False(moveResult.IsSuccess); Assert.Null(shogi.BoardState["E5"]); Assert.Equal(WhichPlayer.Player2, shogi.BoardState.InCheck); Assert.Single(shogi.BoardState.Player2Hand, p => p.WhichPiece == WhichPiece.Bishop); } [Fact] public void PreventInvalidDrop_Capture() { // Arrange var shogi = MockShogiBoard(); // P1 Pawn shogi.Move("C3", "C4", false); // P2 Pawn shogi.Move("G7", "G6", false); // P1 Bishop capture P2 Bishop shogi.Move("B2", "H8", false); // P2 Pawn shogi.Move("G6", "G5", false); Assert.Single(shogi.BoardState.Player1Hand, p => p.WhichPiece == WhichPiece.Bishop); Assert.NotNull(shogi.BoardState["I9"]); Assert.Equal(WhichPiece.Lance, shogi.BoardState["I9"]!.WhichPiece); Assert.Equal(WhichPlayer.Player2, shogi.BoardState["I9"]!.Owner); // Act - P1 tries to place a piece where an opponent's piece resides. var moveResult = shogi.Move(WhichPiece.Bishop, "I9"); // Assert Assert.NotNull(moveResult); Assert.False(moveResult.IsSuccess); Assert.Single(shogi.BoardState.Player1Hand, p => p.WhichPiece == WhichPiece.Bishop); Assert.NotNull(shogi.BoardState["I9"]); Assert.Equal(WhichPiece.Lance, shogi.BoardState["I9"]!.WhichPiece); Assert.Equal(WhichPlayer.Player2, shogi.BoardState["I9"]!.Owner); } [Fact] public void Check() { // Arrange var shogi = MockShogiBoard(); var board = shogi.BoardState; // P1 Pawn shogi.Move("C3", "C4", false); // P2 Pawn shogi.Move("G7", "G6", false); // Act - P1 Bishop, check shogi.Move("B2", "G7", false); // Assert Assert.Equal(WhichPlayer.Player2, board.InCheck); } [Fact] public void Promote() { // Arrange var shogi = MockShogiBoard(); var board = shogi.BoardState; // P1 Pawn shogi.Move("C3", "C4", false); // P2 Pawn shogi.Move("G7", "G6", false); // Act - P1 moves across promote threshold. shogi.Move("B2", "G7", true); // Assert Assert.Null(board["B2"]); Assert.NotNull(board["G7"]); Assert.Equal(WhichPiece.Bishop, board["G7"]!.WhichPiece); Assert.Equal(WhichPlayer.Player1, board["G7"]!.Owner); Assert.True(board["G7"]!.IsPromoted); } [Fact] public void Capture() { // Arrange var shogi = MockShogiBoard(); var board = shogi.BoardState; var p1Bishop = board["B2"]; Assert.Equal(WhichPiece.Bishop, p1Bishop!.WhichPiece); shogi.Move("C3", "C4", false); shogi.Move("G7", "G6", false); // Act - P1 Bishop captures P2 Bishop shogi.Move("B2", "H8", false); // Assert Assert.Null(board["B2"]); Assert.Equal(p1Bishop, board["H8"]); Assert.Single(board.Player1Hand, p => p.WhichPiece == WhichPiece.Bishop && p.Owner == WhichPlayer.Player1); } [Fact] public void CheckMate() { // Arrange var shogi = MockShogiBoard(); var board = shogi.BoardState; // P1 Rook shogi.Move("H2", "E2", false); // P2 Gold shogi.Move("F9", "G8", false); // P1 Pawn shogi.Move("E3", "E4", false); // P2 other Gold shogi.Move("D9", "C8", false); // P1 same Pawn shogi.Move("E4", "E5", false); // P2 Pawn shogi.Move("E7", "E6", false); // P1 Pawn takes P2 Pawn shogi.Move("E5", "E6", false); // P2 King shogi.Move("E9", "E8", false); // P1 Pawn promotes; threatens P2 King shogi.Move("E6", "E7", true); // P2 King retreat shogi.Move("E8", "E9", false); // Act - P1 Pawn wins by checkmate. shogi.Move("E7", "E8", false); // Assert - checkmate Assert.True(board.IsCheckmate); Assert.Equal(WhichPlayer.Player2, board.InCheck); } private static ShogiBoard MockShogiBoard() => new(BoardState.StandardStarting); }