192 lines
6.2 KiB
C#
192 lines
6.2 KiB
C#
namespace CheckersSpielBot
|
|
{
|
|
public class GameService
|
|
{
|
|
// 0=Empty | 1=Red | 2=Blue | 3=RedKing | 4=BlueKing
|
|
public int[,] Board { get; private set; } = new int[8, 8];
|
|
|
|
public int ActivePlayer { get; private set; } = 1;
|
|
public bool IsChainJumpActive { get; private set; } = false;
|
|
public int ChainJumpRow { get; private set; } = -1;
|
|
public int ChainJumpCol { get; private set; } = -1;
|
|
|
|
public HashSet<(int, int)> MandatoryCapturePieces { get; private set; } = new();
|
|
|
|
private MoveGeneratorService _moveGenerator;
|
|
|
|
public GameService()
|
|
{
|
|
_moveGenerator = new MoveGeneratorService(Board);
|
|
}
|
|
|
|
// Setup
|
|
public void InitializeNewGame()
|
|
{
|
|
Board = new int[8, 8];
|
|
ActivePlayer = 1;
|
|
IsChainJumpActive = false;
|
|
ChainJumpRow = -1;
|
|
ChainJumpCol = -1;
|
|
|
|
_moveGenerator = new MoveGeneratorService(Board);
|
|
|
|
PlaceInitialPieces();
|
|
RefreshMandatoryCaptures();
|
|
}
|
|
|
|
private void PlaceInitialPieces()
|
|
{
|
|
for (int row = 0; row < 3; row++)
|
|
for (int col = 0; col < 8; col++)
|
|
if (BoardHelper.IsPlayableSquare(row, col))
|
|
Board[row, col] = 2; // Blue top
|
|
|
|
for (int row = 5; row < 8; row++)
|
|
for (int col = 0; col < 8; col++)
|
|
if (BoardHelper.IsPlayableSquare(row, col))
|
|
Board[row, col] = 1; // Red bottom
|
|
}
|
|
|
|
// Move generation
|
|
public List<Move> GetLegalMoves(int row, int col, bool capturesOnly) =>
|
|
_moveGenerator.GetLegalMoves(row, col, capturesOnly);
|
|
|
|
// Move execution
|
|
public MoveResult ExecuteMove(int originRow, int originCol, Move move)
|
|
{
|
|
int piece = Board[originRow, originCol];
|
|
|
|
Board[move.DestinationRow, move.DestinationCol] = piece;
|
|
Board[originRow, originCol] = 0;
|
|
|
|
if (move.IsCapture)
|
|
Board[move.CapturedPieceRow, move.CapturedPieceCol] = 0;
|
|
|
|
PromoteToKingIfEligible(move.DestinationRow, move.DestinationCol);
|
|
|
|
ResetChainJump();
|
|
|
|
// Chain jump
|
|
if (move.IsCapture)
|
|
{
|
|
var furtherJumps = GetLegalMoves(move.DestinationRow, move.DestinationCol,
|
|
capturesOnly: true);
|
|
if (furtherJumps.Count > 0)
|
|
{
|
|
IsChainJumpActive = true;
|
|
ChainJumpRow = move.DestinationRow;
|
|
ChainJumpCol = move.DestinationCol;
|
|
return MoveResult.ChainJumpRequired;
|
|
}
|
|
}
|
|
|
|
// Victory check
|
|
if (EvaluateVictoryCondition(out int victor))
|
|
return MoveResult.Victory(victor);
|
|
|
|
// Advance turn
|
|
ActivePlayer = ActivePlayer == 1 ? 2 : 1;
|
|
RefreshMandatoryCaptures();
|
|
return MoveResult.TurnAdvanced;
|
|
}
|
|
|
|
private void PromoteToKingIfEligible(int row, int col)
|
|
{
|
|
if (Board[row, col] == 1 && row == 0) Board[row, col] = 3;
|
|
if (Board[row, col] == 2 && row == 7) Board[row, col] = 4;
|
|
}
|
|
|
|
private void ResetChainJump()
|
|
{
|
|
IsChainJumpActive = false;
|
|
ChainJumpRow = -1;
|
|
ChainJumpCol = -1;
|
|
}
|
|
|
|
// Mandatory captures
|
|
public void RefreshMandatoryCaptures()
|
|
{
|
|
MandatoryCapturePieces = new HashSet<(int, int)>();
|
|
|
|
for (int r = 0; r < 8; r++)
|
|
for (int c = 0; c < 8; c++)
|
|
{
|
|
int p = Board[r, c];
|
|
if (BoardHelper.BelongsToPlayer(p, ActivePlayer) &&
|
|
GetLegalMoves(r, c, capturesOnly: true).Count > 0)
|
|
MandatoryCapturePieces.Add((r, c));
|
|
}
|
|
}
|
|
|
|
// Victory
|
|
private bool EvaluateVictoryCondition(out int victor)
|
|
{
|
|
victor = 0;
|
|
int opponent = ActivePlayer == 1 ? 2 : 1;
|
|
|
|
bool opponentHasPieces = false;
|
|
bool opponentCanMove = false;
|
|
|
|
for (int r = 0; r < 8; r++)
|
|
{
|
|
for (int c = 0; c < 8; c++)
|
|
{
|
|
if (!BoardHelper.BelongsToPlayer(Board[r, c], opponent)) continue;
|
|
opponentHasPieces = true;
|
|
if (GetLegalMoves(r, c, capturesOnly: false).Count > 0)
|
|
{
|
|
opponentCanMove = true;
|
|
break;
|
|
}
|
|
}
|
|
if (opponentCanMove) break;
|
|
}
|
|
|
|
if (!opponentHasPieces || !opponentCanMove)
|
|
{
|
|
victor = ActivePlayer;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public List<Move> GetAllLegalMovesForPlayer(int player)
|
|
{
|
|
var moveGen = new MoveGeneratorService(Board);
|
|
var captures = new List<Move>();
|
|
var normals = new List<Move>();
|
|
|
|
for (int r = 0; r < 8; r++)
|
|
{
|
|
for (int c = 0; c < 8; c++)
|
|
{
|
|
if (!BoardHelper.BelongsToPlayer(Board[r, c], player)) continue;
|
|
|
|
var jumps = moveGen.GetLegalMoves(r, c, capturesOnly: true);
|
|
if (jumps.Count > 0) { captures.AddRange(jumps); continue; }
|
|
|
|
normals.AddRange(moveGen.GetLegalMoves(r, c, capturesOnly: false));
|
|
}
|
|
}
|
|
|
|
return captures.Count > 0 ? captures : normals;
|
|
}
|
|
|
|
#region helpers
|
|
public bool BelongsToActivePlayer(int piece) =>
|
|
BoardHelper.BelongsToPlayer(piece, ActivePlayer);
|
|
public (int red, int blue) GetPieceCounts()
|
|
{
|
|
int red = 0, blue = 0;
|
|
for (int r = 0; r < 8; r++)
|
|
for (int c = 0; c < 8; c++)
|
|
{
|
|
int p = Board[r, c];
|
|
if (p == 1 || p == 3) red++;
|
|
else if (p == 2 || p == 4) blue++;
|
|
}
|
|
return (red, blue);
|
|
}
|
|
#endregion
|
|
}
|
|
} |