using FluentAssertions; using Gameboard.ShogiUI.BoardState; using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Linq; using System.Numerics; namespace Gameboard.ShogiUI.UnitTests.BoardState { [TestClass] public class ShogiBoardShould { [TestMethod] public void InitializeBoardState() { // Assert var board = new ShogiBoard().Board; // Assert pieces do not start promoted. foreach (var piece in board) piece?.IsPromoted.Should().BeFalse(); // Assert Player1. for (var y = 0; y < 3; y++) for (var x = 0; x < 9; x++) board[x, y]?.Owner.Should().Be(WhichPlayer.Player1); board[0, 0].WhichPiece.Should().Be(WhichPiece.Lance); board[1, 0].WhichPiece.Should().Be(WhichPiece.Knight); board[2, 0].WhichPiece.Should().Be(WhichPiece.SilverGeneral); board[3, 0].WhichPiece.Should().Be(WhichPiece.GoldenGeneral); board[4, 0].WhichPiece.Should().Be(WhichPiece.King); board[5, 0].WhichPiece.Should().Be(WhichPiece.GoldenGeneral); board[6, 0].WhichPiece.Should().Be(WhichPiece.SilverGeneral); board[7, 0].WhichPiece.Should().Be(WhichPiece.Knight); board[8, 0].WhichPiece.Should().Be(WhichPiece.Lance); board[0, 1].Should().BeNull(); board[1, 1].WhichPiece.Should().Be(WhichPiece.Bishop); for (var x = 2; x < 7; x++) board[x, 1].Should().BeNull(); board[7, 1].WhichPiece.Should().Be(WhichPiece.Rook); board[8, 1].Should().BeNull(); for (var x = 0; x < 9; x++) board[x, 2].WhichPiece.Should().Be(WhichPiece.Pawn); // Assert empty locations. for (var y = 3; y < 6; y++) for (var x = 0; x < 9; x++) board[x, y].Should().BeNull(); // Assert Player2. for (var y = 6; y < 9; y++) for (var x = 0; x < 9; x++) board[x, y]?.Owner.Should().Be(WhichPlayer.Player2); board[0, 8].WhichPiece.Should().Be(WhichPiece.Lance); board[1, 8].WhichPiece.Should().Be(WhichPiece.Knight); board[2, 8].WhichPiece.Should().Be(WhichPiece.SilverGeneral); board[3, 8].WhichPiece.Should().Be(WhichPiece.GoldenGeneral); board[4, 8].WhichPiece.Should().Be(WhichPiece.King); board[5, 8].WhichPiece.Should().Be(WhichPiece.GoldenGeneral); board[6, 8].WhichPiece.Should().Be(WhichPiece.SilverGeneral); board[7, 8].WhichPiece.Should().Be(WhichPiece.Knight); board[8, 8].WhichPiece.Should().Be(WhichPiece.Lance); board[0, 7].Should().BeNull(); board[1, 7].WhichPiece.Should().Be(WhichPiece.Rook); for (var x = 2; x < 7; x++) board[x, 7].Should().BeNull(); board[7, 7].WhichPiece.Should().Be(WhichPiece.Bishop); board[8, 7].Should().BeNull(); for (var x = 0; x < 9; x++) board[x, 6].WhichPiece.Should().Be(WhichPiece.Pawn); } [TestMethod] public void InitializeBoardStateWithMoves() { var moves = new[] { new Move { // Pawn From = new Vector2(0, 2), To = new Vector2(0, 3) } }; var shogi = new ShogiBoard(moves); shogi.Board[0, 2].Should().BeNull(); shogi.Board[0, 3].WhichPiece.Should().Be(WhichPiece.Pawn); } [TestMethod] public void PreventInvalidMoves_MoveToCurrentPosition() { // Arrange var shogi = new ShogiBoard(); // Act - P1 "moves" pawn to the position it already exists at. var moveSuccess = shogi.Move(new Move { From = new Vector2(0, 2), To = new Vector2(0, 2) }); // Assert moveSuccess.Should().BeFalse(); shogi.Board[0, 2].WhichPiece.Should().Be(WhichPiece.Pawn); } [TestMethod] public void PreventInvalidMoves_MoveSet() { var invalidLanceMove = new Move { // Bishop moving lateral From = new Vector2(1, 1), To = new Vector2(2, 1) }; var shogi = new ShogiBoard(); var moveSuccess = shogi.Move(invalidLanceMove); moveSuccess.Should().BeFalse(); // Assert the Lance has not actually moved. shogi.Board[0, 0].WhichPiece.Should().Be(WhichPiece.Lance); } [TestMethod] public void PreventInvalidMoves_Ownership() { // Arrange var shogi = new ShogiBoard(); // Act - Move Player2 Pawn when it's Player1 turn. var moveSuccess = shogi.Move(new Move { From = new Vector2(8, 6), To = new Vector2(8, 5) }); // Assert moveSuccess.Should().BeFalse(); shogi.Board[8, 6].WhichPiece.Should().Be(WhichPiece.Pawn); shogi.Board[8, 5].Should().BeNull(); } [TestMethod] public void PreventInvalidMoves_MoveThroughAllies() { var invalidLanceMove = new Move { // Lance moving through the pawn before it. From = new Vector2(0, 0), To = new Vector2(0, 5) }; var shogi = new ShogiBoard(); var moveSuccess = shogi.Move(invalidLanceMove); moveSuccess.Should().BeFalse(); // Assert the Lance has not actually moved. shogi.Board[0, 0].WhichPiece.Should().Be(WhichPiece.Lance); } [TestMethod] public void PreventInvalidMoves_CaptureAlly() { var invalidKnightMove = new Move { // Knight capturing allied Pawn From = new Vector2(1, 0), To = new Vector2(0, 2) }; var shogi = new ShogiBoard(); var moveSuccess = shogi.Move(invalidKnightMove); moveSuccess.Should().BeFalse(); // Assert the Knight has not actually moved or captured. shogi.Board[1, 0].WhichPiece.Should().Be(WhichPiece.Knight); shogi.Board[0, 2].WhichPiece.Should().Be(WhichPiece.Pawn); } [TestMethod] public void PreventInvalidMoves_Check() { // Arrange var moves = new[] { // P1 Pawn new Move { From = new Vector2(2, 2), To = new Vector2(2, 3) }, // P2 Pawn new Move { From = new Vector2(6, 6), To = new Vector2(6, 5) }, // P1 Bishop puts P2 in check new Move { From = new Vector2(1, 1), To = new Vector2(6, 6) } }; //var shogi = new ShogiBoard(moves); var shogi = new ShogiBoard(moves); // Prerequisit shogi.InCheck.Should().Be(WhichPlayer.Player2); // Act - P2 moves Lance while remaining in check. var moveSuccess = shogi.Move(new Move { From = new Vector2(8, 8), To = new Vector2(8, 7) }); // Assert moveSuccess.Should().BeFalse(); shogi.InCheck.Should().Be(WhichPlayer.Player2); shogi.Board[8, 8].WhichPiece.Should().Be(WhichPiece.Lance); shogi.Board[8, 7].Should().BeNull(); } [TestMethod] public void Check() { // Arrange var moves = new[] { // P1 Pawn new Move { From = new Vector2(2, 2), To = new Vector2(2, 3) }, // P2 Pawn new Move { From = new Vector2(6, 6), To = new Vector2(6, 5) }, }; var shogi = new ShogiBoard(moves); shogi.PrintStateAsAscii(); // Act - P1 Bishop, check shogi.Move(new Move { From = new Vector2(1, 1), To = new Vector2(6, 6) }); // Assert shogi.InCheck.Should().Be(WhichPlayer.Player2); } [TestMethod] public void Capture() { // Arrange var moves = new[] { // P1 Pawn new Move { From = new Vector2(2, 2), To = new Vector2(2, 3) }, // P2 Pawn new Move { From = new Vector2(6, 6), To = new Vector2(6, 5) } }; var shogi = new ShogiBoard(moves); // Act - P1 Bishop captures P2 Bishop var moveSuccess = shogi.Move(new Move { From = new Vector2(1, 1), To = new Vector2(7, 7) }); // Assert moveSuccess.Should().BeTrue(); shogi.Board .Cast() .Count(piece => piece?.WhichPiece == WhichPiece.Bishop) .Should() .Be(1); shogi.Board[1, 1].Should().BeNull(); shogi.Board[7, 7].WhichPiece.Should().Be(WhichPiece.Bishop); shogi.Hands[WhichPlayer.Player1] .Should() .ContainSingle(piece => piece.WhichPiece == WhichPiece.Bishop && piece.Owner == WhichPlayer.Player1); // Act - P2 Silver captures P1 Bishop moveSuccess = shogi.Move(new Move { From = new Vector2(6, 8), To = new Vector2(7, 7) }); // Assert moveSuccess.Should().BeTrue(); shogi.Board[6, 8].Should().BeNull(); shogi.Board[7, 7].WhichPiece.Should().Be(WhichPiece.SilverGeneral); shogi.Board .Cast() .Count(piece => piece?.WhichPiece == WhichPiece.Bishop) .Should().Be(0); shogi.Hands[WhichPlayer.Player2] .Should() .ContainSingle(piece => piece.WhichPiece == WhichPiece.Bishop && piece.Owner == WhichPlayer.Player2); } [TestMethod] public void Promote() { // Arrange var moves = new[] { // P1 Pawn new Move { From = new Vector2(2, 2), To = new Vector2(2, 3) }, // P2 Pawn new Move { From = new Vector2(6, 6), To = new Vector2(6, 5) } }; var shogi = new ShogiBoard(moves); // Act - P1 moves across promote threshold. var moveSuccess = shogi.Move(new Move { From = new Vector2(1, 1), To = new Vector2(6, 6), IsPromotion = true }); // Assert moveSuccess.Should().BeTrue(); shogi.Board[1, 1].Should().BeNull(); shogi.Board[6, 6].Should().Match(piece => piece.WhichPiece == WhichPiece.Bishop && piece.IsPromoted == true); } [TestMethod] public void CheckMate() { // Arrange var moves = new[] { // P1 Rook new Move { From = new Vector2(7, 1), To = new Vector2(4, 1) }, // P2 Gold new Move { From = new Vector2(3, 8), To = new Vector2(2, 7) }, // P1 Pawn new Move { From = new Vector2(4, 2), To = new Vector2(4, 3) }, // P2 other Gold new Move { From = new Vector2(5, 8), To = new Vector2(6, 7) }, // P1 same Pawn new Move { From = new Vector2(4, 3), To = new Vector2(4, 4) }, // P2 Pawn new Move { From = new Vector2(4, 6), To = new Vector2(4, 5) }, // P1 Pawn takes P2 Pawn new Move { From = new Vector2(4, 4), To = new Vector2(4, 5) }, // P2 King new Move { From = new Vector2(4, 8), To = new Vector2(4, 7) }, // P1 Pawn promotes new Move { From = new Vector2(4, 5), To = new Vector2(4, 6), IsPromotion = true }, // P2 King retreat new Move { From = new Vector2(4, 7), To = new Vector2(4, 8) }, }; var shogi = new ShogiBoard(moves); // Act - P1 Pawn wins by checkmate. var moveSuccess = shogi.Move(new Move { From = new Vector2(4, 6), To = new Vector2(4, 7) }); // Assert moveSuccess.Should().BeTrue(); shogi.IsCheckmate.Should().BeTrue(); } } }