diff --git a/src/ChineseCheckers.Domain/Board.cs b/src/ChineseCheckers.Domain/Board.cs index 94f9fdd..7f1e9f6 100644 --- a/src/ChineseCheckers.Domain/Board.cs +++ b/src/ChineseCheckers.Domain/Board.cs @@ -196,45 +196,92 @@ public void SetPieceColor(int x, int y, PieceColor color) _board[x, y] = (int)color; } - public bool IsValidMove(int fromX, int fromY, int toX, int toY) + public bool IsValidMoves(Point[] moves) + { + MoveType lastMove; + for (int i = 0; i < moves.Length - 1; i++) + { + lastMove = IsValidMove(moves[i].X, moves[i].Y, moves[i + 1].X, moves[i + 1].Y); + if (lastMove == MoveType.Error) + { + return false; + } + } + return true; + } + + public enum MoveType + { + OneStep, Jump, Error + } + + public MoveType IsValidMove(int fromX, int fromY, int toX, int toY) { // 檢查是否超出絕對邊界 if (toX < 0 || toX > 16 || toY < 0 || toY > 16) { - return false; + return MoveType.Error; } // From 必須要有棋子 if (_board[fromX, fromY] <= (int)PieceColor.None) { - return false; + return MoveType.Error; } // To 必須是空位 if (_board[toX, toY] != (int)PieceColor.None) { - return false; + return MoveType.Error; } // 檢查是否為一步移動 - if (Math.Abs(fromX - toX) is 0 or 1 && Math.Abs(fromY - toY) is 0 or 1) + var isOneStep = (fromX - toX, fromY - toY) switch + { + // 左上 + (1, 1) => true, + // 右上 + (0, 1) => true, + // 右 + (-1, 0) => true, + // 右下 + (-1, -1) => true, + // 左下 + (0, -1) => true, + // 左 + (1, 0) => true, + // 排除不合法的跳躍 + _ => false + }; + + if (isOneStep) { - return true; + return MoveType.OneStep; } // 檢查是否為跳躍移動 if (Math.Abs(fromX - toX) is 0 or 2 && Math.Abs(fromY - toY) is 0 or 2) { + // 排除不合法的跳躍 + if (fromX - toX == 2 && fromY - toY == -2) + { + return MoveType.Error; + } + if (fromX - toX == -2 && fromY - toY == 2) + { + return MoveType.Error; + } + int middleX = (fromX + toX) / 2; int middleY = (fromY + toY) / 2; if (_board[middleX, middleY] > (int)PieceColor.None) { - return true; + return MoveType.Jump; } } - return false; + return MoveType.Error; } } diff --git a/src/ChineseCheckers.Domain/Game.cs b/src/ChineseCheckers.Domain/Game.cs index 9cd77d2..c51fc07 100644 --- a/src/ChineseCheckers.Domain/Game.cs +++ b/src/ChineseCheckers.Domain/Game.cs @@ -1,6 +1,3 @@ - -using System.Runtime.Serialization; - namespace ChineseCheckers.Domain; public class Game @@ -33,16 +30,16 @@ public void Start() _board.Initialize(_players.Count); } - public void MoveChess(int sx, int sy, int dx, int dy) + public void MoveChess(Point[] moves) { - if (_board.IsValidMove(sx, sy, dx, dy) == false) + if (_board.IsValidMoves(moves) == false) { throw new InvalidMoveException("Invalid Move"); } - var tmp = _board.GetPieceColor(sx, sy); - _board.SetPieceColor(sx, sy, _board.GetPieceColor(dx, dy)); - _board.SetPieceColor(dx, dy, tmp); + var tmp = _board.GetPieceColor(moves[0].X, moves[0].Y); + _board.SetPieceColor(moves[0].X, moves[0].Y, PieceColor.None); + _board.SetPieceColor(moves[^1].X, moves[^1].Y, tmp); } } diff --git a/src/ChineseCheckers.Domain/Point.cs b/src/ChineseCheckers.Domain/Point.cs new file mode 100644 index 0000000..af16e2e --- /dev/null +++ b/src/ChineseCheckers.Domain/Point.cs @@ -0,0 +1,2 @@ +namespace ChineseCheckers.Domain; +public record Point(int X, int Y); diff --git a/tests/ChineseCheckers.Tests/MoveChessTest.cs b/tests/ChineseCheckers.Tests/MoveChessTest.cs index bd04060..2f9bbb3 100644 --- a/tests/ChineseCheckers.Tests/MoveChessTest.cs +++ b/tests/ChineseCheckers.Tests/MoveChessTest.cs @@ -75,7 +75,7 @@ public void CanMoveChessButtomRight() .Build(); // Act - game.MoveChess(4, 0, 5, 1); + game.MoveChess([new Point(4, 0), new Point(5, 1)]); // Assert game.Board.GetPieceColor(4, 0).Should().Be(PieceColor.None); @@ -99,7 +99,7 @@ public void CanMoveChessButtomLeft() .Build(); // Act - game.MoveChess(4, 0, 4, 1); + game.MoveChess([new Point(4, 0), new Point(4, 1)]); // Assert game.Board.GetPieceColor(4, 0).Should().Be(PieceColor.None); @@ -109,7 +109,7 @@ public void CanMoveChessButtomLeft() [Description(""" Given: (4, 0) is red, (5, 1) is red, (6, 2) is none When: (4, 0) jump to (6, 2) - Then: InvalidMoveException + Then: Success """)] [TestMethod] public void CanJumpChessButtomRight() @@ -124,7 +124,7 @@ public void CanJumpChessButtomRight() .Build(); // Act - var act = () => game.MoveChess(4, 0, 6, 2); + game.MoveChess([new Point(4, 0), new Point(6, 2)]); // Assert game.Board.GetPieceColor(4, 0).Should().Be(PieceColor.None); @@ -150,7 +150,7 @@ public void CanNotJumpChessButtomRightWhenMiddleNone() .Build(); // Act - var act = () => game.MoveChess(4, 0, 6, 2); + var act = () => game.MoveChess([new Point(4, 0), new Point(6, 2)]); // Assert act.Should().Throw(); @@ -172,14 +172,14 @@ public void CanNotMoveChessButtom() .Build(); // Act - var act = () => game.MoveChess(4, 0, 5, 2); + var act = () => game.MoveChess([new Point(4, 0), new Point(5, 2)]); // Assert act.Should().Throw(); } [Description(""" - Given: (4, 3) is red + Given: (4, 3) is red, (5, 2) is none When: (4, 3) move to (5, 2) Then: InvalidMoveException """)] @@ -190,11 +190,12 @@ public void CanNotMoveChessTopRightRight() var game = new GameBuilder() .WithPlayers("Player 1", "Player 2") .WithBoard(4, 3, PieceColor.Red) + .WithBoard(5, 2, PieceColor.None) .Started(true) .Build(); // Act - var act = () => game.MoveChess(4, 3, 5, 2); + var act = () => game.MoveChess([new Point(4, 3), new Point(5, 2)]); // Assert act.Should().Throw(); @@ -216,7 +217,7 @@ public void CanNotMoveChessTopLeftLeft() .Build(); // Act - var act = () => game.MoveChess(7, 3, 5, 2); + var act = () => game.MoveChess([new Point(7, 3), new Point(5, 2)]); // Assert act.Should().Throw(); @@ -239,7 +240,7 @@ public void CanNotJumpChessTopRightRight() .Build(); // Act - var act = () => game.MoveChess(3, 4, 5, 2); + var act = () => game.MoveChess([new Point(3, 4), new Point(5, 2)]); // Assert act.Should().Throw(); @@ -261,10 +262,9 @@ public void CanNotMoveChessButtomLeftAfterJumpChess() .WithBoard(6, 2, PieceColor.None) .Started(true) .Build(); - game.MoveChess(4, 0, 6, 2); // Act - var act = () => game.MoveChess(6, 2, 6, 3); + var act = () => game.MoveChess([new Point(4, 0), new Point(6, 2), new Point(6, 3)]); // Assert act.Should().Throw();