You've already forked lazarus-ccr
Starts commiting the KCChess engine
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@1871 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
534
applications/fpchess/engines/kcchess/MOVES.PAS
Normal file
534
applications/fpchess/engines/kcchess/MOVES.PAS
Normal file
@ -0,0 +1,534 @@
|
||||
{****************************************************************************}
|
||||
{* MOVES.PAS: This file contains the routines which generate, move, and *}
|
||||
{* otherwise have to do (on a low level) with moves. *}
|
||||
{****************************************************************************}
|
||||
|
||||
{****************************************************************************}
|
||||
{* Attacked By: Given the row and column of a square, this routine will *}
|
||||
{* tally the number of other pieces which attack (enemy pieces) or protect *}
|
||||
{* (friendly pieces) the piece on that square. This is accomplished by *}
|
||||
{* looking around the piece to all other locations from which a piece *}
|
||||
{* could protect or protect. This routine does not count an attack by *}
|
||||
{* en passent. This routine is called to see if a king is in check and *}
|
||||
{* as part of the position strength calculation. *}
|
||||
{****************************************************************************}
|
||||
procedure AttackedBy (row, col : RowColType; var Attacked, _Protected : integer);
|
||||
var dir, i, distance : integer;
|
||||
PosRow, PosCol, IncRow, IncCol : RowColType;
|
||||
FriendColor, EnemyColor : PieceColorType;
|
||||
begin
|
||||
{*** initialize ***}
|
||||
Attacked := 0;
|
||||
_Protected := 0;
|
||||
FriendColor := Board[row, col].color;
|
||||
if (FriendColor = C_WHITE) then begin
|
||||
dir := 1; {*** row displacement from which an enemy pawn would attack ***}
|
||||
EnemyColor := C_BLACK;
|
||||
end else begin
|
||||
dir := -1;
|
||||
EnemyColor := C_WHITE;
|
||||
end;
|
||||
|
||||
{*** count number of attacking pawns ***}
|
||||
with Board[row + dir, col - 1] do
|
||||
if (image = PAWN) and (color = EnemyColor) then Attacked := Attacked + 1;
|
||||
with Board[row + dir, col + 1] do
|
||||
if (image = PAWN) and (color = EnemyColor) then Attacked := Attacked + 1;
|
||||
|
||||
{*** count number of protecting pawns ***}
|
||||
with Board[row - dir, col - 1] do
|
||||
if (image = PAWN) and (color = FriendColor) then _Protected := _Protected + 1;
|
||||
with Board[row - dir, col + 1] do
|
||||
if (image = PAWN) and (color = FriendColor) then _Protected := _Protected + 1;
|
||||
|
||||
{*** check for a knight in all positions from which it could attack/protect ***}
|
||||
for i := 1 to PossibleMoves[KNIGHT].NumDirections do begin
|
||||
with PossibleMoves[KNIGHT].UnitMove[i] do begin
|
||||
PosRow := row + DirRow;
|
||||
PosCol := col + DirCol;
|
||||
end;
|
||||
if (Board[PosRow, PosCol].image = KNIGHT) then begin
|
||||
{*** color determines if knight is attacking or protecting ***}
|
||||
if (Board[PosRow, PosCol].color = FriendColor) then
|
||||
_Protected := _Protected + 1
|
||||
else
|
||||
Attacked := Attacked + 1;
|
||||
end;
|
||||
end;
|
||||
|
||||
{*** check for king, queen, bishop, and rook attacking or protecting ***}
|
||||
for i := 1 to 8 do begin
|
||||
{*** get the current search direction ***}
|
||||
with PossibleMoves[QUEEN].UnitMove[i] do begin
|
||||
IncRow := DirRow;
|
||||
IncCol := DirCol;
|
||||
end;
|
||||
{*** set distance countdown and search position ***}
|
||||
distance := 7;
|
||||
PosRow := row;
|
||||
PosCol := col;
|
||||
|
||||
{*** search until something is run into ***}
|
||||
while distance > 0 do begin
|
||||
{*** get new position and check it ***}
|
||||
PosRow := PosRow + IncRow;
|
||||
PosCol := PosCol + IncCol;
|
||||
with Board[PosRow, PosCol] do begin
|
||||
if ValidSquare then begin
|
||||
if image = BLANK then
|
||||
{*** continue searching if search_square is blank ***}
|
||||
distance := distance - 1
|
||||
else begin
|
||||
{*** separate cases of straight or diagonal attack/protect ***}
|
||||
if (IncRow = 0) or (IncCol = 0) then begin
|
||||
{*** straight: check for queen, rook, or one-away king ***}
|
||||
if (image = QUEEN) or (image = ROOK) or
|
||||
((image = KING) and (distance = 7)) then
|
||||
if (color = FriendColor) then
|
||||
_Protected := _Protected + 1
|
||||
else
|
||||
Attacked := Attacked + 1;
|
||||
end else begin
|
||||
{*** diagonal: check for queen, bishop, or one-away king ***}
|
||||
if (image = QUEEN) or (image = BISHOP) or
|
||||
((image = KING) and (distance = 7)) then
|
||||
if (color = FriendColor) then
|
||||
_Protected := _Protected + 1
|
||||
else
|
||||
Attacked := Attacked + 1;
|
||||
end;
|
||||
{*** force to stop searching if piece encountered ***}
|
||||
distance := 0;
|
||||
end;
|
||||
end else
|
||||
{*** force to stop searching if border of board encountered ***}
|
||||
distance := 0;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end; {AttackedBy}
|
||||
|
||||
{****************************************************************************}
|
||||
{* Gen Move List: Returns the list of all possible moves for the given *}
|
||||
{* player. Searches the board for all pieces of the given color, and *}
|
||||
{* adds all of the possible moves for that piece to the move list to be *}
|
||||
{* returned. *}
|
||||
{****************************************************************************}
|
||||
procedure GenMoveList (Turn : PieceColorType; var Movelist : MoveListType);
|
||||
var row, col : RowColType;
|
||||
|
||||
{----------------------------------------------------------------------------}
|
||||
{ Gen Piece Move List: Generates all of the moves for the given piece at }
|
||||
{ the given board position, and adds them to the move list for the player. }
|
||||
{ If the piece is a pawn then all of the moves are checked by brute force. }
|
||||
{ If the piece is a king, then the castling move is checked by brute force. }
|
||||
{ For all other moves, each allowed direction for the piece is checked, and }
|
||||
{ each square off in that direction from the piece, up to the piece's move }
|
||||
{ distance limit, is added to the list, until the edge of the board is }
|
||||
{ encountered or another piece is encountered. If the piece encountered }
|
||||
{ is an enemy piece, then taking that enemy piece is added to the player's }
|
||||
{ move list as well. }
|
||||
{----------------------------------------------------------------------------}
|
||||
procedure GenPieceMoveList (Piece : PieceType; row, col : integer);
|
||||
var dir : integer;
|
||||
PosRow, PosCol : RowColType; {*** current scanning position ***}
|
||||
OrigRow, OrigCol : RowColType; {*** location to search from ***}
|
||||
IncRow, IncCol : integer; {*** displacement to add to scanning position ***}
|
||||
DirectionNum : 1..8;
|
||||
distance : 0..7;
|
||||
EPPossible : boolean;
|
||||
EnemyColor : PieceColorType;
|
||||
Attacked, _Protected : integer;
|
||||
|
||||
{----------------------------------------------------------------------------}
|
||||
{ Gen Add Move: Adds the move to be generated to the player's move list. }
|
||||
{ Given the location and displacement to move the piece, takes PieceTaken }
|
||||
{ and PieceMoved from the current board configuration. }
|
||||
{----------------------------------------------------------------------------}
|
||||
procedure GenAddMove (row, col : RowColType; drow, dcol : integer);
|
||||
begin
|
||||
MoveList.NumMoves := MoveList.NumMoves + 1;
|
||||
with MoveList.Move[MoveList.NumMoves] do begin
|
||||
FromRow := row;
|
||||
FromCol := col;
|
||||
ToRow := row + drow;
|
||||
ToCol := col + dcol;
|
||||
PieceTaken := Board [ToRow, ToCol];
|
||||
PieceMoved := Board [FromRow, FromCol];
|
||||
{*** get image of piece after it is moved... ***}
|
||||
{*** same as before the movement except in the case of pawn promotion ***}
|
||||
MovedImage := Board [FromRow, FromCol].image;
|
||||
end;
|
||||
end; {GenAddMove}
|
||||
|
||||
{----------------------------------------------------------------------------}
|
||||
{ Gen Add Pawn Move: Adds the move to be generated for a pawn to the }
|
||||
{ player's move list and checks for pawn promotion. }
|
||||
{----------------------------------------------------------------------------}
|
||||
procedure GenAddPawnMove (row, col : RowColType; drow, dcol : integer);
|
||||
begin
|
||||
GenAddMove (row, col, drow, dcol);
|
||||
{*** if pawn will move to an end row ***}
|
||||
if (row + drow = 1) or (row + drow = 8) then
|
||||
{*** assume the pawn will be promoted to a queen ***}
|
||||
MoveList.Move[MoveList.NumMoves].MovedImage := QUEEN;
|
||||
end; {GenAddPawnMove}
|
||||
|
||||
{----------------------------------------------------------------------------}
|
||||
begin {GenPieceMoveList}
|
||||
OrigRow := row;
|
||||
OrigCol := col;
|
||||
|
||||
{*** pawn movement is a special case ***}
|
||||
if Piece.image = PAWN then begin
|
||||
{*** check for En Passent ***}
|
||||
if Piece.color = C_WHITE then begin
|
||||
dir := 1;
|
||||
EPPossible := (row = 5);
|
||||
EnemyColor := C_BLACK;
|
||||
end else begin
|
||||
dir := -1;
|
||||
EPPossible := (row = 4);
|
||||
EnemyColor := C_WHITE;
|
||||
end;
|
||||
{*** make sure enemy's last move was push pawn two, beside player's pawn ***}
|
||||
with Player[EnemyColor].LastMove do begin
|
||||
if EPPossible and Game.EnPassentAllowed and (FromRow <> NULL_MOVE) then
|
||||
if (abs (FromRow - ToRow) = 2) then
|
||||
if (abs (ToCol - col) = 1) and (PieceMoved.image = PAWN) then
|
||||
GenAddPawnMove (row, col, dir, ToCol - col);
|
||||
end;
|
||||
|
||||
{*** square pawn is moving to (1 or 2 ahead) is guaranteed to be valid ***}
|
||||
if (Board [row + dir, col].image = BLANK) then begin
|
||||
GenAddPawnMove (row, col, dir, 0);
|
||||
{*** see if pawn can move two ***}
|
||||
if (not Piece.HasMoved) and (Board [row + 2*dir, col].image = BLANK) then
|
||||
GenAddPawnMove (row, col, 2*dir, 0);
|
||||
end;
|
||||
|
||||
{*** check for pawn takes to left ***}
|
||||
with Board[row + dir, col - 1] do begin
|
||||
if (image <> BLANK) and (color = EnemyColor) and ValidSquare then
|
||||
GenAddPawnMove (row, col, dir, -1);
|
||||
end;
|
||||
|
||||
{*** check for pawn takes to right ***}
|
||||
with Board[row + dir, col + 1] do begin
|
||||
if (image <> BLANK) and (color = EnemyColor) and ValidSquare then
|
||||
GenAddPawnMove (row, col, dir, +1);
|
||||
end;
|
||||
end else begin
|
||||
{*** check for the king castling ***}
|
||||
if (Piece.image = KING) and (not Piece.HasMoved) and (not Player[Turn].InCheck) then begin
|
||||
{*** check for castling to left ***}
|
||||
if (Board [row, 1].image = ROOK) and (not Board [row, 1].HasMoved) then
|
||||
if (Board [row, 2].image = BLANK) and (Board [row, 3].image = BLANK)
|
||||
and (Board [row, 4].image = BLANK) then begin
|
||||
{*** make sure not moving through check ***}
|
||||
Board [row, 4].color := Turn;
|
||||
AttackedBy (row, 4, Attacked, _Protected);
|
||||
if (Attacked = 0) then
|
||||
GenAddMove (row, 5, 0, -2);
|
||||
end;
|
||||
|
||||
{*** check for castling to right ***}
|
||||
if (Board [row, 8].image = ROOK) and (not Board [row, 8].HasMoved) then
|
||||
if (Board [row, 6].image = BLANK) and (Board [row, 7].image = BLANK) then begin
|
||||
{*** make sure not moving through check ***}
|
||||
Board [row, 6].color := Turn;
|
||||
AttackedBy (row, 6, Attacked, _Protected);
|
||||
if (Attacked = 0) then
|
||||
GenAddMove (row, 5, 0, 2);
|
||||
end;
|
||||
end;
|
||||
|
||||
{*** Normal moves: for each allowed direction of the piece... ***}
|
||||
for DirectionNum := 1 to PossibleMoves [Piece.image].NumDirections do begin
|
||||
{*** initialize search ***}
|
||||
distance := PossibleMoves [Piece.image].MaxDistance;
|
||||
PosRow := OrigRow;
|
||||
PosCol := OrigCol;
|
||||
with PossibleMoves[Piece.image].UnitMove[DirectionNum] do begin
|
||||
IncRow := DirRow;
|
||||
IncCol := DirCol;
|
||||
end;
|
||||
|
||||
{*** search until something is run into ***}
|
||||
while distance > 0 do begin
|
||||
PosRow := PosRow + IncRow;
|
||||
PosCol := PosCol + IncCol;
|
||||
with Board [PosRow, PosCol] do begin
|
||||
if (not ValidSquare) then
|
||||
distance := 0
|
||||
else begin
|
||||
if image = BLANK then begin
|
||||
{*** sqaure is empty: can move there; keep searching ***}
|
||||
GenAddMove (OrigRow, OrigCol, PosRow - OrigRow, PosCol - OrigCol);
|
||||
distance := distance - 1;
|
||||
end else begin
|
||||
{*** piece is there: can take if enemy; stop searching ***}
|
||||
distance := 0;
|
||||
if color <> Turn then
|
||||
GenAddMove (OrigRow, OrigCol, PosRow - OrigRow, PosCol - OrigCol);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end; {GenPieceMoveList}
|
||||
|
||||
{----------------------------------------------------------------------------}
|
||||
begin {GenMoveList}
|
||||
{*** empty out player's move list ***}
|
||||
MoveList.NumMoves := 0;
|
||||
|
||||
{*** search for player's pieces on board ***}
|
||||
for row := 1 to BOARD_SIZE do
|
||||
for col := 1 to BOARD_SIZE do
|
||||
with Board [row, col] do begin
|
||||
{*** if player's piece, add its moves ***}
|
||||
if (image <> BLANK) and (color = Turn) then
|
||||
GenPieceMoveList (Board [row, col], row, col);
|
||||
end;
|
||||
end; {GenMoveList}
|
||||
|
||||
{****************************************************************************}
|
||||
{* Make Move: Update the Board to reflect making the given movement. If *}
|
||||
{* given is a PermanentMove, then the end of game pointers is set to the *}
|
||||
{* current move. Returns the score for the move, which is given by the *}
|
||||
{* number of points for the piece taken. *}
|
||||
{****************************************************************************}
|
||||
procedure MakeMove (Movement : MoveType; PermanentMove : boolean; var Score : integer);
|
||||
var Row: RowColType;
|
||||
Attacked, _Protected : integer;
|
||||
|
||||
begin
|
||||
Score := 0;
|
||||
{*** update board for most moves ***}
|
||||
with Movement do begin
|
||||
{*** pick piece up ***}
|
||||
Board[FromRow, FromCol].image := BLANK;
|
||||
{*** put piece down ***}
|
||||
Board[ToRow, ToCol] := PieceMoved;
|
||||
end;
|
||||
|
||||
{*** check for en passent, pawn promotion, and castling ***}
|
||||
case Movement.PieceMoved.image of
|
||||
PAWN: begin
|
||||
{*** en passent: blank out square taken; get points ***}
|
||||
if (Movement.FromCol <> Movement.ToCol) and (Movement.PieceTaken.image = BLANK) then begin
|
||||
Board[Movement.FromRow, Movement.ToCol].image := BLANK;
|
||||
Score := Score + CapturePoints[PAWN];
|
||||
end;
|
||||
|
||||
{*** pawn promotion: use the after-moved image; get trade-up points ***}
|
||||
if Movement.PieceMoved.color = C_WHITE then Row := 8 else Row := 1;
|
||||
if Movement.ToRow = Row then begin
|
||||
Board[Movement.ToRow, Movement.ToCol].image := Movement.MovedImage;
|
||||
Score := Score + CapturePoints[Movement.MovedImage] - CapturePoints[PAWN];
|
||||
end;
|
||||
end;
|
||||
|
||||
KING: begin
|
||||
{*** update king position in player record ***}
|
||||
with Player[Movement.PieceMoved.color] do begin
|
||||
KingRow := Movement.ToRow;
|
||||
KingCol := Movement.ToCol;
|
||||
end;
|
||||
|
||||
{*** castling left/right: move the rook too ***}
|
||||
if abs (Movement.FromCol - Movement.ToCol) > 1 then begin
|
||||
if (Movement.ToCol < Movement.FromCol) then begin
|
||||
Board[Movement.FromRow, 4] := Board[Movement.FromRow, 1];
|
||||
Board[Movement.FromRow, 4].HasMoved := true;
|
||||
Board[Movement.FromRow, 1].image := BLANK;
|
||||
end else begin
|
||||
Board[Movement.FromRow, 6] := Board[Movement.FromRow, 8];
|
||||
Board[Movement.FromRow, 6].HasMoved := true;
|
||||
Board[Movement.FromRow, 8].image := BLANK;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
{*** update player attributes ***}
|
||||
Player[Movement.PieceMoved.color].LastMove := Movement;
|
||||
Player[Movement.PieceMoved.color].InCheck := false;
|
||||
with Player[EnemyColor[Movement.PieceMoved.color]] do begin
|
||||
AttackedBy (KingRow, KingCol, Attacked, _Protected);
|
||||
InCheck := Attacked <> 0;
|
||||
end;
|
||||
|
||||
{*** remember that piece has been moved, get score ***}
|
||||
Board[Movement.ToRow, Movement.ToCol].HasMoved := true;
|
||||
Score := Score + CapturePoints[Movement.PieceTaken.image];
|
||||
|
||||
{*** update game attributes ***}
|
||||
Game.MoveNum := Game.MoveNum + 1;
|
||||
Game.MovesPointer := Game.MovesPointer + 1;
|
||||
Game.Move[Game.MovesPointer] := Movement;
|
||||
if PermanentMove then
|
||||
Game.MovesStored := Game.MovesPointer;
|
||||
Game.InCheck[Game.MovesPointer] := Attacked <> 0;
|
||||
|
||||
{*** update nondevelopmental moves counter ***}
|
||||
if (Movement.PieceMoved.image = PAWN) or (Movement.PieceTaken.image <> BLANK) then begin
|
||||
Game.NonDevMoveCount[Game.MovesPointer] := 0;
|
||||
end else begin
|
||||
{*** if 50 nondevelopmental moves in a row: stalemate ***}
|
||||
Game.NonDevMoveCount[Game.MovesPointer] := Game.NonDevMoveCount[Game.MovesPointer-1] + 1;
|
||||
if (Game.NonDevMoveCount[Game.MovesPointer] >= NON_DEV_MOVE_LIMIT) then
|
||||
Score := STALE_SCORE;
|
||||
end;
|
||||
end; {MakeMove}
|
||||
|
||||
{****************************************************************************}
|
||||
{* Un Make Move: Updates the board for taking back the last made move. *}
|
||||
{* This routine returns (is not given) the last made movement (so it may *}
|
||||
{* be passed to DisplayUnMadeMove). *}
|
||||
{****************************************************************************}
|
||||
procedure UnMakeMove (var Movement: Movetype);
|
||||
begin
|
||||
{*** make sure there is a move to un-make ***}
|
||||
if (Game.MovesPointer > 0) then begin
|
||||
Movement := Game.Move[Game.MovesPointer];
|
||||
{*** restore whether player who made move was in check ***}
|
||||
Player[Movement.PieceMoved.color].InCheck := Game.InCheck[Game.MovesPointer - 1];
|
||||
{*** the enemy could not have been in check ***}
|
||||
Player[EnemyColor[Movement.PieceMoved.color]].InCheck := false;
|
||||
{*** restore the From and To squares ***}
|
||||
Board[Movement.FromRow, Movement.FromCol] := Movement.PieceMoved;
|
||||
Board[Movement.ToRow, Movement.ToCol] := Movement.PieceTaken;
|
||||
|
||||
{*** special cases ***}
|
||||
case Movement.PieceMoved.image of
|
||||
KING: begin
|
||||
{*** restore position of king in player attributes ***}
|
||||
with Player[Movement.PieceMoved.color] do begin
|
||||
KingRow := Movement.FromRow;
|
||||
KingCol := Movement.FromCol;
|
||||
end;
|
||||
{*** un-castle left/right if applicable ***}
|
||||
if abs (Movement.FromCol - Movement.ToCol) > 1 then begin
|
||||
if (Movement.FromCol < Movement.ToCol) then begin
|
||||
Board[Movement.FromRow, 8] := Board[Movement.FromRow, 6];
|
||||
Board[Movement.FromRow, 6].image := BLANK;
|
||||
Board[Movement.FromRow, 8].HasMoved := false;
|
||||
end else begin
|
||||
Board[Movement.FromRow, 1] := Board[Movement.FromRow, 4];
|
||||
Board[Movement.FromRow, 4].image := BLANK;
|
||||
Board[Movement.FromRow, 1].HasMoved := false;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
PAWN:
|
||||
{*** un-en passent: restore the pawn that was taken ***}
|
||||
if (Movement.FromCol <> Movement.ToCol) and (Movement.PieceTaken.image = BLANK) then
|
||||
with Board[Movement.FromRow, Movement.ToCol] do begin
|
||||
image := PAWN;
|
||||
if Movement.PieceMoved.color = C_WHITE then
|
||||
color := C_BLACK
|
||||
else
|
||||
color := C_WHITE;
|
||||
HasMoved := true;
|
||||
end;
|
||||
end;
|
||||
|
||||
{*** roll back move number and pointer ***}
|
||||
Game.MoveNum := Game.MoveNum - 1;
|
||||
Game.MovesPointer := Game.MovesPointer - 1;
|
||||
|
||||
{*** restore player previous move attributes ***}
|
||||
if (Game.MovesPointer > 1) then
|
||||
Player[Movement.PieceMoved.color].LastMove := Game.Move[Game.MovesPointer - 1]
|
||||
else
|
||||
Player[Movement.PieceMoved.color].LastMove.FromRow := NULL_MOVE;
|
||||
end else
|
||||
{*** indicate no move to take back ***}
|
||||
Movement.FromRow := NULL_MOVE;
|
||||
end; {UnMakeMove}
|
||||
|
||||
{****************************************************************************}
|
||||
{* Trim Checks: Given a move list, remove all of the moves which would *}
|
||||
{* result in the given player moving into check. This is not done *}
|
||||
{* directly by GenMoveList because it is an expensive operation, since *}
|
||||
{* each move will have to be made and then unmade. This routine is called *}
|
||||
{* by the Human Movement routine. The Computer Movement routine *}
|
||||
{* incorporates this code into its code, since the moves have to be made *}
|
||||
{* and unmade there anyway. *}
|
||||
{****************************************************************************}
|
||||
procedure TrimChecks (Turn : PieceColorType; var MoveList : MoveListType);
|
||||
var DummyMove : MoveType;
|
||||
DummyScore, Attacked, _Protected : integer;
|
||||
ValidMoves, i : integer;
|
||||
|
||||
begin
|
||||
ValidMoves := 0;
|
||||
for i := 1 to MoveList.NumMoves do begin
|
||||
MakeMove (MoveList.Move[i], false, DummyScore);
|
||||
{*** check if the king is attacked (in check) ***}
|
||||
AttackedBy (Player[Turn].KingRow, Player[Turn].KingCol, Attacked, _Protected);
|
||||
if Attacked = 0 then begin
|
||||
{*** if not in check, then re-put valid move ***}
|
||||
ValidMoves := ValidMoves + 1;
|
||||
MoveList.Move[ValidMoves] := MoveList.Move[i];
|
||||
end;
|
||||
UnMakeMove (DummyMove);
|
||||
end;
|
||||
MoveList.NumMoves := ValidMoves;
|
||||
end; {TrimChecks}
|
||||
|
||||
{****************************************************************************}
|
||||
{* Randomize Move List: Scrambles the order of the given move list. This *}
|
||||
{* is done to make choosing between tie scores random. It is necassary *}
|
||||
{* to scramble the moves here because the move list will always be *}
|
||||
{* generated in the same order. *}
|
||||
{****************************************************************************}
|
||||
procedure RandomizeMoveList (var MoveList : MoveListType);
|
||||
var i, Exch : integer;
|
||||
ExchMove : MoveType;
|
||||
begin
|
||||
for i := 1 to MoveList.NumMoves do begin
|
||||
{*** swap the current move with some random other one ***}
|
||||
Exch := Random (MoveList.NumMoves) + 1;
|
||||
ExchMove := MoveList.Move[Exch];
|
||||
MoveList.Move[Exch] := MoveList.Move[i];
|
||||
MoveList.Move[i] := ExchMove;
|
||||
end;
|
||||
end; {RandomizeMoveList}
|
||||
|
||||
{****************************************************************************}
|
||||
{* Goto Move: Rolls back/forth the game to the given move number. Each *}
|
||||
{* move between the current move and the destination is made/retracted to *}
|
||||
{* update the board and other game status information. If the given move *}
|
||||
{* number is too small or too large, the game is rolled to the first/last *}
|
||||
{* move. *}
|
||||
{****************************************************************************}
|
||||
procedure GotoMove (GivenMoveTo : integer);
|
||||
var Movement : MoveType;
|
||||
DummyScore : integer;
|
||||
MoveTo, BeginMoveNum, EndMoveNum : integer;
|
||||
begin
|
||||
{*** check the bounds of given move number ***}
|
||||
MoveTo := GivenMoveTo;
|
||||
BeginMoveNum := Game.MoveNum - Game.MovesPointer;
|
||||
EndMoveNum := Game.MoveNum + (Game.MovesStored - Game.MovesPointer);
|
||||
if (MoveTo < BeginMoveNum) then MoveTo := BeginMoveNum;
|
||||
if (MoveTo > EndMoveNum) then MoveTo := EndMoveNum;
|
||||
|
||||
{*** make / retract moves of the game until the destination is reached ***}
|
||||
while (Game.MoveNum <> MoveTo) do begin
|
||||
if MoveTo > Game.MoveNum then begin
|
||||
Movement := Game.Move[Game.MovesPointer + 1];
|
||||
MakeMove (Movement, false, DummyScore);
|
||||
end else
|
||||
UnMakeMove (Movement);
|
||||
end;
|
||||
Game.GameFinished := false;
|
||||
end;
|
||||
|
||||
{*** end of the MOVES.PAS include file ***}
|
||||
|
148
applications/fpchess/engines/kcchess/mod_kcchess.pas
Normal file
148
applications/fpchess/engines/kcchess/mod_kcchess.pas
Normal file
@ -0,0 +1,148 @@
|
||||
unit mod_kcchess;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils;
|
||||
|
||||
const HIGH = 52; WIDE = 52; SINGLE_IMAGE_SIZE = 1500;
|
||||
BOARD_SIZE = 8; ROW_NAMES = '12345678'; COL_NAMES = 'ABCDEFGH';
|
||||
BOARD_X1 = 19; BOARD_Y1 = 4; BOARD_X2 = 434; BOARD_Y2 = 419;
|
||||
INSTR_LINE = 450; MESSAGE_X = 460;
|
||||
NULL_MOVE = -1; STALE_SCORE = -1000;
|
||||
MOVE_LIST_LEN = 300; GAME_MOVE_LEN = 500;
|
||||
MAX_LOOKAHEAD = 9; PLUNGE_DEPTH = -1; NON_DEV_MOVE_LIMIT = 50;
|
||||
|
||||
{*** pixel rows to print various messages in the conversation area ***}
|
||||
MSG_MOVE = 399; MSG_BOXX1 = 464; MSG_BOXX2 = 635; MSG_MIDX = 550;
|
||||
MSG_WHITE = 165; MSG_BLACK = 54; MSG_MOVENUM = 358; MSG_PLHI = 90;
|
||||
MSG_TURN = 375; MSG_SCAN = 416; MSG_CHI = 17; MSG_HINT = 416;
|
||||
MSG_CONV = 40; MSG_WARN50 = 277; MSG_TIME_LIMIT = 258;
|
||||
MSG_SCORE = 318; MSG_POS_EVAL = 344; MSG_ENEMY_SCORE = 331;
|
||||
|
||||
type PieceImageType = (BLANK, PAWN, BISHOP, KNIGHT, ROOK, QUEEN, KING);
|
||||
PieceColorType = (C_WHITE, C_BLACK);
|
||||
{*** the color of the actual square ***}
|
||||
SquareColorType = (S_LIGHT, S_DARK, S_CURSOR);
|
||||
{*** which instructions to print at bottom of screen ***}
|
||||
InstructionType = (INS_MAIN, INS_GAME, INS_SETUP, INS_PLAYER, INS_SETUP_COLOR,
|
||||
INS_SETUP_MOVED, INS_SETUP_MOVENUM, INS_FILE, INS_FILE_INPUT,
|
||||
INS_WATCH, INS_GOTO, INS_OPTIONS, INS_PAWN_PROMOTE);
|
||||
{*** there is a two-thick border of 'dead squares' around the main board ***}
|
||||
RowColType = -1..10;
|
||||
{*** Turbo Pascal requires that parameter string be declared like this ***}
|
||||
string2 = string[2];
|
||||
string10 = string[10];
|
||||
string80 = string[80];
|
||||
{*** memory for a 52*52 pixel image ***}
|
||||
SingleImageType = array [1..SINGLE_IMAGE_SIZE] of byte;
|
||||
{*** images must be allocated on the heap because the stack is not large enough ***}
|
||||
ImageTypePt = ^ImageType;
|
||||
ImageType = array [PieceImageType, PieceColorType, SquareColorType] of SingleImageType;
|
||||
{*** text file records for help mode ***}
|
||||
HelpPageType = array [1..22] of string80;
|
||||
|
||||
{*** directions to scan when looking for all possible moves of a piece ***}
|
||||
PossibleMovesType = array [PieceImageType] of record
|
||||
NumDirections : 1..8;
|
||||
MaxDistance : 1..7;
|
||||
UnitMove : array [1..8] of record
|
||||
DirRow, DirCol: -2..2;
|
||||
end;
|
||||
end;
|
||||
|
||||
{*** attributes for a piece or board square ***}
|
||||
PieceType = record
|
||||
image : PieceImageType;
|
||||
color : PieceColorType;
|
||||
HasMoved : boolean;
|
||||
ValidSquare : boolean;
|
||||
end;
|
||||
|
||||
BoardType = array [RowColType, RowColType] of PieceType;
|
||||
|
||||
{*** representation of the movement of a piece, or 'ply' ***}
|
||||
MoveType = record
|
||||
FromRow, FromCol, ToRow, ToCol : RowColType;
|
||||
PieceMoved : PieceType;
|
||||
PieceTaken : PieceType;
|
||||
{*** image after movement - used for pawn promotion ***}
|
||||
MovedImage : PieceImageType;
|
||||
end;
|
||||
|
||||
{*** string of moves - used to store list of all possible moves ***}
|
||||
MoveListType = record
|
||||
NumMoves : 0..MOVE_LIST_LEN;
|
||||
Move : array [1..MOVE_LIST_LEN] of MoveType;
|
||||
end;
|
||||
|
||||
{*** attributes of both players ***}
|
||||
PlayerType = array [PieceColorType] of record
|
||||
Name : string[20];
|
||||
IsHuman : boolean;
|
||||
LookAhead : 0..MAX_LOOKAHEAD;
|
||||
PosEval : boolean; {*** Position Evaluation On / Off ***}
|
||||
ElapsedTime : LongInt;
|
||||
LastMove : MoveType;
|
||||
InCheck : boolean;
|
||||
KingRow, KingCol : RowColType;
|
||||
CursorRow, CursorCol : RowColType;
|
||||
end;
|
||||
|
||||
{*** attributes to represent an entire game ***}
|
||||
GameType = record
|
||||
MovesStored : 0..GAME_MOVE_LEN; {*** number of moves stored ***}
|
||||
MovesPointer : 0..GAME_MOVE_LEN; {*** move currently displayed - for Takeback, UnTakeback ***}
|
||||
MoveNum : 1..GAME_MOVE_LEN; {*** current move or 'ply' number ***}
|
||||
Player : PlayerType;
|
||||
Move : array [1..GAME_MOVE_LEN] of MoveType;
|
||||
InCheck : array [0..GAME_MOVE_LEN] of boolean; {*** if player to move is in check ***}
|
||||
FinalBoard : BoardType;
|
||||
GameFinished : boolean;
|
||||
TimeOutWhite, TimeOutBlack : boolean; {*** reasons for a game... ***}
|
||||
Stalemate, NoStorage : boolean; {*** being finished ***}
|
||||
NonDevMoveCount : array [0..GAME_MOVE_LEN] of byte; {*** since pawn push or take - Stalemate-50 ***}
|
||||
EnPassentAllowed : boolean;
|
||||
SoundFlag : boolean;
|
||||
FlashCount : integer;
|
||||
WatchDelay : integer;
|
||||
TimeLimit : longint;
|
||||
end;
|
||||
|
||||
{*** global variables ***}
|
||||
var Game : GameType;
|
||||
Board : BoardType; {*** current board setup ***}
|
||||
Player : PlayerType; {*** current player attributes ***}
|
||||
CapturePoints : array [PieceImageType] of integer; {*** for taking enemy piece ***}
|
||||
EnemyColor : array [PieceColorType] of PieceColorType; {*** opposite of given color ***}
|
||||
PossibleMoves : PossibleMovesType;
|
||||
LastTime : longint; {*** last read system time-of-day clock value ***}
|
||||
DefaultFileName : string80; {*** for loading and saving games ***}
|
||||
ImageStore : ImageTypePt;
|
||||
GraphDriver, GraphMode : integer; {*** for Turbo Pascal graphics ***}
|
||||
|
||||
procedure AttackedBy (row, col : RowColType; var Attacked, _Protected : integer);
|
||||
procedure GenMoveList (Turn : PieceColorType; var Movelist : MoveListType);
|
||||
procedure MakeMove (Movement : MoveType; PermanentMove : boolean; var Score : integer);
|
||||
procedure UnMakeMove (var Movement: Movetype);
|
||||
procedure TrimChecks (Turn : PieceColorType; var MoveList : MoveListType);
|
||||
procedure RandomizeMoveList (var MoveList : MoveListType);
|
||||
procedure GotoMove (GivenMoveTo : integer);
|
||||
|
||||
implementation
|
||||
|
||||
{*** include files ***}
|
||||
|
||||
//{$I MISC.PAS} {*** miscellaneous functions ***}
|
||||
//{$I INIT.PAS} {*** initialization of global variables ***}
|
||||
//{$I DISPLAY.PAS} {*** display-oriented routines ***}
|
||||
//{$I INPUT.PAS} {*** keyboard input routines ***}
|
||||
{$I MOVES.PAS} {*** move generation and making routines ***}
|
||||
//{$I SETUP.PAS} {*** default board and custom setup routines ***}
|
||||
//{$I PLAY.PAS} {*** computer thinking and player input routines ***}
|
||||
//{$I MENU.PAS} {*** main menu routines ***}
|
||||
|
||||
end.
|
||||
|
@ -68,7 +68,7 @@
|
||||
<PackageName Value="LCL"/>
|
||||
</Item2>
|
||||
</RequiredPackages>
|
||||
<Units Count="14">
|
||||
<Units Count="15">
|
||||
<Unit0>
|
||||
<Filename Value="fpchess.lpr"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
@ -130,15 +130,20 @@
|
||||
<UnitName Value="chessmodules"/>
|
||||
</Unit11>
|
||||
<Unit12>
|
||||
<Filename Value="mod_singleplayer.pas"/>
|
||||
<Filename Value="mod_samecomputer.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
<UnitName Value="mod_singleplayer"/>
|
||||
<UnitName Value="mod_samecomputer"/>
|
||||
</Unit12>
|
||||
<Unit13>
|
||||
<Filename Value="mod_fics.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
<UnitName Value="mod_fics"/>
|
||||
</Unit13>
|
||||
<Unit14>
|
||||
<Filename Value="engines\kcchess\mod_kcchess.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
<UnitName Value="mod_kcchess"/>
|
||||
</Unit14>
|
||||
</Units>
|
||||
</ProjectOptions>
|
||||
<CompilerOptions>
|
||||
@ -149,6 +154,7 @@
|
||||
</Target>
|
||||
<SearchPaths>
|
||||
<IncludeFiles Value="$(ProjOutDir)"/>
|
||||
<OtherUnitFiles Value="engines\kcchess"/>
|
||||
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
|
||||
</SearchPaths>
|
||||
<Linking>
|
||||
|
@ -8,7 +8,7 @@ uses
|
||||
{$ENDIF}{$ENDIF}
|
||||
Interfaces, // this includes the LCL widgetset
|
||||
Forms, lnetbase, mainform, chessdrawer, chessgame, chessconfig,
|
||||
chesstcputils, chessmodules, mod_singleplayer, mod_fics
|
||||
chesstcputils, chessmodules, mod_samecomputer, mod_fics, mod_kcchess
|
||||
{$ifdef FPCHESS_WEBSERVICES}
|
||||
,IDelphiChess_Intf
|
||||
{$endif};
|
||||
|
@ -1,4 +1,4 @@
|
||||
unit mod_singleplayer;
|
||||
unit mod_samecomputer;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
@ -13,7 +13,7 @@ type
|
||||
|
||||
{ TSinglePlayerChessModule }
|
||||
|
||||
TSinglePlayerChessModule = class(TChessModule)
|
||||
TSameComputerChessModule = class(TChessModule)
|
||||
private
|
||||
textSecondPlayerName: TStaticText;
|
||||
editSecondPlayerName: TEdit;
|
||||
@ -32,9 +32,9 @@ type
|
||||
|
||||
implementation
|
||||
|
||||
{ TSinglePlayerChessModule }
|
||||
{ TSameComputerChessModule }
|
||||
|
||||
constructor TSinglePlayerChessModule.Create;
|
||||
constructor TSameComputerChessModule.Create;
|
||||
begin
|
||||
inherited Create;
|
||||
|
||||
@ -42,7 +42,7 @@ begin
|
||||
Kind := cmkSinglePlayer;
|
||||
end;
|
||||
|
||||
procedure TSinglePlayerChessModule.CreateUserInterface;
|
||||
procedure TSameComputerChessModule.CreateUserInterface;
|
||||
begin
|
||||
textSecondPlayerName := TStaticText.Create(nil);
|
||||
textSecondPlayerName.SetBounds(20, 20, 180, 50);
|
||||
@ -53,45 +53,45 @@ begin
|
||||
editSecondPlayerName.Text := 'Second player';
|
||||
end;
|
||||
|
||||
procedure TSinglePlayerChessModule.ShowUserInterface(AParent: TWinControl);
|
||||
procedure TSameComputerChessModule.ShowUserInterface(AParent: TWinControl);
|
||||
begin
|
||||
textSecondPlayerName.Parent := AParent;
|
||||
editSecondPlayerName.Parent := AParent;
|
||||
end;
|
||||
|
||||
procedure TSinglePlayerChessModule.HideUserInterface();
|
||||
procedure TSameComputerChessModule.HideUserInterface();
|
||||
begin
|
||||
textSecondPlayerName.Parent := nil;
|
||||
editSecondPlayerName.Parent := nil;
|
||||
end;
|
||||
|
||||
procedure TSinglePlayerChessModule.FreeUserInterface();
|
||||
procedure TSameComputerChessModule.FreeUserInterface();
|
||||
begin
|
||||
textSecondPlayerName.Free;
|
||||
editSecondPlayerName.Free;
|
||||
end;
|
||||
|
||||
procedure TSinglePlayerChessModule.PrepareForGame;
|
||||
procedure TSameComputerChessModule.PrepareForGame;
|
||||
begin
|
||||
SecondPlayerName := editSecondPlayerName.Text;
|
||||
end;
|
||||
|
||||
function TSinglePlayerChessModule.IsMovingAllowedNow: Boolean;
|
||||
function TSameComputerChessModule.IsMovingAllowedNow: Boolean;
|
||||
begin
|
||||
Result := True;
|
||||
end;
|
||||
|
||||
function TSinglePlayerChessModule.GetSecondPlayerName: string;
|
||||
function TSameComputerChessModule.GetSecondPlayerName: string;
|
||||
begin
|
||||
Result := SecondPlayerName;
|
||||
end;
|
||||
|
||||
procedure TSinglePlayerChessModule.HandleOnMove(AFrom, ATo: TPoint);
|
||||
procedure TSameComputerChessModule.HandleOnMove(AFrom, ATo: TPoint);
|
||||
begin
|
||||
|
||||
end;
|
||||
|
||||
initialization
|
||||
RegisterChessModule(TSinglePlayerChessModule.Create);
|
||||
RegisterChessModule(TSameComputerChessModule.Create);
|
||||
end.
|
||||
|
Reference in New Issue
Block a user