From 715b328ef5c6811a04eb70eee9fecef069548c9b Mon Sep 17 00:00:00 2001 From: Lucas Morgan Date: Fri, 26 Feb 2021 17:11:08 -0600 Subject: [PATCH] Switch to Vector2 --- Benchmarking/Benchmarks.cs | 26 ++-- Gameboard.ShogiUI.BoardState/Array2D.cs | 11 +- Gameboard.ShogiUI.BoardState/BoardVector.cs | 65 +++------ Gameboard.ShogiUI.BoardState/Move.cs | 8 +- Gameboard.ShogiUI.BoardState/ShogiBoard.cs | 135 +++++++----------- .../ClientActionHandlers/LoadGameHandler.cs | 2 +- Gameboard.ShogiUI.Sockets/Models/Move.cs | 5 +- .../BoardState/BoardVectorShould.cs | 26 ---- .../BoardState/ShogiBoardShould.cs | 95 ++++++------ 9 files changed, 154 insertions(+), 219 deletions(-) delete mode 100644 Gameboard.ShogiUI.UnitTests/BoardState/BoardVectorShould.cs diff --git a/Benchmarking/Benchmarks.cs b/Benchmarking/Benchmarks.cs index 208b962..5a7947f 100644 --- a/Benchmarking/Benchmarks.cs +++ b/Benchmarking/Benchmarks.cs @@ -2,6 +2,7 @@ using BenchmarkDotNet.Running; using Gameboard.ShogiUI.BoardState; using System; +using System.Numerics; namespace Benchmarking { @@ -14,25 +15,25 @@ namespace Benchmarking moves = new[] { // P1 Rook - new Move { From = new BoardVector(7, 1), To = new BoardVector(4, 1) }, + new Move { From = new Vector2(7, 1), To = new Vector2(4, 1) }, // P2 Gold - new Move { From = new BoardVector(3, 8), To = new BoardVector(2, 7) }, + new Move { From = new Vector2(3, 8), To = new Vector2(2, 7) }, // P1 Pawn - new Move { From = new BoardVector(4, 2), To = new BoardVector(4, 3) }, + new Move { From = new Vector2(4, 2), To = new Vector2(4, 3) }, // P2 other Gold - new Move { From = new BoardVector(5, 8), To = new BoardVector(6, 7) }, + new Move { From = new Vector2(5, 8), To = new Vector2(6, 7) }, // P1 same Pawn - new Move { From = new BoardVector(4, 3), To = new BoardVector(4, 4) }, + new Move { From = new Vector2(4, 3), To = new Vector2(4, 4) }, // P2 Pawn - new Move { From = new BoardVector(4, 6), To = new BoardVector(4, 5) }, + new Move { From = new Vector2(4, 6), To = new Vector2(4, 5) }, // P1 Pawn takes P2 Pawn - new Move { From = new BoardVector(4, 4), To = new BoardVector(4, 5) }, + new Move { From = new Vector2(4, 4), To = new Vector2(4, 5) }, // P2 King - new Move { From = new BoardVector(4, 8), To = new BoardVector(4, 7) }, + new Move { From = new Vector2(4, 8), To = new Vector2(4, 7) }, // P1 Pawn promotes - new Move { From = new BoardVector(4, 5), To = new BoardVector(4, 6), IsPromotion = true }, + new Move { From = new Vector2(4, 5), To = new Vector2(4, 6), IsPromotion = true }, // P2 King retreat - new Move { From = new BoardVector(4, 7), To = new BoardVector(4, 8) }, + new Move { From = new Vector2(4, 7), To = new Vector2(4, 8) }, }; } @@ -42,7 +43,7 @@ namespace Benchmarking var board = new ShogiBoard(); foreach (var move in moves) { - board.TryMove(move); + board.Move(move); } } @@ -62,8 +63,9 @@ namespace Benchmarking { public static void Main(string[] args) { - BenchmarkRunner.Run(); + //BenchmarkRunner.Run(); Console.WriteLine("Done"); + } } } diff --git a/Gameboard.ShogiUI.BoardState/Array2D.cs b/Gameboard.ShogiUI.BoardState/Array2D.cs index 623a536..8e46f77 100644 --- a/Gameboard.ShogiUI.BoardState/Array2D.cs +++ b/Gameboard.ShogiUI.BoardState/Array2D.cs @@ -1,6 +1,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Numerics; namespace Gameboard.ShogiUI.BoardState { @@ -24,6 +25,11 @@ namespace Gameboard.ShogiUI.BoardState get => array[y * width + x]; set => array[y * width + x] = value; } + public T this[float x, float y] + { + get => array[(int)y * width + (int)x]; + set => array[(int)y * width + (int)x] = value; + } public void ForEach(ForEachDelegate callback) { @@ -48,15 +54,14 @@ namespace Gameboard.ShogiUI.BoardState } } - // TODO: Figure out a better return type, or make this class specific to ShogiBoard. - public BoardVector IndexOf(Predicate predicate) + public Vector2? IndexOf(Predicate predicate) { for (var x = 0; x < width; x++) for (var y = 0; y < height; y++) { if (this[x, y] != null && predicate(this[x, y])) { - return new BoardVector(x, y); + return new Vector2(x, y); } } return null; diff --git a/Gameboard.ShogiUI.BoardState/BoardVector.cs b/Gameboard.ShogiUI.BoardState/BoardVector.cs index 5568ac5..8f550d3 100644 --- a/Gameboard.ShogiUI.BoardState/BoardVector.cs +++ b/Gameboard.ShogiUI.BoardState/BoardVector.cs @@ -1,21 +1,21 @@ -using System.Diagnostics; +using System.Numerics; namespace Gameboard.ShogiUI.BoardState { /// - /// Provides normalized BoardVectors relative to player. + /// Provides normalized Vector2s relative to player. /// "Up" for player 1 is "Down" for player 2; that sort of thing. /// public class Direction { - private static readonly BoardVector PositiveX = new BoardVector(1, 0); - private static readonly BoardVector NegativeX = new BoardVector(-1, 0); - private static readonly BoardVector PositiveY = new BoardVector(0, 1); - private static readonly BoardVector NegativeY = new BoardVector(0, -1); - private static readonly BoardVector PositiveYX = new BoardVector(1, 1); - private static readonly BoardVector NegativeYX = new BoardVector(-1, -1); - private static readonly BoardVector NegativeYPositiveX = new BoardVector(1, -1); - private static readonly BoardVector PositiveYNegativeX = new BoardVector(-1, 1); + private static readonly Vector2 PositiveX = new Vector2(1, 0); + private static readonly Vector2 NegativeX = new Vector2(-1, 0); + private static readonly Vector2 PositiveY = new Vector2(0, 1); + private static readonly Vector2 NegativeY = new Vector2(0, -1); + private static readonly Vector2 PositiveYX = new Vector2(1, 1); + private static readonly Vector2 NegativeYX = new Vector2(-1, -1); + private static readonly Vector2 NegativeYPositiveX = new Vector2(1, -1); + private static readonly Vector2 PositiveYNegativeX = new Vector2(-1, 1); private readonly WhichPlayer whichPlayer; public Direction(WhichPlayer whichPlayer) @@ -23,40 +23,15 @@ namespace Gameboard.ShogiUI.BoardState this.whichPlayer = whichPlayer; } - public BoardVector Up => whichPlayer == WhichPlayer.Player1 ? PositiveY : NegativeY; - public BoardVector Down => whichPlayer == WhichPlayer.Player1 ? NegativeY : PositiveY; - public BoardVector Left => whichPlayer == WhichPlayer.Player1 ? NegativeX : PositiveX; - public BoardVector Right => whichPlayer == WhichPlayer.Player1 ? PositiveX : NegativeX; - public BoardVector UpLeft => whichPlayer == WhichPlayer.Player1 ? PositiveYNegativeX : NegativeYPositiveX; - public BoardVector UpRight => whichPlayer == WhichPlayer.Player1 ? PositiveYX : NegativeYX; - public BoardVector DownLeft => whichPlayer == WhichPlayer.Player1 ? NegativeYX : PositiveYX; - public BoardVector DownRight => whichPlayer == WhichPlayer.Player1 ? NegativeYPositiveX : PositiveYNegativeX; - public BoardVector KnightLeft => whichPlayer == WhichPlayer.Player1 ? new BoardVector(-1, 2) : new BoardVector(1, -2); - public BoardVector KnightRight => whichPlayer == WhichPlayer.Player1 ? new BoardVector(1, 2) : new BoardVector(-1, -2); - - } - - [DebuggerDisplay("[{X}, {Y}]")] - public class BoardVector - { - public int X { get; set; } - public int Y { get; set; } - public bool IsValidBoardPosition => X > -1 && X < 9 && Y > -1 && Y < 9; - public bool IsHand => X < 0 && Y < 0; // TODO: Find a better way to distinguish positions vs hand. - public BoardVector(int x, int y) - { - X = x; - Y = y; - } - - public BoardVector Add(BoardVector other) => new BoardVector(X + other.X, Y + other.Y); - public override bool Equals(object obj) => (obj is BoardVector other) && other.X == X && other.Y == Y; - public override int GetHashCode() - { - // [0,3] should hash different than [3,0] - return X.GetHashCode() * 3 + Y.GetHashCode() * 5; - } - public static bool operator ==(BoardVector a, BoardVector b) => a.Equals(b); - public static bool operator !=(BoardVector a, BoardVector b) => !a.Equals(b); + public Vector2 Up => whichPlayer == WhichPlayer.Player1 ? PositiveY : NegativeY; + public Vector2 Down => whichPlayer == WhichPlayer.Player1 ? NegativeY : PositiveY; + public Vector2 Left => whichPlayer == WhichPlayer.Player1 ? NegativeX : PositiveX; + public Vector2 Right => whichPlayer == WhichPlayer.Player1 ? PositiveX : NegativeX; + public Vector2 UpLeft => whichPlayer == WhichPlayer.Player1 ? PositiveYNegativeX : NegativeYPositiveX; + public Vector2 UpRight => whichPlayer == WhichPlayer.Player1 ? PositiveYX : NegativeYX; + public Vector2 DownLeft => whichPlayer == WhichPlayer.Player1 ? NegativeYX : PositiveYX; + public Vector2 DownRight => whichPlayer == WhichPlayer.Player1 ? NegativeYPositiveX : PositiveYNegativeX; + public Vector2 KnightLeft => whichPlayer == WhichPlayer.Player1 ? new Vector2(-1, 2) : new Vector2(1, -2); + public Vector2 KnightRight => whichPlayer == WhichPlayer.Player1 ? new Vector2(1, 2) : new Vector2(-1, -2); } } diff --git a/Gameboard.ShogiUI.BoardState/Move.cs b/Gameboard.ShogiUI.BoardState/Move.cs index f87ebad..9df0f89 100644 --- a/Gameboard.ShogiUI.BoardState/Move.cs +++ b/Gameboard.ShogiUI.BoardState/Move.cs @@ -1,10 +1,12 @@ -namespace Gameboard.ShogiUI.BoardState +using System.Numerics; + +namespace Gameboard.ShogiUI.BoardState { public class Move { public WhichPiece? PieceFromCaptured { get; set; } - public BoardVector From { get; set; } - public BoardVector To { get; set; } + public Vector2 From { get; set; } + public Vector2 To { get; set; } public bool IsPromotion { get; set; } } } diff --git a/Gameboard.ShogiUI.BoardState/ShogiBoard.cs b/Gameboard.ShogiUI.BoardState/ShogiBoard.cs index 9b1ca78..0bd9819 100644 --- a/Gameboard.ShogiUI.BoardState/ShogiBoard.cs +++ b/Gameboard.ShogiUI.BoardState/ShogiBoard.cs @@ -12,7 +12,7 @@ namespace Gameboard.ShogiUI.BoardState /// public class ShogiBoard { - private delegate void MoveSetCallback(Piece piece, BoardVector position); + private delegate void MoveSetCallback(Piece piece, Vector2 position); private ShogiBoard validationBoard; private Vector2 player1King; private Vector2 player2King; @@ -35,59 +35,31 @@ namespace Gameboard.ShogiUI.BoardState player1King = new Vector2(4, 0); player2King = new Vector2(4, 8); } - public ShogiBoard(IList moves) : this() - { - for (var i = 0; i < moves.Count; i++) - { - if (!TryMove(moves[i])) - { - throw new InvalidOperationException($"Unable to construct ShogiBoard with the given move at index {i}."); - } - } - } + public bool Move(Move move) + { + var otherPlayer = WhoseTurn == WhichPlayer.Player1 ? WhichPlayer.Player2 : WhichPlayer.Player1; + var moveSuccess = TryMove(move); + + if (!moveSuccess) return false; + + // Evaluate check + InCheck = EvaluateCheck(otherPlayer) ? otherPlayer : null; + if (InCheck.HasValue) + { + //IsCheckmate = EvaluateCheckmate(); + } + return true; + } /// /// Attempts a given move. Returns false if the move is illegal. /// - //public bool TryMove2(Move move) - //{ - // // Try making the move in a "throw away" board. - // if (validationBoard == null) - // { - // validationBoard = new ShogiBoard(MoveHistory); - // } - // var isValid = move.PieceFromCaptured.HasValue - // ? validationBoard.PlaceFromHand(move) - // : validationBoard.PlaceFromBoard(move); - // if (!isValid) - // { - // // Invalidate the "throw away" board. - // validationBoard = null; - // return false; - // } - // // Assert that this move does not put the moving player in check. - // if (validationBoard.EvaluateCheck(WhoseTurn)) return false; - - // var otherPlayer = WhoseTurn == WhichPlayer.Player1 ? WhichPlayer.Player2 : WhichPlayer.Player1; - // // The move is valid and legal; update board state. - // if (move.PieceFromCaptured.HasValue) PlaceFromHand(move); - // else PlaceFromBoard(move); - - // // Evaluate check - // InCheck = EvaluateCheck(otherPlayer) ? otherPlayer : null; - // if (InCheck.HasValue) - // { - // //IsCheckmate = EvaluateCheckmate(); - // } - // return true; - //} - - public bool TryMove(Move move, bool shouldEvaluateCheck = true) + private bool TryMove(Move move) { // Try making the move in a "throw away" board. if (validationBoard == null) { - validationBoard = new ShogiBoard(MoveHistory); + validationBoard = ConstructWithMoves(MoveHistory); } var isValid = move.PieceFromCaptured.HasValue ? validationBoard.PlaceFromHand(move) @@ -101,24 +73,11 @@ namespace Gameboard.ShogiUI.BoardState // Assert that this move does not put the moving player in check. if (validationBoard.EvaluateCheck(WhoseTurn)) return false; - var otherPlayer = WhoseTurn == WhichPlayer.Player1 ? WhichPlayer.Player2 : WhichPlayer.Player1; // The move is valid and legal; update board state. if (move.PieceFromCaptured.HasValue) PlaceFromHand(move); else PlaceFromBoard(move); - - // Evaluate check - if (shouldEvaluateCheck) - { - InCheck = EvaluateCheck(otherPlayer) ? otherPlayer : null; - if (InCheck.HasValue) - { - IsCheckmate = EvaluateCheckmate(); - } - } return true; } - - private bool EvaluateCheckmate() { if (!InCheck.HasValue) return false; @@ -129,10 +88,10 @@ namespace Gameboard.ShogiUI.BoardState { if (!isCheckmate) return; // Short circuit - var from = new BoardVector(x, y); + var from = new Vector2(x, y); if (piece.Owner == InCheck) // Owned by the player in check... { - var positionsToCheck = new List(10); + var positionsToCheck = new List(10); IterateMoveSet(from, (innerPiece, position) => { if (innerPiece?.Owner != InCheck) positionsToCheck.Add(position); // Find possible moves... @@ -141,7 +100,8 @@ namespace Gameboard.ShogiUI.BoardState // And evaluate if any move gets the player out of check. foreach (var position in positionsToCheck) { - var moveSuccess = validationBoard.TryMove(new Move { From = from, To = position }, false); + if (validationBoard == null) validationBoard = ConstructWithMoves(MoveHistory); + var moveSuccess = validationBoard.TryMove(new Move { From = from, To = position }); if (moveSuccess) { isCheckmate &= validationBoard.EvaluateCheck(InCheck.Value); @@ -277,8 +237,7 @@ namespace Gameboard.ShogiUI.BoardState // ...that belongs to the opponent within range... if (piece.Owner != whichPlayer && (piece.IsRanged || Vector2.Distance(kingPosition, v) < 3)) { - Console.WriteLine($"Evaluating {piece.WhichPiece}"); - IterateMoveSet(new BoardVector(x, y), (threatenedPiece, position) => + IterateMoveSet(new Vector2(x, y), (threatenedPiece, position) => { // ...and threatens the player's king. inCheck |= @@ -289,8 +248,7 @@ namespace Gameboard.ShogiUI.BoardState }); return inCheck; } - - private bool ValidateMoveAgainstMoveSet(BoardVector from, BoardVector to) + private bool ValidateMoveAgainstMoveSet(Vector2 from, Vector2 to) { var isValid = false; IterateMoveSet(from, (piece, position) => @@ -306,7 +264,7 @@ namespace Gameboard.ShogiUI.BoardState /// /// Iterate through the possible moves of a piece at a given position. /// - private void IterateMoveSet(BoardVector from, MoveSetCallback callback) + private void IterateMoveSet(Vector2 from, MoveSetCallback callback) { // TODO: Make these are of the move To, so only possible moves towards the move To are iterated. // Maybe separate functions? Sometimes I need to iterate the whole move-set, sometimes I need to iterate only the move-set towards the move To. @@ -339,7 +297,7 @@ namespace Gameboard.ShogiUI.BoardState break; } } - private void IterateKingMoveSet(BoardVector from, MoveSetCallback callback) + private void IterateKingMoveSet(Vector2 from, MoveSetCallback callback) { var piece = Board[from.X, from.Y]; var direction = new Direction(piece.Owner); @@ -352,7 +310,7 @@ namespace Gameboard.ShogiUI.BoardState BoardStep(from, direction.Left, callback); BoardStep(from, direction.Right, callback); } - private void IterateGoldenGeneralMoveSet(BoardVector from, MoveSetCallback callback) + private void IterateGoldenGeneralMoveSet(Vector2 from, MoveSetCallback callback) { var piece = Board[from.X, from.Y]; var direction = new Direction(piece.Owner); @@ -363,7 +321,7 @@ namespace Gameboard.ShogiUI.BoardState BoardStep(from, direction.Left, callback); BoardStep(from, direction.Right, callback); } - private void IterateSilverGeneralMoveSet(BoardVector from, MoveSetCallback callback) + private void IterateSilverGeneralMoveSet(Vector2 from, MoveSetCallback callback) { var piece = Board[from.X, from.Y]; var direction = new Direction(piece.Owner); @@ -380,7 +338,7 @@ namespace Gameboard.ShogiUI.BoardState BoardStep(from, direction.DownRight, callback); } } - private void IterateBishopMoveSet(BoardVector from, MoveSetCallback callback) + private void IterateBishopMoveSet(Vector2 from, MoveSetCallback callback) { var piece = Board[from.X, from.Y]; var direction = new Direction(piece.Owner); @@ -396,7 +354,7 @@ namespace Gameboard.ShogiUI.BoardState BoardStep(from, direction.Down, callback); } } - private void IterateRookMoveSet(BoardVector from, MoveSetCallback callback) + private void IterateRookMoveSet(Vector2 from, MoveSetCallback callback) { var piece = Board[from.X, from.Y]; var direction = new Direction(piece.Owner); @@ -412,7 +370,7 @@ namespace Gameboard.ShogiUI.BoardState BoardStep(from, direction.DownRight, callback); } } - private void IterateKnightMoveSet(BoardVector from, MoveSetCallback callback) + private void IterateKnightMoveSet(Vector2 from, MoveSetCallback callback) { var piece = Board[from.X, from.Y]; if (piece.IsPromoted) @@ -426,7 +384,7 @@ namespace Gameboard.ShogiUI.BoardState BoardStep(from, direction.KnightRight, callback); } } - private void IterateLanceMoveSet(BoardVector from, MoveSetCallback callback) + private void IterateLanceMoveSet(Vector2 from, MoveSetCallback callback) { var piece = Board[from.X, from.Y]; if (piece.IsPromoted) @@ -439,7 +397,7 @@ namespace Gameboard.ShogiUI.BoardState BoardWalk(from, direction.Up, callback); } } - private void IteratePawnMoveSet(BoardVector from, MoveSetCallback callback) + private void IteratePawnMoveSet(Vector2 from, MoveSetCallback callback) { var piece = Board[from.X, from.Y]; if (piece?.WhichPiece == WhichPiece.Pawn) @@ -459,15 +417,15 @@ namespace Gameboard.ShogiUI.BoardState /// Useful for iterating the board for pieces that move many spaces. /// /// A function that returns true if walking should continue. - private void BoardWalk(BoardVector from, BoardVector direction, MoveSetCallback callback) + private void BoardWalk(Vector2 from, Vector2 direction, MoveSetCallback callback) { var foundAnotherPiece = false; - var to = from.Add(direction); - while (to.IsValidBoardPosition && !foundAnotherPiece) + var to = Vector2.Add(from, direction); + while (to.X >= 0 && to.X < 9 && to.Y >= 0 && to.Y < 9 && !foundAnotherPiece) { var piece = Board[to.X, to.Y]; callback(piece, to); - to = to.Add(direction); + to = Vector2.Add(to, direction); foundAnotherPiece = piece != null; } } @@ -475,10 +433,10 @@ namespace Gameboard.ShogiUI.BoardState /// /// Useful for iterating the board for pieces that move only one space. /// - private void BoardStep(BoardVector from, BoardVector direction, MoveSetCallback callback) + private void BoardStep(Vector2 from, Vector2 direction, MoveSetCallback callback) { - var to = from.Add(direction); - if (to.IsValidBoardPosition) + var to = Vector2.Add(from, direction); + if (to.X >= 0 && to.X < 9 && to.Y >= 0 && to.Y < 9) { callback(Board[to.X, to.Y], to); } @@ -540,5 +498,18 @@ namespace Gameboard.ShogiUI.BoardState ResetRearRow(WhichPlayer.Player2); } #endregion + + public static ShogiBoard ConstructWithMoves(IList moves) + { + var s = new ShogiBoard(); + for (var i = 0; i < moves.Count; i++) + { + if (!s.Move(moves[i])) + { + throw new InvalidOperationException($"Unable to construct ShogiBoard with the given move at index {i}."); + } + } + return s; + } } } diff --git a/Gameboard.ShogiUI.Sockets/Managers/ClientActionHandlers/LoadGameHandler.cs b/Gameboard.ShogiUI.Sockets/Managers/ClientActionHandlers/LoadGameHandler.cs index db15bfa..1ec37d1 100644 --- a/Gameboard.ShogiUI.Sockets/Managers/ClientActionHandlers/LoadGameHandler.cs +++ b/Gameboard.ShogiUI.Sockets/Managers/ClientActionHandlers/LoadGameHandler.cs @@ -52,7 +52,7 @@ namespace Gameboard.ShogiUI.Sockets.Managers.ClientActionHandlers communicationManager.SubscribeToGame(sessionModel, userName); var boardMoves = moveModels.Select(_ => _.ToBoardModel()).ToList(); - boardManager.Add(getGameResponse.Session.Name, new ShogiBoard(boardMoves)); + boardManager.Add(getGameResponse.Session.Name, ShogiBoard.ConstructWithMoves(boardMoves)); var response = new LoadGameResponse(ClientAction.LoadGame) { diff --git a/Gameboard.ShogiUI.Sockets/Models/Move.cs b/Gameboard.ShogiUI.Sockets/Models/Move.cs index fcb7274..b61d8d7 100644 --- a/Gameboard.ShogiUI.Sockets/Models/Move.cs +++ b/Gameboard.ShogiUI.Sockets/Models/Move.cs @@ -1,6 +1,7 @@ using Gameboard.ShogiUI.BoardState; using Microsoft.FSharp.Core; using System; +using System.Numerics; using ShogiApi = Gameboard.Shogi.Api.ServiceModels.Types; namespace Gameboard.ShogiUI.Sockets.Models @@ -77,10 +78,10 @@ namespace Gameboard.ShogiUI.Sockets.Models { return new BoardState.Move { - From = new BoardVector(From.X, From.Y), + From = new Vector2(From.X, From.Y), IsPromotion = IsPromotion, PieceFromCaptured = Enum.TryParse(PieceFromCaptured, out var whichPiece) ? whichPiece : null, - To = new BoardVector(To.X, To.Y) + To = new Vector2(To.X, To.Y) }; } } diff --git a/Gameboard.ShogiUI.UnitTests/BoardState/BoardVectorShould.cs b/Gameboard.ShogiUI.UnitTests/BoardState/BoardVectorShould.cs deleted file mode 100644 index 85d9b99..0000000 --- a/Gameboard.ShogiUI.UnitTests/BoardState/BoardVectorShould.cs +++ /dev/null @@ -1,26 +0,0 @@ -using FluentAssertions; -using Gameboard.ShogiUI.BoardState; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace Gameboard.ShogiUI.UnitTests.BoardState -{ - [TestClass] - public class BoardVectorShould - { - [TestMethod] - public void BeEqualWhenPropertiesAreEqual() - { - var a = new BoardVector(3, 2); - var b = new BoardVector(3, 2); - a.Should().Be(b); - a.GetHashCode().Should().Be(b.GetHashCode()); - (a == b).Should().BeTrue(); - - // Properties should not be transitively equal. - b = new BoardVector(2, 3); - a.Should().NotBe(b); - a.GetHashCode().Should().NotBe(b.GetHashCode()); - (a == b).Should().BeFalse(); - } - } -} diff --git a/Gameboard.ShogiUI.UnitTests/BoardState/ShogiBoardShould.cs b/Gameboard.ShogiUI.UnitTests/BoardState/ShogiBoardShould.cs index 8d4a22d..2933154 100644 --- a/Gameboard.ShogiUI.UnitTests/BoardState/ShogiBoardShould.cs +++ b/Gameboard.ShogiUI.UnitTests/BoardState/ShogiBoardShould.cs @@ -1,8 +1,9 @@ using FluentAssertions; using Gameboard.ShogiUI.BoardState; using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; using System.Linq; +using System.Numerics; + namespace Gameboard.ShogiUI.UnitTests.BoardState { [TestClass] @@ -70,11 +71,11 @@ namespace Gameboard.ShogiUI.UnitTests.BoardState new Move { // Pawn - From = new BoardVector(0, 2), - To = new BoardVector(0, 3) + From = new Vector2(0, 2), + To = new Vector2(0, 3) } }; - var shogi = new ShogiBoard(moves); + var shogi = ShogiBoard.ConstructWithMoves(moves); shogi.Board[0, 2].Should().BeNull(); shogi.Board[0, 3].WhichPiece.Should().Be(WhichPiece.Pawn); } @@ -86,7 +87,7 @@ namespace Gameboard.ShogiUI.UnitTests.BoardState var shogi = new ShogiBoard(); // Act - P1 "moves" pawn to the position it already exists at. - var moveSuccess = shogi.TryMove(new Move { From = new BoardVector(0, 2), To = new BoardVector(0, 2) }); + var moveSuccess = shogi.Move(new Move { From = new Vector2(0, 2), To = new Vector2(0, 2) }); // Assert moveSuccess.Should().BeFalse(); @@ -99,12 +100,12 @@ namespace Gameboard.ShogiUI.UnitTests.BoardState var invalidLanceMove = new Move { // Lance moving adjacent - From = new BoardVector(0, 0), - To = new BoardVector(1, 5) + From = new Vector2(0, 0), + To = new Vector2(1, 5) }; var shogi = new ShogiBoard(); - var moveSuccess = shogi.TryMove(invalidLanceMove); + var moveSuccess = shogi.Move(invalidLanceMove); moveSuccess.Should().BeFalse(); // Assert the Lance has not actually moved. @@ -118,7 +119,7 @@ namespace Gameboard.ShogiUI.UnitTests.BoardState var shogi = new ShogiBoard(); // Act - Move Player2 Pawn when it's Player1 turn. - var moveSuccess = shogi.TryMove(new Move { From = new BoardVector(8, 6), To = new BoardVector(8, 5) }); + var moveSuccess = shogi.Move(new Move { From = new Vector2(8, 6), To = new Vector2(8, 5) }); // Assert moveSuccess.Should().BeFalse(); @@ -132,12 +133,12 @@ namespace Gameboard.ShogiUI.UnitTests.BoardState var invalidLanceMove = new Move { // Lance moving through the pawn before it. - From = new BoardVector(0, 0), - To = new BoardVector(0, 5) + From = new Vector2(0, 0), + To = new Vector2(0, 5) }; var shogi = new ShogiBoard(); - var moveSuccess = shogi.TryMove(invalidLanceMove); + var moveSuccess = shogi.Move(invalidLanceMove); moveSuccess.Should().BeFalse(); // Assert the Lance has not actually moved. @@ -150,12 +151,12 @@ namespace Gameboard.ShogiUI.UnitTests.BoardState var invalidKnightMove = new Move { // Knight capturing allied Pawn - From = new BoardVector(1, 0), - To = new BoardVector(0, 2) + From = new Vector2(1, 0), + To = new Vector2(0, 2) }; var shogi = new ShogiBoard(); - var moveSuccess = shogi.TryMove(invalidKnightMove); + var moveSuccess = shogi.Move(invalidKnightMove); moveSuccess.Should().BeFalse(); // Assert the Knight has not actually moved or captured. @@ -170,20 +171,24 @@ namespace Gameboard.ShogiUI.UnitTests.BoardState var moves = new[] { // P1 Pawn - new Move { From = new BoardVector(2, 2), To = new BoardVector(2, 3) }, + new Move { From = new Vector2(2, 2), To = new Vector2(2, 3) }, // P2 Pawn - new Move { From = new BoardVector(6, 6), To = new BoardVector(6, 5) }, + new Move { From = new Vector2(6, 6), To = new Vector2(6, 5) }, // P1 Bishop puts P2 in check - new Move { From = new BoardVector(1, 1), To = new BoardVector(6, 6) } + new Move { From = new Vector2(1, 1), To = new Vector2(6, 6) } }; - var shogi = new ShogiBoard(moves); + var shogi = ShogiBoard.ConstructWithMoves(moves); + //foreach(var m in moves) + //{ + // shogi.Move(m); + //} // Prerequisit shogi.InCheck.Should().Be(WhichPlayer.Player2); // Act - P2 moves Lance while remaining in check. - var moveSuccess = shogi.TryMove(new Move { From = new BoardVector(8, 8), To = new BoardVector(8, 7) }); + var moveSuccess = shogi.Move(new Move { From = new Vector2(8, 8), To = new Vector2(8, 7) }); // Assert moveSuccess.Should().BeFalse(); @@ -199,15 +204,15 @@ namespace Gameboard.ShogiUI.UnitTests.BoardState var moves = new[] { // P1 Pawn - new Move { From = new BoardVector(2, 2), To = new BoardVector(2, 3) }, + new Move { From = new Vector2(2, 2), To = new Vector2(2, 3) }, // P2 Pawn - new Move { From = new BoardVector(6, 6), To = new BoardVector(6, 5) }, + new Move { From = new Vector2(6, 6), To = new Vector2(6, 5) }, }; - var shogi = new ShogiBoard(moves); + var shogi = ShogiBoard.ConstructWithMoves(moves); // Act - P1 Bishop, check - shogi.TryMove(new Move { From = new BoardVector(1, 1), To = new BoardVector(6, 6) }); + shogi.Move(new Move { From = new Vector2(1, 1), To = new Vector2(6, 6) }); // Assert shogi.InCheck.Should().Be(WhichPlayer.Player2); @@ -220,14 +225,14 @@ namespace Gameboard.ShogiUI.UnitTests.BoardState var moves = new[] { // P1 Pawn - new Move { From = new BoardVector(2, 2), To = new BoardVector(2, 3) }, + new Move { From = new Vector2(2, 2), To = new Vector2(2, 3) }, // P2 Pawn - new Move { From = new BoardVector(6, 6), To = new BoardVector(6, 5) } + new Move { From = new Vector2(6, 6), To = new Vector2(6, 5) } }; - var shogi = new ShogiBoard(moves); + var shogi = ShogiBoard.ConstructWithMoves(moves); // Act - P1 Bishop captures P2 Bishop - var moveSuccess = shogi.TryMove(new Move { From = new BoardVector(1, 1), To = new BoardVector(7, 7) }); + var moveSuccess = shogi.Move(new Move { From = new Vector2(1, 1), To = new Vector2(7, 7) }); // Assert moveSuccess.Should().BeTrue(); @@ -244,7 +249,7 @@ namespace Gameboard.ShogiUI.UnitTests.BoardState // Act - P2 Silver captures P1 Bishop - moveSuccess = shogi.TryMove(new Move { From = new BoardVector(6, 8), To = new BoardVector(7, 7) }); + moveSuccess = shogi.Move(new Move { From = new Vector2(6, 8), To = new Vector2(7, 7) }); // Assert moveSuccess.Should().BeTrue(); @@ -266,14 +271,14 @@ namespace Gameboard.ShogiUI.UnitTests.BoardState var moves = new[] { // P1 Pawn - new Move { From = new BoardVector(2, 2), To = new BoardVector(2, 3) }, + new Move { From = new Vector2(2, 2), To = new Vector2(2, 3) }, // P2 Pawn - new Move { From = new BoardVector(6, 6), To = new BoardVector(6, 5) } + new Move { From = new Vector2(6, 6), To = new Vector2(6, 5) } }; - var shogi = new ShogiBoard(moves); + var shogi = ShogiBoard.ConstructWithMoves(moves); // Act - P1 moves across promote threshold. - var moveSuccess = shogi.TryMove(new Move { From = new BoardVector(1, 1), To = new BoardVector(6, 6), IsPromotion = true }); + var moveSuccess = shogi.Move(new Move { From = new Vector2(1, 1), To = new Vector2(6, 6), IsPromotion = true }); // Assert moveSuccess.Should().BeTrue(); @@ -288,30 +293,30 @@ namespace Gameboard.ShogiUI.UnitTests.BoardState var moves = new[] { // P1 Rook - new Move { From = new BoardVector(7, 1), To = new BoardVector(4, 1) }, + new Move { From = new Vector2(7, 1), To = new Vector2(4, 1) }, // P2 Gold - new Move { From = new BoardVector(3, 8), To = new BoardVector(2, 7) }, + new Move { From = new Vector2(3, 8), To = new Vector2(2, 7) }, // P1 Pawn - new Move { From = new BoardVector(4, 2), To = new BoardVector(4, 3) }, + new Move { From = new Vector2(4, 2), To = new Vector2(4, 3) }, // P2 other Gold - new Move { From = new BoardVector(5, 8), To = new BoardVector(6, 7) }, + new Move { From = new Vector2(5, 8), To = new Vector2(6, 7) }, // P1 same Pawn - new Move { From = new BoardVector(4, 3), To = new BoardVector(4, 4) }, + new Move { From = new Vector2(4, 3), To = new Vector2(4, 4) }, // P2 Pawn - new Move { From = new BoardVector(4, 6), To = new BoardVector(4, 5) }, + new Move { From = new Vector2(4, 6), To = new Vector2(4, 5) }, // P1 Pawn takes P2 Pawn - new Move { From = new BoardVector(4, 4), To = new BoardVector(4, 5) }, + new Move { From = new Vector2(4, 4), To = new Vector2(4, 5) }, // P2 King - new Move { From = new BoardVector(4, 8), To = new BoardVector(4, 7) }, + new Move { From = new Vector2(4, 8), To = new Vector2(4, 7) }, // P1 Pawn promotes - new Move { From = new BoardVector(4, 5), To = new BoardVector(4, 6), IsPromotion = true }, + new Move { From = new Vector2(4, 5), To = new Vector2(4, 6), IsPromotion = true }, // P2 King retreat - new Move { From = new BoardVector(4, 7), To = new BoardVector(4, 8) }, + new Move { From = new Vector2(4, 7), To = new Vector2(4, 8) }, }; - var shogi = new ShogiBoard(moves); + var shogi = ShogiBoard.ConstructWithMoves(moves); // Act - P1 Pawn wins by checkmate. - var moveSuccess = shogi.TryMove(new Move { From = new BoardVector(4, 6), To = new BoardVector(4, 7) }); + var moveSuccess = shogi.Move(new Move { From = new Vector2(4, 6), To = new Vector2(4, 7) }); // Assert moveSuccess.Should().BeTrue();