home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / Pascal / BPASCAL.700 / D11 / CHESSDLL.ZIP / CHESSINF.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1992-10-01  |  24.0 KB  |  877 lines

  1. unit ChessInf;
  2.  
  3. interface
  4.  
  5. type
  6.   TPiece = (pEmpty, pKing, pQueen, pRook, pBishop, pKnight, pPawn);
  7.   TColor = (cWhite, cBlack);
  8.   TKind  = (kNormal, kEnPassant, kCastling, kPawnPromote);
  9.   HChess = Word;
  10.  
  11. type
  12.   TSquare = record
  13.     Piece: TPiece;
  14.     Color: TColor;
  15.   end;
  16.   TBoard = array[1..8,1..8] of TSquare;
  17.  
  18.   TLocation = record
  19.     X: 0..8;            { 0 is off-board or empty }
  20.     Y: 0..8;            { 0 is off-board or empty }
  21.   end;
  22.  
  23.   PChange = ^TChange;
  24.   TChange = record
  25.     Piece: TPiece;
  26.     Source: TLocation;
  27.     Dest: TLocation;
  28.   end;
  29.  
  30.   PMove = ^TMove;
  31.   TMove = record
  32.     Change: TChange;
  33.     Capture: Boolean;
  34.     Contents: TPiece;
  35.     case Kind: TKind of
  36.       kEnPassant: (EPCapture: TLocation);
  37.       kCastling: (RookSource, RookDest: TLocation);
  38.   end;
  39.  
  40. type
  41.   TSearchStatus = (
  42.     ssComplete,                 { Completed last opperation }
  43.     ssMoveSearch,               { Searching for a move for the current
  44.                                   player }
  45.     ssThinkAhead,               { Thinking ahead while waiting for a
  46.                                   SubmitMove }
  47.     ssGameOver                  { Game is complete }
  48.   );
  49.  
  50.   TChessStatus = (
  51.     csNormal,                   { Nothing is special about the current state }
  52.     csCheck,                    { The current player is in check }
  53.     csCheckMate,                { The current player is in checkmate }
  54.     csStaleMate,                { The game is a stalemate }
  55.     csResigns,                  { The opponent is so far ahead there is no
  56.                                   point in playing the game further }
  57.     csMateFound,                { Checkmate will happen in a maximum of
  58.                                   Count moves (Count is a parameter of
  59.                                   GetChessStatus) }
  60.     csFiftyMoveRule,            { The game violates the 50 move rule
  61.                                   (stalemate) }
  62.     csRepetitionRule);          { The game violates the 3 repetition rule
  63.                                   (stalemate) }
  64.  
  65. type
  66.   TChessError = (
  67.                                 { General results }
  68.     ceOK,                       { Request sucessful }
  69.     ceInvalidHandle,            { Handle passed is not valid }
  70.     ceIllegalState,             { Call not legal in current state }
  71.  
  72.                                 { NewGame results }
  73.     ceOutOfMemory,              { Not enough memory to allocate game context }
  74.     ceTooManyGames,             { Not enough game handles for new game }
  75.  
  76.                                 { SubmitMove/VarifyMove/ParseMove results }
  77.     ceInvalidMove,              { Cannot move specified piece there }
  78.     ceIllegalMove,              { Move into or does not prevent check or
  79.                                   castling through check }
  80.  
  81.                                 { VerifyMove results }
  82.     ceInvalidSyntax,            { Move syntax cannot be determined }
  83.     ceAmbiguousMove,            { More then one piece fits move (i.e. if you
  84.                                   pass in NF3 and two Knights can be there) }
  85.  
  86.                                 { RetractMove results }
  87.     ceNoMovesLeft);             { No moves left to retract }
  88.  
  89. { Game handle management }
  90.  
  91. { Allocates a game handle }
  92. function NewGame(var GameHandle: HChess): TChessError; {$IFDEF DLL} export; {$ENDIF}
  93.  
  94. { Frees the game handle }
  95. function DisposeGame(CH: HChess): TChessError; {$IFDEF DLL} export; {$ENDIF}
  96.  
  97.  
  98. { Move management }
  99.  
  100. { Parses the given Move into a change record. The syntax is as follows:
  101.  
  102.      <Location> | <Piece name><Location> | <Location><Location>
  103.  
  104.   where <Location> is in the form A3 or F5 and <Piece letter> is one of:
  105.  
  106.     P = Pawn, R = Rook, N = Knight, B = Biship, Q = Queen, K = King
  107.  
  108.   If only a Location is given and the move is ambigious it is assumed the
  109.   piece being moved is a pawn }
  110.  
  111. function ParseMove(Move: PChar; var Change: TChange): TChessError; {$IFDEF DLL} export; {$ENDIF}
  112.  
  113. { Retracts the last move }
  114. function RetractMove(CH: HChess; const Move: TMove): TChessError; {$IFDEF DLL} export; {$ENDIF}
  115.  
  116. { Submits a move for the current player.  Both the "Piece" field and
  117.   the "From" field can be empty if the move is unambigious.  This is
  118.   only legal to call while idle or during a "think ahead" }
  119. function SubmitMove(CH: HChess; const Change: TChange): TChessError; {$IFDEF DLL} export; {$ENDIF}
  120.  
  121. { Verify the legality of the given change but do not perform the
  122.   change.  The "Source" and "Piece" fields can be empty if move is
  123.   unambigious. This is only legal to call while complete or during a
  124.   "think ahead" }
  125. function VerifyMove(CH: HChess; const Change: TChange): TChessError; {$IFDEF DLL} export; {$ENDIF}
  126.  
  127.  
  128. { Search management }
  129.  
  130. { Starts a move search.  It will always return immediately.  You need
  131.   to call Think to perform the actual search. TimeLimit is in 1/18ths
  132.   of a second. }
  133. function ComputerMove(CH: HChess; TimeLimit: LongInt): TChessError; {$IFDEF DLL} export; {$ENDIF}
  134.  
  135. { Force the computer to make a move with the information it has now.
  136.   The move will be completed with the next call to Think. This is only
  137.   legal while performing a move search }
  138. function ForceMove(CH: HChess): TChessError; {$IFDEF DLL} export; {$ENDIF}
  139.  
  140. { Start using the Think time to begin a search assuming the opponent is
  141.   going to follow the main line.  If the opponent does, the next search
  142.   will start at the think-ahead point, otherwise a new search is started.
  143.   This is only legal to call while idle }
  144. function ThinkAhead(CH: HChess): TChessError; {$IFDEF DLL} export; {$ENDIF}
  145.  
  146.  
  147. { Chess process management }
  148.  
  149. { Gives TimeLimit ticks to the computer to think (1/18'ths of a second).
  150.   This call performs the move search.  Think should be called whenever
  151.   the chess program is idle, even while waiting for the opponent.
  152.   The engine utilizes the opponents idle time to "look ahead" to
  153.   improve the results of the next move. The number given in TimeLimit
  154.   should be small (below 10 when searching for a computer move, below
  155.   5 when waiting for the opponent) to allow the rest of the app to be
  156.   responsive.  This is especially important in Windows.  }
  157. function Think(CH: HChess; TimeLimit: LongInt;
  158.   var Status: TSearchStatus): TChessError; {$IFDEF DLL} export; {$ENDIF}
  159.  
  160.  
  161. { Board editing }
  162.  
  163. { Replace the current board with the given board }
  164. function SetBoard(CH: HChess; const ABoard: TBoard): TChessError; {$IFDEF DLL} export; {$ENDIF}
  165.  
  166. { Set the current player to Player }
  167. function SetPlayer(CH: HChess; APlayer: TColor): TChessError; {$IFDEF DLL} export; {$ENDIF}
  168.  
  169. { Make the following modification to the board.  If the "Source" Location
  170.   is blank the piece is new, if the "Dest" Location is blank the piece is
  171.   taken from the board. If neither are blank the piece is moved.  If the
  172.   piece type does not match the piece in the Source location, the piece
  173.   is changed to be the given type }
  174. function MakeChange(CH: HChess; Color: TColor;
  175.   const Change: TChange): TChessError; {$IFDEF DLL} export; {$ENDIF}
  176.  
  177.  
  178. { Status interface }
  179.  
  180. { Returns the status of the move search }
  181. function GetSearchStatus(CH: HChess): TSearchStatus; {$IFDEF DLL} export; {$ENDIF}
  182.  
  183. { Returns the current status of the game }
  184. function GetChessStatus(CH: HChess; var Count: Integer): TChessStatus; {$IFDEF DLL} export; {$ENDIF}
  185.  
  186. { Returns the last move }
  187. function GetLastMove(CH: HChess; var Move: TMove): TChessError; {$IFDEF DLL} export; {$ENDIF}
  188.  
  189. { Returns the hint move }
  190. function GetHintMove(CH: HChess; var Move: TMove): TChessError; {$IFDEF DLL} export; {$ENDIF}
  191.  
  192. { Format the move as a text string }
  193. function MoveToStr(const Move: TMove; var Str: array of Char): TChessError; {$IFDEF DLL} export; {$ENDIF}
  194.  
  195. { Returns the current state of the board.  If a search is being performed
  196.   it is the state of the board that is being searched. }
  197. function GetBoard(CH: HChess; var ABoard: TBoard): TChessError; {$IFDEF DLL} export; {$ENDIF}
  198.  
  199. { Return the whose turn it is }
  200. function GetPlayer(CH: HChess): TColor; {$IFDEF DLL} export; {$ENDIF}
  201.  
  202. { Returns the current move being searched by the computer }
  203. function GetCurrentMove(CH: HChess; var Move: TMove): TChessError; {$IFDEF DLL} export; {$ENDIF}
  204.  
  205. { Returns the current priciple line being used by the computer. }
  206. function GetMainLine(CH: HChess; var Value: Integer;
  207.   var Line: array of TMove): TChessError; {$IFDEF DLL} export; {$ENDIF}
  208.  
  209. { Returns a list of the valid given Change.  Empty fields in the change
  210.   record are used as wildcards in the search.  For example, if you
  211.   want all the legal pawn moves only fill in the Piece field leaving
  212.   the Location fields blank.  If you want all the legal moves for the
  213.   piece on A4, fill in Source with A4 and leave Piece and Dest blank.
  214.   Leaving all fields of Change blank will return all legal moves }
  215. function GetValidMoves(CH: HChess; Change: TChange;
  216.   var Moves: array of TMove): TChessError; {$IFDEF DLL} export; {$ENDIF}
  217.  
  218. { Returns the number of nodes processed during the last (or current)
  219.   search }
  220. function GetNodes(CH: HChess): LongInt; {$IFDEF DLL} export; {$ENDIF}
  221.  
  222. implementation
  223.  
  224. uses GameRec, LBoard, LMoveGen, LOpenLib, LMoves, Strings, TaskMgr,
  225.   LEval, GameTask;
  226.  
  227.  
  228. const
  229.   PieceLetter: array[TPiece] of Char =
  230.     (' ', 'K', 'Q', 'R', 'B', 'N', 'P');
  231.  
  232.  
  233. { Internal verification routines }
  234.  
  235. function LoadGameHandle(CH: HChess): Boolean;
  236. begin
  237.   if (CH >= 1) and (CH <= MaxGames) and
  238.     (GameList[CH].Magic = gmGameMagic) then
  239.   begin
  240.     LoadGameHandle := True;
  241.     CCHandle := CH;
  242.     CC := GameList[CCHandle];
  243.   end
  244.   else
  245.     LoadGameHandle := False;
  246. end;
  247.  
  248. procedure StoreGameHandle;
  249. begin
  250.   GameList[CCHandle] := CC;
  251. end;
  252.  
  253. { Utility functions }
  254.  
  255. function OppColor(Color: TColor): TColor;
  256. begin
  257.   if Color = cWhite then OppColor := cBlack else OppColor := cWhite;
  258. end;
  259.  
  260. { Internal vs. External representation conversion }
  261.  
  262. procedure ICoordToECoord(ICoord: Byte; var Location: TLocation);
  263. begin
  264.   if ICoord and $88 <> 0 then
  265.   begin
  266.     Location.X := 0;
  267.     Location.Y := 0;
  268.   end
  269.   else
  270.   begin
  271.     Location.X := ICoord and $F + 1;
  272.     Location.Y := ICoord shr 4  + 1;
  273.   end;
  274. end;
  275.  
  276. function ECoordToICoord(const Location: TLocation): Byte;
  277. begin
  278.   ECoordToICoord := (Location.X - 1) or (Location.Y - 1) shl 4;
  279. end;
  280.  
  281. { Convert an TChange into a MoveType.  Fills in just the partial
  282.   information enough for MoveCheck to fill in the rest }
  283. procedure ChangeToMoveType(const Change: TChange; var IMove: MoveType);
  284. begin
  285.   with Change, IMove do
  286.   begin
  287.     if Source.X <> 0 then
  288.       Old := ECoordToICoord(Change.Source)
  289.     else
  290.       Old := $08;
  291.     if Dest.X <> 0 then
  292.       New1 := ECoordToICoord(Dest)
  293.     else
  294.       New1 := $08;
  295.     MovPiece := PieceType(Piece);
  296.     Spe := False;
  297.     Content := Empty;
  298.   end;
  299. end;
  300.  
  301. procedure MoveTypeToTMove(const IMove: MoveType; var EMove: TMove);
  302.  
  303.   { Calculates the Locations for the Rook Move in a castling }
  304.   procedure GenCastLocation(New1 : SquareType; var CastLocation,
  305.     CornerLocation : SquareType);
  306.   begin
  307.     if (New1 and 7) >= 4 then     { Short }
  308.     begin
  309.       CastLocation := New1 - 1;
  310.       CornerLocation := New1 + 1;
  311.     end
  312.     else
  313.     begin                         { Long }
  314.       CastLocation := New1 + 1;
  315.       CornerLocation := New1 - 2;
  316.     end;
  317.   end; { GenCastLocation }
  318.  
  319. var
  320.   EpLocation: SquareType;
  321.   CastLocation, CornerLocation: SquareType;
  322. begin
  323.   with IMove, EMove do
  324.   begin
  325.     Change.Piece := TPiece(MovPiece);
  326.     ICoordToECoord(Old, Change.Source);
  327.     ICoordToECoord(New1, Change.Dest);
  328.  
  329.     { Capture moves }
  330.     Contents := TPiece(Content);
  331.     Capture := Content <> Empty;
  332.  
  333.     { Process special moves }
  334.     if not Spe then
  335.       Kind := kNormal
  336.     else
  337.       if MovPiece = King then
  338.       begin
  339.         { Castling Move }
  340.         Kind := kCastling;
  341.         GenCastLocation(New1, CastLocation, CornerLocation);
  342.         ICoordToECoord(CornerLocation, RookSource);
  343.         ICoordToECoord(CastLocation, RookDest);
  344.       end
  345.       else
  346.         if MovPiece = Pawn then
  347.         begin
  348.           { E.P. capture }
  349.           Capture := True;
  350.           Kind := kEnPassant;
  351.  
  352.           EpLocation := (New1 and 7) + (Old and $70);
  353.           ICoordToECoord(EpLocation, EPCapture);
  354.         end
  355.         else
  356.           { Pawn-promotion }
  357.           Kind := kPawnPromote;
  358.   end;
  359. end;
  360.  
  361.  
  362. { Interface implementation }
  363.  
  364. function NewGame(var GameHandle: HChess): TChessError;
  365. var
  366.   X: Integer;
  367. begin
  368.   NewGame := ceOK;
  369.   GameHandle := 0;
  370.   X := 0;
  371.   repeat
  372.     Inc(X);
  373.   until (X > MaxGames) or (GameList[X].Magic <> gmGameMagic);
  374.   if X > MaxGames then
  375.   begin
  376.     NewGame := ceTooManyGames;
  377.     Exit;
  378.   end;
  379.  
  380.   CCHandle := X;
  381.   GameHandle := X;
  382.   CC := GameList[CCHandle];
  383.  
  384.   { Initiallize everything to zero }
  385.   FillChar(CC, SizeOf(TGameData), 0);
  386.  
  387.   with CC do
  388.   begin
  389.     Magic := gmGameMagic;
  390.     Level := Normal;                   { set Level }
  391.     AverageTime := 15000;
  392.     MaxLevel := MaxPly;
  393.     InitBoard;
  394.     Player := White;
  395.     Opponent := Black;
  396.     ProgramColor := White;
  397.     ResetMoves;
  398.     UseLib := 200;
  399.     MovTab[-1].Content := King;
  400.     InitChessTime;
  401.     MoveNo := 0;
  402.     ClearHint;
  403.     PlayerMove := ZeroMove;
  404.     Nodes := 0;
  405.     Clock.Init;
  406.     Clock.Reset;
  407.     Clock.SetLimit(180);   { max 10 seconds per turn }
  408.  
  409.     State := [];
  410.     AllocateTask(20000);
  411.  
  412.     Spawn(DoGameTask);    { Assumes it will immediatly block on a message }
  413.   end;
  414.   StoreGameHandle;
  415. end;
  416.  
  417. function DisposeGame(CH: HChess): TChessError;
  418. begin
  419.   DisposeGame := ceInvalidHandle;
  420.   if LoadGameHandle(CH) then
  421.   begin
  422.     DisposeGame := ceOK;
  423.     DisposeTask;
  424.     GameList[CCHandle].Magic := 0;
  425.     CCHandle := 0;
  426.   end;
  427. end;
  428.  
  429.  
  430. { Converts the Location indicator from its input from to a
  431.   form that the Analysis part of the program understands  }
  432. procedure CalcLocation(X, Y: Char; var Location: TLocation);
  433. begin
  434.    if (X in ['A'..'H']) and (Y in ['1'..'8']) then
  435.    begin
  436.      Location.X := ord(X) - ord('A') + 1;
  437.      Location.Y := ord(Y) - ord('1') + 1;
  438.    end
  439.    else
  440.    begin
  441.      Location.X := 0;
  442.      Location.Y := 0;
  443.    end;
  444. end;
  445.  
  446. function ParseMove(Move: PChar; var Change: TChange): TChessError;
  447. var
  448.   APiece: TPiece;
  449. begin
  450.    ParseMove := ceInvalidSyntax;
  451.    with Change do
  452.    begin
  453.      Source.X := 0;
  454.      Dest.X := 0;
  455.      Piece := pEmpty;
  456.  
  457.      case StrLen(Move) of
  458.        4: { Two Locations (e2e4) }
  459.          begin
  460.            CalcLocation(UpCase(Move[0]),Move[1], Change.Source);
  461.            if Source.X = 0 then Exit;
  462.            CalcLocation(UpCase(Move[2]),Move[3], Change.Dest);
  463.          end;
  464.        3: { Piece and Location (Pe4) }
  465.          begin
  466.            CalcLocation(UpCase(Move[1]),Move[2], Change.Dest);
  467.            for APiece := Low(TPiece) to High(TPiece) do
  468.              if UpCase(Move[0]) = PieceLetter[APiece] then
  469.              begin
  470.                Piece := APiece;
  471.                Break;
  472.              end;
  473.            if Piece = pEmpty then Exit;
  474.          end;
  475.        2: { Location only (e4) }
  476.          CalcLocation(UpCase(Move[0]), Move[1], Change.Dest);
  477.      end;
  478.  
  479.      if Dest.X = 0 then Exit;
  480.    end;
  481.    ParseMove := ceOk;
  482. end;
  483.  
  484. function RetractMove(CH: HChess; const Move: TMove): TChessError;
  485. begin
  486.   RetractMove := ceInvalidHandle;
  487.   if not LoadGameHandle(CH) then Exit;
  488.  
  489.   with CC do
  490.     TakeBackMove(MovTab[Depth]);
  491.  
  492.   RetractMove := ceOk;
  493.  
  494.   StoreGameHandle;
  495. end;
  496.  
  497. function SubmitMove(CH: HChess; const Change: TChange): TChessError;
  498. var
  499.   Move: MoveType;
  500.   Result: TChessError;
  501. begin
  502.   SubmitMove := ceInvalidHandle;
  503.   if not LoadGameHandle(CH) then Exit;
  504.  
  505.   ChangeToMoveType(Change, Move);
  506.   Result := MoveCheck(Move); { Move now in CC^.KeyMove }
  507.  
  508.   if Result = ceOK then
  509.     Message(tmEnterMove);
  510.  
  511.   SubmitMove := Result;
  512.   StoreGameHandle;
  513. end;
  514.  
  515.  
  516. function VerifyMove(CH: HChess; const Change: TChange): TChessError;
  517. var
  518.   Move: MoveType;
  519. begin
  520.   VerifyMove := ceInvalidHandle;
  521.   if not LoadGameHandle(CH) then Exit;
  522.  
  523.   ChangeToMoveType(Change, Move);
  524.  
  525.   VerifyMove := MoveCheck(Move);
  526. end;
  527.  
  528. function ComputerMove(CH: HChess; TimeLimit: LongInt): TChessError;
  529. begin
  530.   ComputerMove := ceInvalidHandle;
  531.   if not LoadGameHandle(CH) then Exit;
  532.  
  533.   with CC do
  534.   begin
  535.     Clock.SetLimit(TimeLimit);
  536.     Clock.Reset;
  537.     Message(tmFindMove);
  538.   end;
  539.  
  540.   ComputerMove := ceOk;
  541.   StoreGameHandle;
  542. end;
  543.  
  544. function ForceMove(CH: HChess): TChessError;
  545. begin
  546.   ForceMove := ceInvalidHandle;
  547.   if not LoadGameHandle(CH) then Exit;
  548.  
  549.   CC.Clock.SetLimit(0);
  550.  
  551.   ForceMove := ceOk;
  552.  
  553.   StoreGameHandle;
  554. end;
  555.  
  556. function ThinkAhead(CH: HChess): TChessError;
  557. begin
  558.   ThinkAhead := ceInvalidHandle;
  559.   if not LoadGameHandle(CH) then Exit;
  560.  
  561.   Message(tmThinkAhead);
  562.  
  563.   ThinkAhead := ceOk;
  564.  
  565.   StoreGameHandle;
  566. end;
  567.  
  568. function CalcSearchStatus: TSearchStatus;
  569. begin
  570.   with CC do
  571.   begin
  572.     if GameOver in State then CalcSearchStatus := ssGameOver
  573.     else if Analysis in State then CalcSearchStatus := ssMoveSearch
  574.     else if OppAnalysis in State then CalcSearchStatus := ssThinkAhead
  575.     else CalcSearchStatus := ssComplete;
  576.   end;
  577. end;
  578.  
  579. function Think(CH: HChess; TimeLimit: LongInt; var Status: TSearchStatus): TChessError;
  580. begin
  581.   Think := ceInvalidHandle;
  582.   if not LoadGameHandle(CH) then Exit;
  583.  
  584.   with CC do
  585.   begin
  586.     { Give more time to the task }
  587.     TaskTimer.SetLimit(TimeLimit);
  588.     TaskTimer.Reset;
  589.     TaskTimer.Start;
  590.  
  591.     Message(tmResume);
  592.  
  593.     Status := CalcSearchStatus;
  594.   end;
  595.  
  596.   Think := ceOk;
  597.  
  598.   StoreGameHandle;
  599. end;
  600.  
  601. function SetBoard(CH: HChess; const ABoard: TBoard): TChessError;
  602. begin
  603.   SetBoard := ceInvalidHandle;
  604.   if not LoadGameHandle(CH) then Exit;
  605.  
  606.   { Not implemented yet }
  607.  
  608.   SetBoard := ceOk;
  609.  
  610.   StoreGameHandle;
  611. end;
  612.  
  613. function SetPlayer(CH: HChess; APlayer: TColor): TChessError;
  614. begin
  615.   SetPlayer := ceInvalidHandle;
  616.   if not LoadGameHandle(CH) then Exit;
  617.  
  618.   with CC do
  619.   begin
  620.     Player := ColorType(APlayer);
  621.     Opponent := ColorType(Byte(APlayer) xor 1);
  622.   end;
  623.  
  624.   SetPlayer := ceOk;
  625.  
  626.   StoreGameHandle;
  627. end;
  628.  
  629. function MakeChange(CH: HChess; Color: TColor;
  630.   const Change: TChange): TChessError;
  631. begin
  632.   MakeChange := ceInvalidHandle;
  633.   if not LoadGameHandle(CH) then Exit;
  634.  
  635.   { Not implemented yet }
  636.  
  637.   MakeChange := ceOk;
  638. end;
  639.  
  640. function GetChessStatus(CH: HChess; var Count: Integer): TChessStatus;
  641. var
  642.   Check,PossibleMove,CheckMate : boolean;
  643.   NumMoves : integer;
  644. begin
  645.   GetChessStatus := csNormal;
  646.   if not LoadGameHandle(CH) then Exit;
  647.  
  648.   with CC do
  649.   begin
  650.     CheckMate := False;
  651.     Inc(Depth);               { Test if there is a Possible Move }
  652.     PossibleMove := False;
  653.     InitMovGen;
  654.     repeat
  655.        MovGen;
  656.        if NextMove.MovPiece <> Empty then
  657.           if not IllegalMove(NextMove) then
  658.              PossibleMove := true;
  659.     until (NextMove.MovPiece = Empty) or PossibleMove;
  660.     Dec(Depth);
  661.     Check := Attacks(Opponent, PieceTab[Player,0].ISquare); { Calculate Check }
  662.  
  663.     { No Possible Move means Checkmate or Stalemate }
  664.     if not PossibleMove then
  665.     begin
  666.        if Check then
  667.          GetChessStatus := csCheckMate
  668.        else
  669.          GetChessStatus := csStaleMate;
  670.     end
  671.     else if Check then
  672.       GetChessStatus := csCheck
  673.     else if FiftyMoveCnt >= 100 then
  674.       GetChessStatus := csFiftyMoveRule
  675.     else if Repetition(False) >= 3 then
  676.       GetChessStatus := csRepetitionRule
  677.     else if HintEvalu >= MateValue - DepthFactor * 16 then
  678.     begin
  679.       GetChessStatus := csMateFound;
  680.       Count := (MateValue - HintEvalu + $40) div (DepthFactor * 2);
  681.     end
  682.     else if (-25500 < HintEvalu) and (HintEvalu <- $880) then
  683.       GetChessStatus := csResigns;
  684.   end;
  685. end;
  686.  
  687. function GetSearchStatus(CH: HChess): TSearchStatus;
  688. begin
  689.   GetSearchStatus := ssComplete;
  690.   if not LoadGameHandle(CH) then Exit;
  691.  
  692.   GetSearchStatus := CalcSearchStatus;
  693. end;
  694.  
  695. function GetLastMove(CH: HChess; var Move: TMove): TChessError;
  696. begin
  697.   GetLastMove := ceInvalidHandle;
  698.   if not LoadGameHandle(CH) then Exit;
  699.  
  700.   with CC do
  701.     MoveTypeToTMove(MovTab[Depth], Move);
  702.  
  703.   GetLastMove := ceOk;
  704. end;
  705.  
  706. function GetHintMove(CH: HChess; var Move: TMove): TChessError;
  707. begin
  708.   GetHintMove := ceInvalidHandle;
  709.   if not LoadGameHandle(CH) then Exit;
  710.  
  711.   with CC do
  712.     MoveTypeToTMove(HintLine[0], Move);
  713.  
  714.   GetHintMove := ceOk;
  715. end;
  716.  
  717.  
  718. function MoveToStr(const Move: TMove; var Str: array of Char): TChessError;
  719. begin
  720.   MoveToStr := ceOk;
  721.  
  722.   Str[0] := #0;
  723.   if (High(Str) >= 6) and (Move.Change.Piece <> pEmpty) then
  724.     with Move do
  725.       case Kind of
  726.         kCastling:
  727.           begin
  728.             if Change.Source.X > Change.Dest.X then
  729.               StrCopy(PChar(@Str), 'O-O-O')
  730.             else
  731.               StrCopy(PChar(@Str), 'O-O');
  732.           end;
  733.  
  734.         kNormal, kPawnPromote, kEnPassant:
  735.           begin
  736.             { Normal moves }
  737.             Str[0] := PieceLetter[Change.Piece];
  738.             Str[1] := Chr(ord('a') + Change.Source.X - 1);
  739.             Str[2] := Chr(ord('1') + Change.Source.Y - 1);
  740.             if Capture then
  741.               Str[3] :='x'
  742.             else
  743.               Str[3] :='-';
  744.             Str[4] := Chr(ord('a') + Change.Dest.X - 1);
  745.             Str[5] := Chr(ord('1') + Change.Dest.Y - 1);
  746.  
  747.             Str[6] := #0;
  748.           end;
  749.       end
  750.   else
  751.     MoveToStr := ceOutOfMemory;
  752. end;
  753.  
  754. function GetBoard(CH: HChess; var ABoard: TBoard): TChessError;
  755. var
  756.   I, J: Integer;
  757.   Index: Word;
  758. begin
  759.   GetBoard := ceInvalidHandle;
  760.   if not LoadGameHandle(CH) then Exit;
  761.  
  762.   with CC do
  763.     for I := Low(ABoard) to High(ABoard) do
  764.       for J := Low(ABoard[I]) to High(ABoard[I]) do
  765.         with ABoard[J, I] do
  766.         begin
  767.           Index := (I - Low(ABoard)) shl 4 or (J - Low(ABoard[I]));
  768.           Piece := TPiece(Board[Index].Piece);
  769.           Color := TColor(Board[Index].Color);
  770.         end;
  771.  
  772.   GetBoard := ceOk;
  773. end;
  774.  
  775. function GetPlayer(CH: HChess): TColor;
  776. begin
  777.   GetPlayer := cWhite;
  778.   if not LoadGameHandle(CH) then Exit;
  779.  
  780.   GetPlayer := TColor(CC.Player);
  781. end;
  782.  
  783. function GetCurrentMove(CH: HChess; var Move: TMove): TChessError;
  784. begin
  785.   GetCurrentMove := ceInvalidHandle;
  786.   if not LoadGameHandle(CH) then Exit;
  787.  
  788.   { Not implemented yet }
  789.  
  790.   GetCurrentMove := ceOk;
  791. end;
  792.  
  793. function GetMainLine(CH: HChess; var Value: Integer;
  794.   var Line: array of TMove): TChessError;
  795. var
  796.   I: Integer;
  797. begin
  798.   GetMainLine := ceInvalidHandle;
  799.   if not LoadGameHandle(CH) then Exit;
  800.  
  801.   I := 0;
  802.   with CC do
  803.   begin
  804.     while (I < High(Line)) and (MainLine[I].MovPiece <> Empty) do
  805.     begin
  806.       MoveTypeToTMove(MainLine[I], Line[I]);
  807.       Inc(I);
  808.     end;
  809.     Value := MainEvalu;
  810.   end;
  811.  
  812.   FillChar(Line[I], SizeOf(Line[I]), 0);
  813.  
  814.   GetMainLine := ceOk;
  815. end;
  816.  
  817. function GetValidMoves(CH: HChess; Change: TChange;
  818.   var Moves: array of TMove): TChessError;
  819. var
  820.   I, J, K: Integer;
  821.   Move: MoveType;
  822. begin
  823.   GetValidMoves := ceInvalidHandle;
  824.   if not LoadGameHandle(CH) then Exit;
  825.  
  826.   ChangeToMoveType(Change, Move);
  827.  
  828.   I := 0;
  829.   with CC do
  830.   begin
  831.     Inc(Depth);
  832.  
  833.     KeyMove := ZeroMove;
  834.     InitMovGen;
  835.     repeat
  836.        MovGen;
  837.        if (NextMove.MovPiece <> Empty) and
  838.           ((NextMove.MovPiece = Move.MovPiece) or (Move.MovPiece = Empty)) and
  839.           ((NextMove.New1 = Move.New1) or (Move.New1 and $88 <> 0)) and
  840.           ((NextMove.Old = Move.Old) or (Move.Old and $88 <> 0)) and
  841.           not IllegalMove(NextMove) then
  842.        begin
  843.          MoveTypeToTMove(NextMove, Moves[I]);
  844.          Inc(I);
  845.        end;
  846.     until (NextMove.MovPiece = Empty) or (I > High(Moves));
  847.  
  848.     if I > High(Moves) then
  849.     begin
  850.       Dec(I);
  851.       GetValidMoves := ceOutOfMemory;
  852.     end
  853.     else
  854.       GetValidMoves := ceOK;
  855.  
  856.     FillChar(Moves[I], SizeOf(Moves[I]), 0);
  857.  
  858.     Dec(Depth);
  859.   end;
  860. end;
  861.  
  862. function GetNodes(CH: HChess): LongInt;
  863. begin
  864.   if not LoadGameHandle(CH) then Exit;
  865.   GetNodes := CC.Nodes;
  866. end;
  867.  
  868. begin  { global initialization section }
  869.   FillChar(GameList, SizeOf(GameList), 0);
  870.   CCHandle := 0;
  871.  
  872.   { Init attack tables, shared by all game instances }
  873.   CalcAttackTab;
  874.   InitPawnStrTables;
  875. end.
  876.  
  877.