This commit is contained in:
2021-12-29 16:27:43 -06:00
parent a2f3abb94e
commit 9ec91615a3
5 changed files with 157 additions and 102 deletions

View File

@@ -31,25 +31,21 @@
public MoveResult CanMove(string from, string to, bool isPromotion)
{
// TODO: ShogiBoardState.FromBoardNotation should not throw an execption in this query method.
var fromVector = ShogiBoardState.FromBoardNotation(from);
var toVector = ShogiBoardState.FromBoardNotation(to);
var simulator = new StandardRules(new ShogiBoardState(board));
return simulator.Move(fromVector, toVector, isPromotion);
return simulator.Move(from, to, isPromotion);
}
public MoveResult CanMove(WhichPiece pieceInHand, string to)
{
var toVector = ShogiBoardState.FromBoardNotation(to);
var simulator = new StandardRules(new ShogiBoardState(board));
return simulator.Move(pieceInHand, toVector);
return simulator.Move(pieceInHand, to);
}
public void Move(string from, string to, bool isPromotion)
{
var fromVector = ShogiBoardState.FromBoardNotation(from);
var toVector = ShogiBoardState.FromBoardNotation(to);
var moveResult = rules.Move(fromVector, toVector, isPromotion);
var moveResult = rules.Move(from, to, isPromotion);
if (!moveResult.Success)
{
throw new InvalidOperationException(moveResult.Reason);

View File

@@ -1,5 +1,7 @@
using System.Numerics;
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Shogi.Domain.UnitTests")]
namespace Shogi.Domain
{
internal class StandardRules
@@ -39,11 +41,13 @@ namespace Shogi.Domain
/// <summary>
/// Move a piece from a board tile to another board tile.
/// </summary>
/// <param name="from">The position of the piece being moved expressed in board notation.</param>
/// <param name="to">The target position 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>
/// <returns>A <see cref="MoveResult" /> describing the success or failure of the simulation.</returns>
public MoveResult Move(Vector2 from, Vector2 to, bool isPromotion = false)
public MoveResult Move(string fromNotation, string toNotation, bool isPromotion = false)
{
var from = ShogiBoardState.FromBoardNotation(fromNotation);
var to = ShogiBoardState.FromBoardNotation(toNotation);
var fromPiece = board[from];
if (fromPiece == null)
{
@@ -55,7 +59,7 @@ namespace Shogi.Domain
return new MoveResult(false, "Not allowed to move the opponents piece");
}
if (IsPathable(from, to) == false)
if (ShogiIsPathable(from, to) == false)
{
return new MoveResult(false, $"Proposed move is not part of the move-set for piece {fromPiece.WhichPiece}.");
}
@@ -106,8 +110,9 @@ namespace Shogi.Domain
/// <param name="pieceInHand"></param>
/// <param name="to">The target position expressed in board notation.</param>
/// <returns>A <see cref="MoveResult" /> describing the success or failure of the simulation.</returns>
public MoveResult Move(WhichPiece pieceInHand, Vector2 to)
public MoveResult Move(WhichPiece pieceInHand, string toNotation)
{
var to = ShogiBoardState.FromBoardNotation(toNotation);
var index = board.Hand.FindIndex(p => p.WhichPiece == pieceInHand);
if (index == -1)
{
@@ -150,7 +155,7 @@ namespace Shogi.Domain
return new MoveResult(true);
}
private bool IsPathable(Vector2 from, Vector2 to)
private bool ShogiIsPathable(Vector2 from, Vector2 to)
{
var piece = board[from];
if (piece == null) return false;
@@ -255,7 +260,9 @@ namespace Shogi.Domain
PathEvery(from, (other, position) =>
{
var simulationBoard = new StandardRules(new ShogiBoardState(board));
var simulationResult = simulationBoard.Move(from, position, false);
var fromNotation = ShogiBoardState.ToBoardNotation(from);
var toNotation = ShogiBoardState.ToBoardNotation(position);
var simulationResult = simulationBoard.Move(fromNotation, toNotation, false);
if (simulationResult.Success)
{
if (!EvaluateCheckAfterMove(from, position, board.InCheck.Value))
@@ -288,7 +295,7 @@ namespace Shogi.Domain
if (piece == null) return false;
var path = FindDirectionTowardsDestination(GetMoveSet(piece.WhichPiece).GetMoves(piece.IsUpsideDown), origin, destination);
if (!IsPathable(origin, destination))
if (!IsPathable(origin, destination, path.Direction))
{
// Assumption: if a single best-choice step towards the destination cannot happen, no pathing can happen.
return false;
@@ -341,6 +348,25 @@ namespace Shogi.Domain
}
}
public static bool IsPathable(Vector2 origin, Vector2 destination, Vector2 direction)
{
var next = Vector2.Add(origin, direction);
if (Vector2.Distance(next, destination) >= Vector2.Distance(origin, destination)) return false;
var slope = (destination.Y - origin.Y) / (destination.X - origin.X);
if (float.IsInfinity(slope))
{
return next.X == destination.X;
}
else
{
// b = -mx + y
var yIntercept = -slope * origin.X + origin.Y;
// y = mx + b
return next.Y == slope * next.X + yIntercept;
}
}
/// <summary>
/// Path the line from origin to destination, ignoring any Paths defined by the element at origin.
/// </summary>