diff --git a/applications/fpchess/engines/kcchess/MOVES.PAS b/applications/fpchess/engines/kcchess/MOVES.PAS new file mode 100644 index 000000000..2a8f4a098 --- /dev/null +++ b/applications/fpchess/engines/kcchess/MOVES.PAS @@ -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 ***} + diff --git a/applications/fpchess/engines/kcchess/mod_kcchess.pas b/applications/fpchess/engines/kcchess/mod_kcchess.pas new file mode 100644 index 000000000..d238cd8a8 --- /dev/null +++ b/applications/fpchess/engines/kcchess/mod_kcchess.pas @@ -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. + diff --git a/applications/fpchess/fpchess.lpi b/applications/fpchess/fpchess.lpi index 1873a9e58..ee1af9e78 100644 --- a/applications/fpchess/fpchess.lpi +++ b/applications/fpchess/fpchess.lpi @@ -68,7 +68,7 @@ - + @@ -130,15 +130,20 @@ - + - + + + + + + @@ -149,6 +154,7 @@ + diff --git a/applications/fpchess/fpchess.lpr b/applications/fpchess/fpchess.lpr index eb7a9f042..35732d8b3 100644 --- a/applications/fpchess/fpchess.lpr +++ b/applications/fpchess/fpchess.lpr @@ -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}; diff --git a/applications/fpchess/mod_singleplayer.pas b/applications/fpchess/mod_samecomputer.pas similarity index 70% rename from applications/fpchess/mod_singleplayer.pas rename to applications/fpchess/mod_samecomputer.pas index e873d5f8a..74babd2d2 100644 --- a/applications/fpchess/mod_singleplayer.pas +++ b/applications/fpchess/mod_samecomputer.pas @@ -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.