home *** CD-ROM | disk | FTP | other *** search
/ CD Actual Thematic 25: Programming / pc_actual_25.iso / Delphi / CheesboardComponent / chessbrd.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  2000-02-05  |  111.6 KB  |  3,894 lines

  1. //--------------------------------------------------------------------------
  2. // ChessBoard Component for Delphi2-5
  3. // Version 3.03 - Feb 5, 2000
  4. // Author: Daniel Terhell, Resplendence Sp
  5. // Copyright (c) 1997-2000 Resplendence Sp
  6. //
  7. // Contains translated source from Tom's Simple Chess Program
  8. //
  9. // Contains graphics from Andrew Gate
  10. //--------------------------------------------------------------------------
  11.  
  12. unit ChessBrd;
  13.  
  14. interface
  15.  
  16.  
  17. uses
  18.   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  19.   Grids, ExtCtrls, ImgList;
  20.  
  21. {$RESOURCE Chessbrd.res}
  22.  
  23. const
  24.  
  25. //  Resource Identifiers
  26.     SetAndrew40Str='SETANDREW40';
  27.  
  28.     versionStr='3.02';
  29.  
  30.     NoPiece =-1;
  31.     Black   =0;
  32.     White   =1;
  33.  
  34. //  From Tom:
  35.  
  36.     MOVE_STACK=4096;
  37.     HIST_STACK=64;
  38.  
  39.     LIGHT =0;
  40.     DARK  =1;
  41.  
  42.     PAWN  =0;
  43.     KNIGHT=1;
  44.     BISHOP=2;
  45.     ROOK  =3;
  46.     QUEEN =4;
  47.     KING  =5;
  48.     EMPTY =6;
  49.  
  50. //  This is the basic description of a move. promote is what
  51. //  piece to promote the pawn to, if the move is a pawn
  52. //  promotion. bits is a bitfield that describes the move,
  53. //  with the following bits:
  54. //
  55. //    1    capture
  56. //    2    castle
  57. //    4    en passant capture
  58. //    8    pushing a pawn 2 squares
  59. //   16    pawn move
  60. //   32    promote
  61. //
  62.  
  63. type
  64.     EChessException = class(Exception);
  65.  
  66.     Square=(None, A8,B8,C8,D8,E8,F8,G8,H8,
  67.                   A7,B7,C7,D7,E7,F7,G7,H7,
  68.                   A6,B6,C6,D6,E6,F6,G6,H6,
  69.                   A5,B5,C5,D5,E5,F5,G5,H5,
  70.                   A4,B4,C4,D4,E4,F4,G4,H4,
  71.                   A3,B3,C3,D3,E3,F3,G3,H3,
  72.                   A2,B2,C2,D2,E2,F2,G2,H2,
  73.                   A1,B1,C1,D1,E1,F1,G1,H1);
  74.  
  75.     DisplayCoords=(West, North, East, South);
  76.     CanStillCastle=(WhiteKingSide, WhiteQueenSide, BlackKingSide, BlackQueenSide);
  77.     CastleSet=set of CanStillCastle;
  78.     CoordSet= set of DisplayCoords;
  79.  
  80.     MoveInfo = record
  81.         position: String;
  82.         Castling: CastleSet;
  83.         OldSquare,NewSquare, EnPassant: Square;
  84.     end;
  85.  
  86.     pieces=(BP,BN,BB,BR,BK,BQ,WP,WN,WB,WR,WQ,WK);
  87.  
  88.     pGenRec   = ^gen_rec;
  89.     pSquare   = ^Square;
  90.     pCastleSet= ^CastleSet;
  91.     pBoolean  = ^Boolean;
  92.     pThreadPriority= ^TThreadPriority;
  93.  
  94.     TMoveEvent     =procedure(Sender:TObject; oldSq, newSq: Square) of object;
  95.     TCaptureEvent  =procedure(Sender:TObject; oldSq, newSq: Square; CapturedPiece: Char) of object;
  96.     TOneSquareEvent=procedure(Sender:TObject; square: Square) of object;
  97.     TPromotionEvent=procedure(Sender:TObject; oldSq, newSq: Square;var NewPiece: Char) of object;
  98.     TMoveFunc      =function(oldsq, newsq: Square): Boolean of Object;
  99.     TThinkEvent    =procedure(Sender: TObject; var oldsq,newsq: Square) of object;
  100.  
  101. //  From Tom:
  102.  
  103.     move_bytes = record
  104.         src,dst,promote,bits: Byte;
  105.     end;
  106.  
  107.     moverec = record
  108.         b: move_bytes;
  109.     end;
  110.  
  111.     // an element of the move stack. it's just a move with a
  112.     // score, so it can be sorted by the search functions. */
  113.  
  114.     gen_rec = record
  115.         m: moverec;
  116.         score: Integer;
  117.     end;
  118.  
  119.     // an element of the history stack, with the information
  120.     // necessary to take a move back. */
  121.  
  122.     hist_rec = record
  123.         m: moverec;
  124.         capture,castle,ep,fifty: Integer;
  125.     end;
  126.  
  127.  
  128.     // The thinking thread contains mainly code from Tom's Simple Chess Program:
  129.     TChessThread = class(TThread)
  130.     private
  131.         // pcsq stands for piece/square table. It's indexed by the piece's color,
  132.         // type, and square. The value of pcsq[LIGHT,KNIGHT,e5] might be 310
  133.         // one of the outer squares. //
  134.         // instead of just 300 because a knight on e5 is better than one on
  135.  
  136.         pcsq:                Array [0..1,0..5,0..63] of Integer;
  137.         flip:                Array [0..63] of Integer;
  138.         pawn_pcsq:           Array [0..63] of Integer;
  139.         kingside_pawn_pcsq:  Array [0..63] of Integer;
  140.         queenside_pawn_pcsq: Array [0..63] of Integer;
  141.         minor_pcsq:          Array [0..63] of Integer;
  142.         king_pcsq:           Array [0..63] of Integer;
  143.         endgame_king_pcsq:   Array[0..63] of Integer;
  144.         color: Array [0..63] of Integer;  // LIGHT, DARK, or EMPTY
  145.         piece: Array [0..63] of Integer;  // PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING, or EMPTY
  146.         side:  Integer;  // the side to move
  147.         xside: Integer;  // the side not to move
  148.         castle: Integer; // a bitfield with the castle permissions. if 1 is set,
  149.                          // white can still castle kingside. 2 is white queenside.
  150.                          // 4 is black kingside. 8 is black queenside.
  151.         ep: Integer ;    // the en passant square. if white moves e2e4, the en passant
  152.                          // square is set to e3, because that's where a pawn would move
  153.                          // in an en passant capture
  154.         fifty: Integer;  // the number of moves since a capture or pawn move, used
  155.                          //   to handle the fifty-move-draw rule
  156.         ply: Integer;    // the half-move that we're on
  157.  
  158.         //   this is the move stack. gen_dat is basically a list of move lists,
  159.         //   all stored back to back. gen_begin[x] is where the first move of the
  160.         //   ply x move list is (in gen_dat). gen_end is right after the last move.
  161.  
  162.         gen_dat:   Array [0..MOVE_STACK-1] of gen_rec;
  163.         gen_begin: Array [0..63] of Integer;
  164.         gen_end:   Array [0..63] of Integer;
  165.  
  166.         history: Array [0..63,0..63] of Integer;
  167.  
  168.         // we need an array of hist_rec's so we can take back the
  169.         //   moves we make
  170.         hist_dat: Array [0..63] of hist_rec;
  171.  
  172.         nodes: Integer;  // the number of nodes we've searched
  173.  
  174.         // a triangular PV array
  175.         pv: Array[0..63,0..63]of moverec;
  176.         pv_length: Array [0..63] of Integer;
  177.         follow_pv: Boolean;
  178.  
  179.         // Now we have the mailbox array, so called because it looks like a
  180.         // mailbox, at least according to Bob Hyatt. This is useful when we
  181.         // need to figure out what pieces can go where. Let's say we have a
  182.         // rook on square a4 (32) and we want to know if it can move one
  183.         // square to the left. We subtract 1, and we get 31 (h5). The rook
  184.         // obviously can't move to h5, but we don't know that without doing
  185.         // a lot of annoying work. Sooooo, what we do is figure out a4's
  186.         // mailbox number, which is 61. Then we subtract 1 from 61 (60) and
  187.         // see what mailbox[60] is. In this case, it's -1, so it's out of
  188.         // bounds and we can forget it. You can see how mailbox[] is used
  189.         // in attack() in board.c.
  190.  
  191.         mailbox: Array [0..119] of Integer;
  192.         mailbox64:Array [0..63] of Integer;
  193.  
  194.         // slide, offsets, and offset are basically the vectors that
  195.         // pieces can move in. If slide for the piece is FALSE, it can
  196.         // only move one square in any one direction. offsets is the
  197.         // number of directions it can move in, and offset is an array
  198.         // of the actual directions.
  199.  
  200.         slide: Array[0..5] of Boolean;
  201.         offsets: Array [0..5] of Integer;
  202.         offset: Array[0..5,0..7] of Integer;
  203.  
  204.         // This is the castle_mask array. We can use it to determine
  205.         // the castling permissions after a move. What we do is
  206.         // logical-AND the castle bits with the castle_mask bits for
  207.         // both of the move's squares. Let's say castle is 1, meaning
  208.         // that white can still castle kingside. Now we play a move
  209.         // where the rook on h1 gets captured. We AND castle with
  210.         // castle_mask[63], so we have 1&14, and castle becomes 0 and
  211.         // white can't castle kingside anymore.
  212.  
  213.         castle_mask: Array [0..63] of Integer;
  214.  
  215.         // values of the pieces
  216.         value: Array [0..5] of Integer;
  217.  
  218.         // the piece letters, for print_board()
  219.         piece_char: Array [0..5] of Char;
  220.  
  221.         // the initial board state
  222.  
  223.         init_color: Array [0..63] of Integer;
  224.         init_piece: Array [0..63] of Integer;
  225.  
  226.         //---------------------------------------------------------------------
  227.         Thinking: Boolean;
  228.         WhiteToMove: pBoolean;
  229.         ComputerPlaysWhite: pBoolean;
  230.         ComputerPlaysBlack: pBoolean;
  231.         StopThinkingNow: Boolean;
  232.         Position: pChar;
  233.         EnPassant: pSquare;
  234.         Castling: pCastleSet;
  235.         SearchDepth: PInt;
  236.         ThinkingPriority: pThreadPriority;
  237.  
  238.         function eval: Integer;
  239.         function attack(sq,s: Integer): Boolean;
  240.         function ColorOfPiece (sq: Square): Integer;
  241.         function in_check(s: Integer): Boolean;
  242.         function makemove (m: move_bytes): Boolean;
  243.         function quiesce(alpha,beta: Integer): Integer;
  244.         function search(alpha,beta,depth: Integer): Integer;
  245.  
  246.         procedure ThinkAboutAMove;
  247.         procedure ThinkingFinished;
  248.  
  249.         procedure gen;
  250.         procedure gen_caps;
  251.         procedure gen_promote(src,dst,bits: Integer);
  252.         procedure gen_push(src,dst,bits: Integer);
  253.         procedure InitValues;
  254.         procedure init_eval;
  255.         procedure IntCopy (dest,source: pInt; count: Integer);
  256.         procedure PerformMove;
  257.         procedure sort(src: Integer);
  258.         procedure sort_pv;
  259.         procedure takeback;
  260.  
  261.   protected
  262.     procedure Execute; override;
  263.  
  264.   public
  265.         MoveFunc: TMoveFunc;
  266.         EndFunc:  TNotifyEvent;
  267.         constructor Create;
  268.   end;
  269.  
  270.  
  271.   TChessBrd = class(TGraphicControl)
  272.   private
  273.     // Class members starting with a _
  274.     // represent internal storage variables of properties
  275.  
  276.     timer: TTimer;
  277.     stopThinking: Boolean;
  278.  
  279.     temp: MoveInfo;
  280.     OldCursor: TCursor;
  281.  
  282.     Now: TChessThread;
  283.     GameEnded: Boolean;
  284.     FirstTime: Boolean;
  285.  
  286.     MoveList: Array[0..256,0..2]of MoveInfo;
  287.     buf: Array[0..MAX_PATH] of Char;
  288.     PromoteTo: Char;
  289.     PieceIndex: Array[0..2,0..6] of Integer;
  290.     Boardx,Boardy, PieceSize, _SizeOfSquare, _CurrentMove: Integer;
  291.     ResizeState, _resizable: Boolean;
  292.     _ResizeMinSize,_ResizeMaxSize: Integer;
  293.  
  294.     _ComputerPlaysWhite,_ComputerPlaysBlack: Boolean;
  295.     _SearchDepth: Integer;
  296.     _ThinkingPriority: TThreadPriority;
  297.  
  298.     _legalMove,_check,_mate,_staleMate,_castle,_failed :TMoveEvent;
  299.     _paint,_draw,_noMatingMaterial,_threefoldPosition: TNotifyEvent;
  300.     _calculate: TThinkEvent;
  301.     _capture: TCaptureEvent;
  302.     _illegalMove: TOneSquareEvent;
  303.     _promotion: TPromotionEvent;
  304.     _enPassant: Square;
  305.  
  306.     _position: Array[0..65] of Char;
  307.  
  308.     list: TImageList;
  309.     _squareLight, _squareDark, _borderBitmap, _custompieceset, Default: TBitmap;
  310.     _lineStyle: TPen;
  311.     _coordFont: TFont;
  312.  
  313.     _castlingAllowed: CastleSet;
  314.     _displayCoords: CoordSet;
  315.  
  316.     _customEngine: Boolean;
  317.  
  318.     SquareClick1, SquareClick2: Square;
  319.     _SizeOfBorder,_animationDelay: Integer;
  320.     _whiteOnTop,_whiteToMove,_boardlines, _animateMoves: Boolean;
  321.     _squareColorLight, _squareColorDark, _bordercolor: TColor;
  322.  
  323.     _version: String;
  324.  
  325.     procedure TimerCallback (Sender: TObject);
  326.  
  327.     function CheckLegalBishopMove (oldsq, newsq: Square):Boolean;
  328.     function CheckLegalKingMove   (oldsq, newsq: Square):Boolean;
  329.     function CheckLegalKnightMove (oldsq, newsq: Square):Boolean;
  330.     function CheckLegalPawnMove   (oldsq, newsq: Square):Boolean;
  331.     function CheckLegalRookMove   (oldsq, newsq: Square):Boolean;
  332.     function CheckLegalQueenMove  (oldsq, newsq: Square):Boolean;
  333.     function BitmapExists         (bmp: TBitmap)        :Boolean;
  334.     function BitmapIsValidPieceSet(bmp: TBitmap)        :Boolean;
  335.     function CheckForThreefoldPosition: Boolean;
  336.     function PieceToInt (piece: Char): Integer;
  337.     procedure DoPromotion (sq: Square);
  338.     procedure ThinkingComplete(Sender:TObject);
  339.     procedure DrawBorder;
  340.     procedure DrawBoard;
  341.     procedure DrawBoardLines;
  342.     procedure DrawPieces;
  343.     procedure DrawPiece (sq: Square; piece: Char);
  344.     procedure InitializeBitmap;
  345.     procedure OrganizeBitmaps;
  346.     procedure AnimateHorizontally (x1,x2,y,delay: Integer);
  347.     procedure AnimateVertically   (y1,y2,x,delay: Integer);
  348.     procedure AnimateDiagonally   (x1,y1,x2,y2,delay: Integer);
  349.     procedure SetNewGame;
  350.  
  351.     //--Boring Write Methods--------------------------------------
  352.  
  353.     function  Get_Position: String;
  354.     function  Get_Thinking: Boolean;
  355.     procedure Set_BoardLines (show: Boolean);
  356.     procedure Set_BorderBitmap (bmp: TBitmap);
  357.     procedure Set_BorderColor (c: TColor);
  358.     procedure Set_ComputerPlaysBlack (plays: Boolean);
  359.     procedure Set_ComputerPlaysWhite (plays: Boolean);
  360.     procedure Set_CoordFont (f: TFont);
  361.     procedure Set_CurrentMove (moveno: Integer);
  362.     procedure Set_CustomPieceSet (bmp: TBitmap);
  363.     procedure Set_CustomEngine (use: Boolean);
  364.     procedure Set_DarkSquare(bmp: TBitmap);
  365.     procedure Set_DisplayCoords (cset: CoordSet);
  366.     procedure Set_EnPassant(sq: Square);
  367.     procedure Set_LightSquare(bmp: TBitmap);
  368.     procedure Set_LineStyle (pen: TPen);
  369.     procedure Set_Position (pos: String);
  370.     procedure Set_ResizeMaxSize (size: Integer);
  371.     procedure Set_ResizeMinSize (size: Integer);
  372.     procedure Set_SearchDepth (depth: Integer);
  373.     procedure Set_SizeOfBorder (border: Integer);
  374.     procedure Set_SizeOfSquare (size: Integer);
  375.     procedure Set_SquareColorDark (c: TColor);
  376.     procedure Set_SquareColorLight (c: TColor);
  377.     procedure Set_Thinking (thinking: Boolean);
  378.     procedure Set_ThinkingPriority (priority: TThreadPriority);
  379.     procedure Set_Version (str: String);
  380.     procedure Set_WhiteOnTop (wabove: Boolean);
  381.     procedure Set_WhiteToMove (wmove: Boolean);
  382.  
  383.   protected
  384.  
  385.    procedure Click; override;
  386.    procedure DragCanceled;override;
  387.    procedure DragDrop(Source: TObject;X,Y: Integer);override;
  388.    procedure DragOver(Source: TObject;X,Y: Integer; State: TDragState;var Accept: Boolean );override;
  389.    procedure EndDrag(drop:Boolean);
  390.    procedure MouseDown(Button:TMouseButton; Shift:TShiftState;X,Y: Integer); override;
  391.    procedure MouseMove(Shift:TShiftState; X,Y: Integer); override;
  392.    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X,Y: Integer);override;
  393.    procedure Paint; override;
  394.    procedure Promotion (Sender: TObject;oldSq,newSq: Square; var NewPiece: Char);
  395.    procedure WndProc(var Message: TMessage); override;
  396.   public
  397.    FirstMove, LastMove: Integer;
  398.    FirstTurn, LastTurn: Boolean;
  399.  
  400.    constructor Create(AOwner: TComponent); override;
  401.    destructor  Destroy; override;
  402.  
  403.    function BlackInCheckAfter(oldsq, newsq: Square): Boolean;
  404.    function ColorOfPiece (piece: Char): Integer;
  405.    function ColorOfPieceOnSquare (sq: Square): Integer;
  406.    function ColorOfSquare (sq: Square): Integer;
  407.    function GetMove (moveno: Integer; whiteMoves: Boolean): MoveInfo;
  408.    function GotoMove (moveno: Integer; whiteMoves:Boolean): Boolean;
  409.    function LegalMoveAvailable: Boolean;
  410.    function MouseToSquare (x, y: Integer): Square;
  411.    function Move (oldsq, newsq: Square): Boolean;
  412.    function MoveBackward: Boolean;
  413.    function MoveForward: Boolean;
  414.    function MoveIsLegal (oldsq, newsq: Square):Boolean;
  415.    function PerformMove (oldsq, newsq: Square): Boolean;
  416.    function SetUpPosition (pos: MoveInfo; moveno: Integer; whiteMoves:Boolean): Boolean;
  417.    function StringToSquare (str: String): Square;
  418.    function WhiteInCheckAfter(oldsq, newsq: Square):Boolean;
  419.    function WindowToSquare (x, y: Integer): Square;
  420.    function XPos (sq: Square): Integer;
  421.    function YPos (sq: Square): Integer;
  422.  
  423.    procedure Animate (oldsq,newsq: Square; delay: Integer);
  424.    procedure CancelThinking;
  425.    procedure ClearSquare(sq: Square);
  426.    procedure DrawChessPiece (canvas: TCanvas; x,y: Integer; piece: Char);
  427.    procedure GetMoveList(var list: TStringList);
  428.    procedure NewGame;
  429.    procedure SquareToCoords (sq: Square; var x,y: Integer);
  430.    procedure Think;
  431.    procedure UpdateChessBoard (oldpos: String);
  432.  
  433.   published
  434.    property AnimateMoves:Boolean read _animateMoves write _animateMoves;
  435.    property AnimationDelay:Integer read _animationDelay write _animationDelay;
  436.    property BoardLines:Boolean read _boardLines write Set_BoardLines;
  437.    property BorderBitmap:TBitmap read _borderBitmap write Set_BorderBitmap;
  438.    property BorderColor:TColor read _borderColor  write Set_BorderColor;
  439.    property CastlingAllowed:CastleSet  read _castlingAllowed write _castlingAllowed;
  440.    property ComputerPlaysBlack:Boolean  read _ComputerPlaysBlack  write  Set_ComputerPlaysBlack;
  441.    property ComputerPlaysWhite:Boolean  read _ComputerPlaysWhite  write  Set_ComputerPlaysWhite;
  442.    property Thinking: Boolean read Get_Thinking write Set_Thinking;
  443.    property CoordFont:TFont  read _CoordFont write Set_CoordFont;
  444.    property CurrentMove:Integer  read _CurrentMove write Set_CurrentMove;
  445.    property CustomPieceSet: TBitmap  read _customPieceset write Set_CustomPieceSet;
  446.    property DisplayCoords:CoordSet  read _displayCoords write Set_DisplayCoords;
  447.    property CustomEngine: Boolean  read _customEngine write Set_CustomEngine;
  448.    property EnPassant:Square read _EnPassant write Set_EnPassant;
  449.    property LineStyle:TPen  read _lineStyle write Set_LineStyle;
  450.    property Position:String read Get_position write Set_Position;
  451.    property Resizable:Boolean  read _resizable write _resizable;
  452.    property ResizeMinSize:Integer  read _ResizeMinSize write Set_ResizeMinSize;
  453.    property ResizeMaxSize:Integer  read _ResizeMaxSize write Set_ResizeMaxSize;
  454.    property SearchDepth: Integer read _SearchDepth  write set_SearchDepth;
  455.    property SizeOfBorder:Integer  read _SizeOfBorder write Set_SizeOfBorder;
  456.    property SizeOfSquare:Integer  read _SizeOfSquare write Set_SizeOfSquare;
  457.    property SquareColorDark:TColor  read _squareColorDark write Set_SquareColorDark;
  458.    property SquareColorLight:TColor  read _squareColorLight write Set_SquareColorLight;
  459.    property SquareDark:TBitmap  read _SquareDark write Set_DarkSquare;
  460.    property SquareLight:TBitmap  read _SquareLight write Set_LightSquare;
  461.    property WhiteOnTop:Boolean  read _whiteOnTop write Set_WhiteOnTop;
  462.    property WhiteToMove:Boolean  read _whiteToMove write Set_WhiteToMove;
  463.    property ThinkingPriority: TThreadPriority read _ThinkingPriority  write set_ThinkingPriority;
  464.    property Version: String read _version write Set_Version;
  465.  
  466.    property DragCursor;
  467.    property DragMode;
  468.    property Enabled;
  469.    property Visible;
  470.  
  471.    property OnCapture: TCaptureEvent  read _capture write _capture;
  472.    property OnCastle: TMoveEvent  read _castle write _castle;
  473.    property OnCheck: TMoveEvent read _check write _check;
  474.    property OnDraw: TNotifyEvent read _draw write _draw;
  475.    property OnIllegalMove: TOneSquareEvent  read _illegalmove write _illegalmove;
  476.    property OnLegalMove: TMoveEvent  read _legalmove write _legalmove;
  477.    property OnMate: TMoveEvent  read _mate write _mate;
  478.    property OnNoMatingMaterial: TNotifyEvent  read _noMatingMaterial write _noMatingMaterial;
  479.    property OnPaint: TNotifyEvent  read _paint write _paint;
  480.    property OnPromotion: TPromotionEvent read _promotion write _promotion;
  481.    property OnStaleMate: TMoveEvent  read _stalemate write _stalemate;
  482.    property OnCalculateMove: TThinkEvent read _calculate write _calculate;
  483.    property OnCalculationFailed: TMoveEvent read _failed write _failed;
  484.    property OnThreefoldPosition: TNotifyEvent  read _threefoldposition write _threefoldposition;
  485.  
  486.    property OnClick;
  487.    property OnDblClick;
  488.    property OnDragDrop;
  489.    property OnDragOver;
  490.    property OnEndDrag;
  491.    property OnMouseDown;
  492.    property OnMouseMove;
  493.    property OnMouseUp;
  494.    property OnStartDrag;
  495.  
  496.   end;
  497.  
  498.   ChessBrdError = class(Exception);
  499.  
  500. procedure Register;
  501.  
  502. implementation
  503.  
  504. procedure Register;
  505. begin
  506.   RegisterComponents('Chess', [TChessBrd]);
  507. end;
  508.  
  509. constructor TChessBrd.Create(AOwner: TComponent);
  510. var
  511.     p,q: pInt;
  512. begin
  513.     inherited Create(AOwner);
  514.  
  515.     list:=TImageList.CreateSize(40,40);
  516.     Default:=TBitmap.Create;
  517.  
  518.     _lineStyle     :=TPen.Create;
  519.     _coordfont     :=TFont.Create;
  520.     _customPieceSet:=TBitmap.Create;
  521.     _SquareLight   :=TBitmap.Create;
  522.     _SquareDark    :=TBitmap.Create;
  523.     _borderBitmap  :=TBitmap.Create;
  524.  
  525.     Timer:=TTimer.Create(Self);
  526.  
  527.     _ResizeMinSize:=100;
  528.     _ResizeMaxSize:=1000;
  529.  
  530.     _animateMoves:=TRUE;
  531.     _animationDelay:=0;
  532.  
  533.     FirstMove:=1;
  534.     LastMove:=1;
  535.     LastTurn:=TRUE;
  536.  
  537.     PromoteTo:='q';
  538.  
  539.     InitializeBitmap;
  540.     OrganizeBitmaps;
  541.  
  542.     _coordfont.Color:=clWhite;
  543.     _coordfont.Name:='Arial';
  544.     _coordfont.Size:=7;
  545.     _coordfont.Pitch:=fpDefault;
  546.  
  547.     _SizeOfSquare:=40;
  548.     _SizeOfBorder:=24;
  549.     _bordercolor:=clBlack;
  550.     _squareColorDark:=clGray;
  551.     _squareColorLight:=clSilver;
  552.  
  553.     Boardx:=_SizeOfBorder;
  554.     Boardy:=_SizeOfBorder;
  555.  
  556.     _ComputerPlaysWhite:=FALSE;
  557.     _ComputerPlaysBlack:=FALSE;
  558.     _SearchDepth:=1;
  559.     _ThinkingPriority:=tpNormal;
  560.  
  561.     p:=@Width;
  562.     p^:=8*_SizeOfSquare+2*_SizeOfBorder;
  563.     q:=@Height;
  564.     q^:=Width;
  565.  
  566.     SetNewGame;
  567.  
  568.     if ((csDesigning in ComponentState)=FALSE) then
  569.     begin
  570.         Now:=TChessThread.Create;
  571.         Now.Castling:=@_CastlingAllowed;
  572.         Now.EnPassant:=@_EnPassant;
  573.         Now.MoveFunc:=PerformMove;
  574.         Now.EndFunc:=ThinkingComplete;
  575.         Now.Position:=@_position;
  576.         Now.ComputerPlaysWhite:=@_ComputerPlaysWhite;
  577.         Now.ComputerPlaysBlack:=@_ComputerPlaysBlack;
  578.         Now.SearchDepth:=@_SearchDepth;
  579.         Now.ThinkingPriority:=@_ThinkingPriority;
  580.         Now.WhiteToMove:=@_WhiteToMove;
  581.     end;
  582.  
  583. end;
  584.  
  585.  
  586. destructor TChessBrd.destroy;
  587. begin
  588.     if(_customEngine=FALSE)and(Now<>nil) then
  589.     begin
  590.         Now.Suspend;
  591.         Now.Free;
  592.     end;
  593.  
  594.     inherited destroy;
  595.  
  596.     list.Destroy;
  597.     _lineStyle.Destroy;
  598.     _coordfont.Destroy;
  599.     _SquareLight.Destroy;
  600.     _SquareDark.Destroy;
  601.     _borderBitmap.Destroy;
  602.     _customPieceSet.Destroy;
  603.     Default.Destroy;
  604. end;
  605.  
  606. procedure TChessBrd.TimerCallback(Sender: TObject);
  607. var
  608.     msg: TMessage;
  609. begin
  610.     WndProc(msg);
  611. end;
  612.  
  613. procedure TChessBrd.MouseDown(Button: TMouseButton; Shift: TShiftState;X,Y: Integer);
  614. var
  615.     sq: Square;
  616. const
  617.      space: Char=' ';
  618. begin
  619.     inherited MouseDown(Button,Shift,X,Y);
  620.  
  621.     sq:=WindowToSquare(X,Y);
  622.     if (sq>=A8)AND(sq<=H1)AND
  623.         (_position[Integer(sq)]<>' ') then
  624.      begin
  625.          SquareClick1:=sq;
  626.          BeginDrag(FALSE);
  627.      end;
  628. end;
  629.  
  630. procedure TChessBrd.ThinkingComplete(Sender: TObject);
  631. begin
  632.     Now.Thinking:=FALSE;
  633.     Now.Suspend;
  634.     if (Now.StopThinkingNow=FALSE) then Think;
  635. end;
  636.  
  637. procedure TChessBrd.WndProc (var Message: TMessage);
  638. begin
  639.     inherited WndProc (Message);
  640.     if (stopThinking=FALSE)and(_customEngine)and(((_ComputerPlaysBlack)and(_WhiteToMove=FALSE))or
  641.        ((_ComputerPlaysWhite)and(_WhiteToMove=TRUE)))and(csDesigning in ComponentState=FALSE)and
  642.        (csLoading in ComponentState=FALSE) then
  643.     Think;
  644. end;
  645.  
  646.  
  647. procedure TChessBrd.Paint;
  648. var
  649.     size: Integer;
  650. begin
  651.     if ((csLoading in ComponentState)=TRUE) then Exit;
  652.  
  653.     if ((csDesigning in ComponentState)=FALSE)and(@_paint<>nil)
  654.         then _paint(Self);
  655.  
  656.     if (FirstTime=FALSE) then
  657.     begin
  658.         OrganizeBitmaps;
  659.     end;
  660.  
  661.     size:=(Width+Height) shr 1;
  662.     _SizeOfSquare:=(size-2*_SizeOfBorder) shr 3;
  663.     Width:=8*_SizeOfSquare+2*_SizeOfBorder;
  664.     Height:=Width;
  665.     DrawBorder;
  666.     DrawBoard;
  667.     DrawPieces;
  668.  
  669.     if (FirstTime=FALSE) then
  670.     begin
  671.         FirstTime:=TRUE;
  672.         Think;
  673.         timer.Interval:=500;
  674.         timer.OnTimer:=TimerCallBack;
  675.     end;
  676. end;
  677.  
  678.  
  679. // Displays an move animation
  680. // It's up to the to user ensure there is a piece on oldSq
  681. procedure TChessBrd.Animate (oldSq,newSq: Square; delay: Integer);
  682. var
  683.     x1,y1,x2,y2: Integer;
  684. begin
  685.     if (list.Dragging=FALSE)then
  686.     begin
  687.         list.SetDragImage(PieceToInt(_position[Integer(oldSq)]), 0,0);
  688.         SquareToCoords(oldSq,x1,y1);
  689.         SquareToCoords(newSq,x2,y2);
  690.         x1:=x1+Left;
  691.         y1:=y1+Top;
  692.         x2:=x2+Left;
  693.         y2:=y2+Top;
  694.         list.DragLock  (Parent.Handle,x1,y1);
  695.         list.ShowDragImage;
  696.         list.BeginDrag (Parent.Handle,0,0);
  697.  
  698.         // Knights don't go diagonally
  699.         if (_position[Integer(oldSq)]<>'n')and(_position[Integer(oldSq)]<>'N') then
  700.             AnimateDiagonally(x1,y1,x2,y2,delay)
  701.         else
  702.         begin
  703.             AnimateHorizontally(x1,x2,y1,delay);
  704.             AnimateVertically(y1,y2,x2,delay);
  705.         end;
  706.     end;
  707.     list.HideDragImage;
  708.     list.EndDrag;
  709.     list.DragUnlock;
  710. end;
  711.  
  712. procedure TChessBrd.AnimateHorizontally(x1,x2,y,delay: Integer);
  713. var
  714.     x,v: Integer;
  715. begin
  716.     if (x2>x1) then
  717.         for x:=x1 to x2 do
  718.         begin
  719.             v:=GetTickCount;
  720.             list.DragMove(x,y);
  721.             list.ShowDragImage;
  722.             if (delay>0) then
  723.             repeat
  724.             until ((GetTickCount-v)>delay);
  725.         end
  726.     else
  727.         for x:=x1 downto x2 do
  728.         begin
  729.             v:=GetTickCount;
  730.             list.DragMove(x,y);
  731.             list.ShowDragImage;
  732.             if (delay>0) then
  733.             repeat
  734.             until ((GetTickCount-v)>delay);
  735.         end;
  736. end;
  737.  
  738. procedure TChessBrd.AnimateVertically(y1,y2,x,delay: Integer);
  739. var
  740.     y,v: Integer;
  741. begin
  742.     if (y2>y1) then
  743.         for y:=y1 to y2 do
  744.         begin
  745.              v:=GetTickCount;
  746.              list.DragMove(x,y);
  747.              list.ShowDragImage;
  748.              if (delay>0) then
  749.              repeat
  750.              until ((GetTickCount-v)>delay);
  751.         end
  752.     else
  753.         for y:=y1 downto y2 do
  754.         begin
  755.              v:=GetTickCount;
  756.              list.DragMove(x,y);
  757.              list.ShowDragImage;
  758.              if (delay>0) then
  759.              repeat
  760.              until ((GetTickCount-v)>delay);
  761.         end;
  762. end;
  763.  
  764. procedure TChessBrd.AnimateDiagonally(x1,y1,x2,y2,delay: Integer);
  765. var
  766.     y,v: Integer;
  767.     x,step: Real;
  768. begin
  769.     if (x1-x2=0)and(y2-y1=0) then Exit;
  770.  
  771.     if(abs(y2-y1)>abs(x2-x1)) then
  772.     begin
  773.         if (y2>y1) then
  774.         begin
  775.             step:=(x2-x1)/(y2-y1);
  776.             x:=x1;
  777.             for y:=y1 to y2 do
  778.             begin
  779.                 v:=GetTickCount;
  780.                 list.DragMove(Trunc(x),y);
  781.                 list.ShowDragImage;
  782.                 if (delay>0) then
  783.                 repeat
  784.                 until ((GetTickCount-v)>delay);
  785.                 x:=x+step;
  786.             end;
  787.         end
  788.         else
  789.         begin
  790.             step:=(x2-x1)/(y1-y2);
  791.             x:=x1;
  792.             for y:=y1 downto y2 do
  793.             begin
  794.                 v:=GetTickCount;
  795.                 list.DragMove(Trunc(x),y);
  796.                 list.ShowDragImage;
  797.                 if (delay>0) then
  798.                 repeat
  799.                 until ((GetTickCount-v)>delay);
  800.                 x:=x+step;
  801.             end;
  802.         end
  803.     end
  804.     else
  805.     begin
  806.         if (x2>x1) then
  807.         begin
  808.             step:=(y2-y1)/(x2-x1);
  809.             x:=y1;
  810.             for y:=x1 to x2 do
  811.             begin
  812.                 v:=GetTickCount;
  813.                 list.DragMove(y,Trunc(x));
  814.                 list.ShowDragImage;
  815.                 if (delay>0) then
  816.                 repeat
  817.                 until ((GetTickCount-v)>delay);
  818.                 x:=x+step;
  819.             end;
  820.         end
  821.         else
  822.         begin
  823.             step:=(y2-y1)/(x1-x2);
  824.             x:=y1;
  825.             for y:=x1 downto x2 do
  826.             begin
  827.                 v:=GetTickCount;
  828.                 list.DragMove(y,Trunc(x));
  829.                 list.ShowDragImage;
  830.                 if (delay>0) then
  831.                 repeat
  832.                 until ((GetTickCount-v)>delay);
  833.                 x:=x+step;
  834.             end;
  835.         end
  836.     end;
  837. end;
  838.  
  839. procedure TChessBrd.DragOver(Source:TObject;
  840.      X,Y: Integer; State: TDragState; var Accept: Boolean );
  841. var
  842.     sq: Square;
  843.     mid: Integer;
  844. begin
  845.     inherited DragOver(Source, X, Y, State, Accept);
  846.  
  847.     sq:=WindowToSquare(X,Y);
  848.     mid:=_SizeOfSquare shr 1;
  849.  
  850.     if (list.Dragging=FALSE)then
  851.     begin
  852.         ClearSquare(SquareClick1);
  853.         DrawBoardLines;
  854.         list.SetDragImage(PieceToInt(_position[Integer(SquareClick1)]), 0,0);
  855.         list.DragLock  (Parent.Handle,X+Left-mid,Y+Top-mid);
  856.         list.BeginDrag (Parent.Handle,0,0);
  857.     end;
  858.  
  859.     list.DragMove(X+Left-mid,Y+Top-mid);
  860.  
  861.     if (Source=Self)then
  862.     begin
  863.         if (Thinking=FALSE)then
  864.         begin
  865.             if MoveIsLegal(SquareClick1,sq)or(SquareClick1=sq) then
  866.             begin
  867.                 Accept:=TRUE;
  868.             end;
  869.         end;
  870.     end;
  871. end;
  872.  
  873. procedure TChessBrd.DragDrop(Source:TObject ;X,Y: Integer);
  874. begin
  875.     inherited DragDrop(Source,X,Y);
  876.     if (list.Dragging)then
  877.     begin
  878.         list.HideDragImage;
  879.         list.EndDrag;
  880.         list.DragUnlock;
  881.     end;
  882.  
  883.     SquareClick2:=WindowToSquare(X,Y);
  884.     if (SquareClick1<>SquareClick2)then
  885.         Move (SquareClick1,SquareClick2)
  886.     else DrawPiece (SquareClick1,_position[Integer(SquareClick1)]);
  887. end;
  888.  
  889. procedure TChessBrd.DragCanceled;
  890. begin
  891.     list.HideDragImage;
  892.     list.EndDrag;
  893.     list.DragUnlock;
  894.     DrawPiece (SquareClick1,_position[Integer(SquareClick1)]);
  895.     if (@_illegalmove<>nil) then _illegalmove(Self, SquareClick1);
  896. end;
  897.  
  898. procedure TChessBrd.MouseMove(Shift: TShiftState;X,Y: Integer);
  899. var
  900.     w: Integer;
  901. begin
  902.     inherited MouseMove(Shift,X,Y);
  903.  
  904.     if (Cursor<>crSizeNWSE)and(Cursor<>crSizeWE) and (Cursor<>crSizeNS)then
  905.         OldCursor:=Cursor;
  906.  
  907.     if (_resizable)and(X>=(Width-10))and(X<=Width)and(Y>=(Height-10))
  908.          and (Y<=Height) then
  909.         begin
  910.         Cursor:=crSizeNWSE;
  911.         if (ssLeft in Shift)then
  912.             ResizeState:=TRUE;
  913.         end
  914.     else if (_resizable) and(ResizeState=FALSE)then
  915.         Cursor:=OldCursor;
  916.  
  917.     if (_resizable)and(ResizeState) then
  918.     begin
  919.         if (X>Y) then w:=X
  920.           else w:=Y;
  921.         if (w<_ResizeMinSize) then w:=_ResizeMinSize;
  922.         if (w>_ResizeMaxSize) then w:=_ResizeMaxSize;
  923.         if (w<>Width) then
  924.             begin
  925.             Width:=w;
  926.             end;
  927.     end;
  928. end;
  929.  
  930. procedure TChessBrd.MouseUp(Button:TMouseButton;Shift:TShiftState;
  931.           X,Y: Integer);
  932. begin
  933.     inherited MouseUp(Button,Shift,X,Y);
  934.     if (ResizeState) then ResizeState:=FALSE;
  935. end;
  936.  
  937. procedure TChessBrd.Click;
  938. begin
  939.     inherited Click();
  940. end;
  941.  
  942. procedure TChessBrd.EndDrag(drop: Boolean);
  943. begin
  944.     inherited EndDrag(drop);
  945. end;
  946.  
  947. procedure TChessBrd.Promotion (Sender:TObject; oldSq,newSq: Square;
  948.      var NewPiece: Char);
  949. var
  950.     i: String;
  951.     r: Integer;
  952. begin
  953.       i:='NBRQnbrq';
  954.  
  955.       for r:=1 to 8 do
  956.       begin
  957.           if (NewPiece=i[r])then
  958.               Break;
  959.           if (r=8) then NewPiece:='q';
  960.       end;
  961.  
  962.     PromoteTo:=NewPiece;
  963. end;
  964.  
  965. procedure TChessBrd.DoPromotion (sq: Square);
  966. begin
  967.     if YPos(sq)=8 then
  968.         begin
  969.         _position[Integer(sq)]:=UpCase(PromoteTo);
  970.         end
  971.     else if (YPos(sq)=1) then
  972.         begin
  973.         _position[Integer(sq)]:=Char(Integer(UpCase(PromoteTo))+32);
  974.         end;
  975.  
  976.     ClearSquare(sq);
  977.     DrawPiece(sq,_position[Integer(sq)]);
  978.     DrawBoardLines;
  979. end;
  980.  
  981. //-----------------------------------------------------------------------
  982. // Boring Write Methods
  983. //-----------------------------------------------------------------------
  984.  
  985. function TChessBrd.Get_Position: String;
  986. begin
  987.      Result:=StrPas(@_position[1]);
  988. end;
  989.  
  990. procedure  TChessBrd.Set_ComputerPlaysBlack(plays: Boolean);
  991. begin
  992.     CancelThinking;
  993.     _ComputerPlaysBlack:=plays;
  994.     Think;
  995. end;
  996.  
  997. procedure  TChessBrd.Set_ComputerPlaysWhite(plays: Boolean);
  998. begin
  999.     CancelThinking;
  1000.     _ComputerPlaysWhite:=plays;
  1001.     Think;
  1002. end;
  1003.  
  1004.  
  1005. procedure TChessBrd.Set_Position(pos:String);
  1006. var
  1007.     PieceStr: String;
  1008.     q,n,len: Integer;
  1009. begin
  1010.     CancelThinking;
  1011.  
  1012.     PieceStr:=' PNBRQKpnbrqk';
  1013.  
  1014.     len:=Length(pos);
  1015.     if (len>64) then len:=64;
  1016.  
  1017.     _position:='                                                                ';
  1018.  
  1019.     for q:=1 to len do
  1020.         begin
  1021.         if Integer(pos[q])>0 then
  1022.             begin
  1023.             for n:=1 to 13 do
  1024.                 begin
  1025.                 if PieceStr[n]=pos[q] then
  1026.                     begin
  1027.                     _position[q]:=pos[q];
  1028.                     Break;
  1029.                     end;
  1030.                 end;
  1031.             end
  1032.         else Break;
  1033.         end;
  1034.  
  1035.     if (LowerCase(pos)='init')or(LowerCase(pos)='newgame') then
  1036.     begin
  1037.         _position:='_rnbqkbnrpppppppp                                PPPPPPPPRNBQKBNR';
  1038.     end;
  1039.  
  1040.     Paint;
  1041. end;
  1042.  
  1043. procedure TChessBrd.Set_ResizeMinSize (size: Integer);
  1044. begin
  1045.     if (size<_ResizeMaxSize) then _ResizeMinsize:=size
  1046.         else _ResizeMinSize:=_ResizeMaxSize;
  1047. end;
  1048.  
  1049. procedure TChessBrd.Set_ResizeMaxSize (size: Integer);
  1050. begin
  1051.     if (size > _ResizeMinsize) then
  1052.         _ResizeMaxSize:=size
  1053.     else _ResizeMaxSize:=_ResizeMinSize;
  1054. end;
  1055.  
  1056. procedure TChessBrd.Set_SearchDepth (depth: Integer);
  1057. begin
  1058.    if (depth<1) then _SearchDepth:=1
  1059.    else if (depth>=8) then _SearchDepth:=8
  1060.    else _SearchDepth:=depth;
  1061. end;
  1062.  
  1063. procedure  TChessBrd.Set_SizeOfSquare (size: Integer);
  1064. begin
  1065.     _SizeOfSquare:=size;
  1066.     Width:=8*_SizeOfSquare+2*_SizeOfBorder;
  1067. end;
  1068.  
  1069. procedure  TChessBrd.Set_CurrentMove (moveno: Integer);
  1070. begin
  1071.     // Read-Only
  1072. end;
  1073.  
  1074. procedure  TChessBrd.Set_EnPassant (sq: Square);
  1075. begin
  1076.     if ((sq>=A6)and(sq<=H6))or((sq>=A3)and(sq<=H3)) then
  1077.     begin
  1078.         CancelThinking;
  1079.         _EnPassant:=sq;
  1080.     end;
  1081. end;
  1082.  
  1083. procedure  TChessBrd.Set_BoardLines (show: Boolean);
  1084. begin
  1085.     _boardLines:=show;
  1086.     Paint;
  1087. end;
  1088.  
  1089. function TChessBrd.Get_Thinking: Boolean;
  1090. begin
  1091.     Result:=FALSE;
  1092.     if (Now<>nil)then
  1093.         Result:=Now.Thinking;
  1094. end;
  1095.  
  1096. procedure TChessBrd.Set_Thinking (thinking:Boolean);
  1097. begin
  1098.     // Read-Only
  1099. end;
  1100.  
  1101. procedure TChessBrd.Set_ThinkingPriority (priority: TThreadPriority);
  1102. begin
  1103.     _ThinkingPriority:=priority;
  1104.     if (Now<>nil) then Now.Priority:=_ThinkingPriority;
  1105. end;
  1106.  
  1107. procedure  TChessBrd.Set_DisplayCoords (cset: CoordSet);
  1108. begin
  1109.     _displayCoords:=cset;
  1110.     Paint;
  1111. end;
  1112.  
  1113. procedure  TChessBrd.Set_CoordFont(f: TFont);
  1114. begin
  1115.     _coordfont.Assign(f);
  1116.     Paint;
  1117. end;
  1118.  
  1119. procedure  TChessBrd.Set_CustomPieceSet(bmp: TBitmap);
  1120. begin
  1121.     if  (bmp=nil)or(BitmapIsValidPieceSet(bmp)) then
  1122.     begin
  1123.        _customPieceSet.Assign(bmp);
  1124.        OrganizeBitmaps;
  1125.        Paint;
  1126.     end;
  1127. end;
  1128.  
  1129. procedure  TChessBrd.Set_CustomEngine (use: Boolean);
  1130. begin
  1131.      _customEngine:=use;
  1132. end;
  1133.  
  1134. procedure  TChessBrd.Set_LineStyle (pen: TPen);
  1135. begin
  1136.     _lineStyle.Assign(pen);
  1137.     Paint;
  1138. end;
  1139.  
  1140. procedure  TChessBrd.Set_SizeOfBorder (border: Integer);
  1141. begin
  1142.     _SizeOfBorder:=border;
  1143.     Boardx:=_SizeOfBorder;
  1144.     Boardy:=_SizeOfBorder;
  1145.  
  1146.     Width:=8*_SizeOfSquare+2*_SizeOfBorder;
  1147. end;
  1148.  
  1149. procedure TChessBrd.Set_Version (str: String);
  1150. begin
  1151.     // Read-only
  1152. end;
  1153.  
  1154. procedure  TChessBrd.Set_WhiteOnTop (wabove: Boolean);
  1155. begin
  1156.     _whiteOnTop:=wabove;
  1157.     Paint;
  1158. end;
  1159.  
  1160. procedure  TChessBrd.Set_WhiteToMove (wmove: Boolean);
  1161. begin
  1162.     CancelThinking;
  1163.     _whiteToMove:=wmove;
  1164. end;
  1165.  
  1166. procedure  TChessBrd.Set_DarkSquare(bmp: TBitmap);
  1167. begin
  1168.     _SquareDark.Assign(bmp);
  1169.     Paint;
  1170. end;
  1171.  
  1172. procedure  TChessBrd.Set_LightSquare(bmp: TBitmap);
  1173. begin
  1174.     _SquareLight.Assign(bmp);
  1175.     Paint;
  1176. end;
  1177.  
  1178. procedure  TChessBrd.Set_BorderBitmap(bmp: TBitmap);
  1179. begin
  1180.     _borderBitmap.Assign(bmp);
  1181.     Paint;
  1182. end;
  1183.  
  1184. procedure  TChessBrd.Set_SquareColorDark(c: TColor);
  1185. begin
  1186.     _squareColorDark:=c;
  1187.     Paint;
  1188. end;
  1189.  
  1190. procedure  TChessBrd.Set_SquareColorLight(c: TColor);
  1191. begin
  1192.     _squareColorLight:=c;
  1193.     Paint;
  1194. end;
  1195.  
  1196. procedure  TChessBrd.Set_BorderColor(c: TColor);
  1197. begin
  1198.     _borderColor:=c;
  1199.     Paint;
  1200. end;
  1201.  
  1202. //---------------------------------------------------------------------
  1203. //-------PUBLIC Graphic Routines-----------------------------------------------
  1204. //---------------------------------------------------------------------
  1205.  
  1206. procedure TChessBrd.DrawChessPiece (canvas: TCanvas; x,y: Integer; piece: Char);
  1207. var
  1208.     v,i,j: Integer;
  1209.     c: Char;
  1210. begin
  1211.     i:=-1;
  1212.     c:=piece;
  1213.  
  1214.     if (c>='A')and(c<='Z')then
  1215.         c:=Char(Integer(c)+32);
  1216.     case c of
  1217.          'p': i:=0;
  1218.          'n': i:=1;
  1219.          'b': i:=2;
  1220.          'r': i:=3;
  1221.          'q': i:=4;
  1222.          'k': i:=5;
  1223.          end;
  1224.     if (piece>='A')and(piece<='Z')
  1225.         then j:=0 else j:=1;
  1226.  
  1227.     if (i>=0) then v:=PieceIndex[j,i]
  1228.         else v:=-1;
  1229.  
  1230.     list.Draw (canvas,x,y,v);
  1231. end;
  1232.  
  1233. procedure  TChessBrd.UpdateChessBoard (oldpos: String);
  1234. var
  1235.     sq: Square;
  1236. begin
  1237.     for sq:=A8 to H1 do
  1238.         begin
  1239.             if (oldpos[Integer(sq)]<>_position[Integer(sq)])then
  1240.             begin
  1241.                 ClearSquare(sq);
  1242.                 if (_position[Integer(sq)]<>' ')then
  1243.                     DrawPiece(sq,_position[Integer(sq)]);
  1244.             end;
  1245.         end;
  1246.     DrawBoardLines;
  1247. end;
  1248.  
  1249. procedure  TChessBrd.DrawPiece (sq: Square; piece: Char);
  1250. var
  1251.     x,y,adj: Integer;
  1252. begin
  1253.     x:=(Integer(sq)-1) mod 8;
  1254.     y:=(Integer(sq)-1) shr 3;
  1255.  
  1256.     if (_whiteOnTop)then
  1257.         begin
  1258.         x:=7-x;
  1259.         y:=7-y;
  1260.         end;
  1261.  
  1262.     adj:=Trunc ((_SizeOfSquare-PieceSize)/2);
  1263.     list.Draw(Canvas, Boardx+_SizeOfSquare*x+adj, Boardy+_SizeOfSquare*y+adj, PieceToInt(piece));
  1264. end;
  1265.  
  1266.  
  1267. procedure TChessBrd.ClearSquare(sq: Square);
  1268. var
  1269.     x,y,posx,posy,SavedDC: Integer;
  1270.     Pic: TBitmap;
  1271. begin
  1272.     SavedDC:=SaveDC(Canvas.Handle);
  1273.  
  1274.     Canvas.CopyMode:=cmSrcCopy;
  1275.     Canvas.Brush.Style:=bsSolid;
  1276.  
  1277.     x:=XPos(sq)-1;
  1278.     y:=8-YPos(sq);
  1279.     if (_whiteOnTop) then
  1280.         begin
  1281.         x:=7-x;
  1282.         y:=7-y;
  1283.         end;
  1284.  
  1285.     posx:=Boardx+x*_SizeOfSquare;
  1286.     posy:=Boardy+y*_SizeOfSquare;
  1287.     IntersectClipRect(Canvas.Handle,posx,posy,posx+_SizeOfSquare,
  1288.           posy+_SizeOfSquare);
  1289.  
  1290.     if (ColorOfSquare(sq)=Black) then
  1291.         if BitmapExists(_SquareDark) then
  1292.             Pic:=_SquareDark
  1293.         else
  1294.             begin
  1295.             Pic:=nil;
  1296.             Canvas.Brush.Color:=_SquareColorDark;
  1297.             Canvas.Pen.Color:=_SquareColorDark;
  1298.             end
  1299.     else
  1300.         if BitmapExists(_SquareLight) then
  1301.             Pic:=_SquareLight
  1302.         else
  1303.             begin
  1304.             Pic:=nil;
  1305.             Canvas.Brush.Color:=_SquareColorLight;
  1306.             Canvas.Pen.Color:=_SquareColorLight;
  1307.         end;
  1308.  
  1309.     if (Pic<>nil) then
  1310.         begin
  1311.         for Y:=0 to Height div Pic.Height do
  1312.             for X:=0 to Width div Pic.Width do
  1313.                 Canvas.Draw(X*Pic.Width,Y*Pic.Height,Pic);
  1314.         end
  1315.     else
  1316.         Canvas.FillRect(Canvas.ClipRect);
  1317.  
  1318.     if (_boardLines)then
  1319.         begin
  1320.         Canvas.Pen.Color:=clBlack;
  1321.         for X:=1 to 7 do
  1322.             begin
  1323.             Canvas.MoveTo(BoardX+X*_SizeOfSquare,BoardY);
  1324.             Canvas.LineTo(BoardX+X*_SizeOfSquare,Height-BoardY);
  1325.             Canvas.MoveTo(BoardX,BoardY+X*_SizeOfSquare);
  1326.             Canvas.LineTo(Width-BoardX,BoardY+X*_SizeOfSquare);
  1327.             end;
  1328.         end;
  1329.  
  1330.     RestoreDC(Canvas.Handle,SavedDC);
  1331. end;
  1332.  
  1333.  
  1334.  
  1335. //Converts from Window Coordinates to square
  1336. //returns 0 if invalid else
  1337. // 1-64 as a int number
  1338. function TChessBrd.WindowToSquare (x,y: Integer): Square;
  1339. var
  1340.     xn,yn,xv,yv: Integer;
  1341. begin
  1342.  
  1343.     xv:=x-(Boardx);
  1344.     yv:=y-(Boardy);
  1345.  
  1346.     if ((xv<0)or(xv>=8*_SizeOfSquare)or(yv<0)or(yv>=8*_SizeOfSquare))then
  1347.        begin
  1348.        Result:=None;
  1349.        Exit;
  1350.        end;
  1351.  
  1352.     xn:=Trunc(xv/_SizeOfSquare);
  1353.     yn:=Trunc(yv/_SizeOfSquare);
  1354.  
  1355.     if (xn>7) then xn:=7;
  1356.     if (yn>7) then yn:=7;
  1357.  
  1358.     if (_whiteOnTop)then
  1359.     begin
  1360.         xn:=7-xn;
  1361.         yn:=7-yn;
  1362.     end;
  1363.  
  1364.     Result:=Square(8*yn+xn+1);
  1365. end;
  1366.  
  1367.  
  1368. //
  1369. //-PRIVATE Graphic Routines -----------------------------------------------
  1370. //
  1371. function TChessBrd.BitmapExists (bmp: TBitmap) : Boolean;
  1372. begin
  1373.     Result:=((bmp<>nil)and(bmp.Width>0)and(bmp.Height>0));
  1374. end;
  1375.  
  1376. function TChessBrd.BitmapIsValidPieceSet (bmp: TBitmap) : Boolean;
  1377. begin
  1378.     Result:=((bmp<>nil)and(bmp.Width>0)and(bmp.Height>0)and
  1379.              (bmp.Width*2=bmp.Height*3));
  1380. end;
  1381.  
  1382. procedure TChessBrd.OrganizeBitmaps;
  1383. var
  1384.     Bmp: TBitmap;
  1385.     tmp, tmpmask: TBitmap;
  1386.     r,n: Integer;
  1387.     src,dest: TRect;
  1388. begin
  1389.     if (BitmapIsValidPieceSet(_customPieceSet)) then Bmp:=_customPieceSet
  1390.         else Bmp:=Default;
  1391.  
  1392.     PieceSize:=Bmp.Height shr 2;
  1393.  
  1394.     list.Clear;
  1395.     list.Masked:=TRUE;
  1396.     list.DrawingStyle:=dsTransparent;
  1397.     list.Width:=PieceSize;
  1398.     list.Height:=PieceSize;
  1399.  
  1400.     tmp:=TBitmap.Create;
  1401.     tmpmask:=TBitmap.Create;
  1402.  
  1403.     tmp.Width:=PieceSize;
  1404.     tmp.Height:=PieceSize;
  1405.     tmpmask.Width:=PieceSize;
  1406.     tmpmask.Height:=PieceSize;
  1407.  
  1408.     for n:=0 to 1 do
  1409.     for r:=0 to 5 do
  1410.     begin
  1411.         src.Left:=r*PieceSize;
  1412.         src.Top:=n*(PieceSize*2);
  1413.         src.Right:=src.Left+PieceSize;
  1414.         src.Bottom:=n*(PieceSize*2)+PieceSize;
  1415.         dest.Left:=0;
  1416.         dest.Top:=0;
  1417.         dest.Right:=PieceSize;
  1418.         dest.Bottom:=PieceSize;
  1419.         tmp.Canvas.CopyRect(dest,Bmp.Canvas,src);
  1420.  
  1421.         src.Left:=r*PieceSize;
  1422.         src.Top:=n*(PieceSize*2)+PieceSize;
  1423.         src.Right:=src.Left+PieceSize;
  1424.         src.Bottom:=n*(PieceSize*2)+(PieceSize*2);
  1425.         tmpmask.Canvas.CopyRect(dest,Bmp.Canvas,src);
  1426.  
  1427.         PieceIndex[n,r]:=list.Add (tmp,tmpmask);
  1428.     end;
  1429.  
  1430.     tmpmask.Free;
  1431.     tmp.Free;
  1432. end;
  1433.  
  1434. procedure  TChessBrd.DrawBorder;
  1435. var
  1436.     abc: String;
  1437.     r, v, boffset, soffset,X,Y,SavedDC: Integer;
  1438. begin
  1439.     SavedDC:=SaveDC(Canvas.Handle);
  1440.  
  1441.     Canvas.CopyMode:=cmSrcCopy;
  1442.     Canvas.Brush.Style:=bsSolid;
  1443.     Canvas.Brush.Color:=_bordercolor;
  1444.     ExcludeClipRect(Canvas.Handle,_SizeOfBorder,_SizeOfBorder,Width-_SizeOfBorder,Height-_SizeOfBorder);
  1445.     if (BitmapExists(_borderBitmap))then begin
  1446.         for Y:=0 to Height div _borderBitmap.Height do
  1447.             for X:=0 to Width div _borderBitmap.Width do
  1448.                 Canvas.Draw(X*_borderBitmap.Width,Y*_borderBitmap.Height,_borderBitmap);
  1449.     end else
  1450.         Canvas.FillRect(Canvas.ClipRect);
  1451.     Canvas.Font:=_coordfont;
  1452.  
  1453.     if (_WhiteOnTop=FALSE) then abc:='ABCDEFGH' else abc:='HGFEDCBA';
  1454.  
  1455.     boffset:=((_SizeOfBorder-_coordfont.Size)shr 1)+1;
  1456.     soffset:=(Integer(_SizeOfSquare-_coordfont.Size) shr 1);
  1457.  
  1458.     Y:=Canvas.TextHeight('0') div 4;
  1459.     SetBkMode(Canvas.Handle,TRANSPARENT);
  1460.  
  1461.     for r:=0 to 7 do
  1462.         begin
  1463.         if _WhiteOnTop then v:=r+1 else
  1464.             v:=8-r;
  1465.         if (West in _displayCoords)then
  1466.             Canvas.TextOut(boffset,_SizeOfBorder+r*_SizeOfSquare+soffset,IntToStr(v));
  1467.         if (East in _displayCoords)then
  1468.             Canvas.TextOut(Width-_SizeOfBorder+boffset,_SizeOfBorder+r*_SizeOfSquare+soffset,IntToStr(v));
  1469.         if (North in _displayCoords)then
  1470.             Canvas.TextOut(_SizeOfBorder+r*_SizeOfSquare+soffset,boffset-y,abc[r+1]);
  1471.         if (South in _displayCoords)then
  1472.             Canvas.TextOut(_SizeOfBorder+r*_SizeOfSquare+soffset,Height-_SizeOfBorder+boffset-y,abc[r+1]);
  1473.         end;
  1474.  
  1475.     Canvas.Pen:=_lineStyle;
  1476.     Canvas.MoveTo(0,0);
  1477.     Canvas.LineTo(Width-1,0);
  1478.     Canvas.LineTo(Width-1,Width-1);
  1479.     Canvas.LineTo(0,Width-1);
  1480.     Canvas.LineTo(0,0);
  1481.  
  1482.     Canvas.MoveTo(_SizeOfBorder-1,_SizeOfBorder-1);
  1483.     Canvas.LineTo(Width-_SizeOfBorder,_SizeOfBorder-1);
  1484.     Canvas.LineTo(Width-_SizeOfBorder,Width-_SizeOfBorder);
  1485.     Canvas.LineTo(_SizeOfBorder-1,Width-_SizeOfBorder);
  1486.     Canvas.LineTo(_SizeOfBorder-1,_SizeOfBorder-1);
  1487.  
  1488.     RestoreDC(Canvas.Handle,SavedDC);
  1489. end;
  1490.  
  1491. procedure  TChessBrd.DrawPieces;
  1492. var
  1493.     sq: Square;
  1494.     len: Integer;
  1495. begin
  1496.     if (Length(_position)<64) then len:=Length(_position)
  1497.         else len:=64;
  1498.     for sq:=A8 to Square(len) do
  1499.     begin
  1500.         if (_position[Integer(sq)]<>' ') then
  1501.             DrawPiece(sq,_position[Integer(sq)]);
  1502.     end;
  1503. end;
  1504.  
  1505. procedure  TChessBrd.DrawBoard;
  1506. var
  1507.     n,x,y,posx,posy,SavedDC,TempDC: Integer;
  1508.     Pic: TBitmap;
  1509. begin
  1510.     SavedDC:=SaveDC(Canvas.Handle);
  1511.  
  1512.     Canvas.CopyMode:=cmSrcCopy;
  1513.     Canvas.Brush.Style:=bsSolid;
  1514.     IntersectClipRect(Canvas.Handle,_SizeOfBorder,_SizeOfBorder,Width-_SizeOfBorder,Height-_SizeOfBorder);
  1515.  
  1516.     for n:=0 to 1 do
  1517.         begin
  1518.         TempDC:=SaveDC(Canvas.Handle);
  1519.         for x:=0 to 3 do
  1520.             for y:=0 to 7 do
  1521.             begin
  1522.                 posx:=Boardx+(x*2+(n xor (y and 1)))*_SizeOfSquare;
  1523.                 posy:=Boardy+y*_SizeOfSquare;
  1524.                 ExcludeClipRect(Canvas.Handle,posx,posy,posx+_SizeOfSquare,posy+_SizeOfSquare);
  1525.             end;
  1526.         if n=0 then
  1527.             if BitmapExists(_SquareDark) then
  1528.                 Pic:=_SquareDark
  1529.             else
  1530.             begin
  1531.                 Pic:=nil;
  1532.                 Canvas.Brush.Color:=_SquareColorDark;
  1533.                 Canvas.Pen.Color:=_SquareColorDark;
  1534.             end
  1535.         else
  1536.             if BitmapExists(_SquareLight) then
  1537.                 Pic:=_SquareLight
  1538.             else
  1539.             begin
  1540.                 Pic:=nil;
  1541.                 Canvas.Brush.Color:=_SquareColorLight;
  1542.                 Canvas.Pen.Color:=_SquareColorLight;
  1543.             end;
  1544.         if (Pic<>nil) then
  1545.         begin
  1546.             for Y:=0 to Height div Pic.Height do
  1547.                 for X:=0 to Width div Pic.Width do
  1548.                     Canvas.Draw(X*Pic.Width,Y*Pic.Height,Pic);
  1549.         end
  1550.         else
  1551.             Canvas.FillRect(Canvas.ClipRect);
  1552.  
  1553.         RestoreDC(Canvas.Handle,TempDC);
  1554.         end;
  1555.  
  1556.     DrawBoardLines;
  1557.  
  1558.     RestoreDC(Canvas.Handle,SavedDC);
  1559.  
  1560. end;
  1561.  
  1562. procedure  TChessBrd.DrawBoardLines;
  1563. var
  1564.     x: Integer;
  1565. begin
  1566.     if (_boardLines)then
  1567.     begin
  1568.         Canvas.Pen.Color:=_lineStyle.Color;
  1569.         for x:=1 to 7 do
  1570.         begin
  1571.             Canvas.MoveTo(BoardX+X*_SizeOfSquare,BoardY);
  1572.             Canvas.LineTo(BoardX+X*_SizeOfSquare,Height-BoardY);
  1573.             Canvas.MoveTo(BoardX,BoardY+X*_SizeOfSquare);
  1574.             Canvas.LineTo(Width-BoardX,BoardY+X*_SizeOfSquare);
  1575.         end;
  1576.     end;
  1577. end;
  1578.  
  1579.  
  1580. //-----------------------------------------------------------------------
  1581. // PUBLIC, Chess
  1582. //-----------------------------------------------------------------------
  1583.  
  1584. procedure TChessBrd.CancelThinking;
  1585. begin
  1586.     if(_CustomEngine=FALSE)and(Now<>nil)and(GameEnded=FALSE)then
  1587.     begin
  1588.         Now.StopThinkingNow:=TRUE;
  1589.         while (Now.Suspended=FALSE) do Application.ProcessMessages;
  1590.     end;
  1591.     StopThinking:=TRUE;
  1592. end;
  1593.  
  1594. procedure TChessBrd.Think;
  1595. var
  1596.     oldsq, newsq: Square;
  1597. begin
  1598.     if ((csDesigning in ComponentState)=FALSE)and
  1599.        ((csLoading in ComponentState)=FALSE) then
  1600.     begin
  1601.         if (_customEngine=FALSE) then
  1602.         begin
  1603.             Now.StopThinkingNow:=FALSE;
  1604.             Now.Resume;
  1605.         end
  1606.         else
  1607.         begin
  1608.             if (((_ComputerPlaysBlack)and(_WhiteToMove=FALSE))or
  1609.                 ((_ComputerPlaysWhite)and(_WhiteToMove=TRUE)))and
  1610.                 (@_calculate<>nil)and(stopThinking=FALSE) then
  1611.             begin
  1612.                 oldSq:=None;
  1613.                 newSq:=None;
  1614.                 _calculate(Self,oldsq,newsq);
  1615.                 if (stopThinking=FALSE)and(PerformMove(oldsq,newsq)=FALSE) then
  1616.                 begin
  1617.                      if (@_failed<>nil) then
  1618.                          _failed(Self,oldsq,newsq);
  1619.                 end;
  1620.             end;
  1621.         end;
  1622.     end;
  1623. end;
  1624.  
  1625.  
  1626. procedure TChessBrd.GetMoveList(var list:TStringList);
  1627. var
  1628.     c: Char;
  1629.     s: String;
  1630.     r,side: Integer;
  1631.     Label BreakOut;
  1632. begin
  1633.     for r:=FirstMove to LastMove do
  1634.      for side:=0 to 1 do
  1635.      begin
  1636.         if (r=LastMove)and(side=0)and(LastTurn=TRUE) then Exit;
  1637.         if (r>LastMove)or((r=LastMove)and(side=1)and(LastTurn=FALSE))then Exit;
  1638.  
  1639.         if (side=0) then  s:=IntToStr(r)+'. '
  1640.             else s:='              ';
  1641.  
  1642.         if (r=FirstMove)and(side=0)and(FirstTurn=FALSE)then
  1643.             s:=s+' ...   '
  1644.         else
  1645.             begin
  1646.             c:=Char(Integer('A')+XPos(MoveList[r,side].OldSquare)-1);
  1647.             s:=s+c;
  1648.             c:=char(Integer('0')+YPos(MoveList[r,side].OldSquare));
  1649.             s:=s+c;
  1650.             end;
  1651.  
  1652.         s:=s+'-';
  1653.  
  1654.         c:=char(Integer('A')+XPos(MoveList[r,side].NewSquare)-1);
  1655.         s:=s+c;
  1656.         c:=char(Integer('0')+YPos(MoveList[r,side].NewSquare));
  1657.         s:=s+c;
  1658.         list.Add(s);
  1659.     end;
  1660. end;
  1661.  
  1662. function TChessBrd.GetMove (moveno:Integer;whiteMoves: Boolean): MoveInfo;
  1663. begin
  1664.     temp.OldSquare:=None;
  1665.     temp.NewSquare:=None;
  1666.     temp.position:='init';
  1667.     temp.EnPassant:=None;
  1668.  
  1669.     if (moveno>LastMove)or((moveno=LastMove)and(LastTurn)and(whiteMoves=FALSE)) then
  1670.         begin
  1671.         Result:=temp;
  1672.         Exit;
  1673.         end;
  1674.  
  1675.     if (moveno<FirstMove)or((moveno=FirstMove)and(FirstTurn=FALSE)and(whiteMoves=TRUE))then
  1676.         begin
  1677.         Result:=temp;
  1678.         Exit;
  1679.         end;
  1680.  
  1681.     Result:=MoveList[moveno,1-Integer(whiteMoves)];
  1682. end;
  1683.  
  1684. //Squares are numbered from 1 - 64 (a8,b8...h1)
  1685. function TChessBrd.ColorOfSquare (sq:Square): Integer;
  1686. begin
  1687.     Result:=Integer (((Integer(sq)-1) and 1)=(((Integer(sq)-1) shr 3) and 1));
  1688. end;
  1689.  
  1690. function  TChessBrd.PieceToInt (piece: Char): Integer;
  1691. var
  1692.     i: String;
  1693.     r: Integer;
  1694. begin
  1695.     i:='PNBRQKpnbrqk';
  1696.  
  1697.     for r:=1 to 12 do
  1698.         if (piece=i[r]) then
  1699.             begin
  1700.             Result:=(PieceIndex[Trunc((r-1)/6),(r-1) mod 6]);
  1701.             Exit;
  1702.             end;
  1703.     Result:=-1;
  1704. end;
  1705.  
  1706.  
  1707. //returns color of the PIECE on a square
  1708. function TChessBrd.ColorOfPieceOnSquare (sq: Square): Integer;
  1709. begin
  1710.     Result:=NoPiece;
  1711.       if ((_position[Integer(sq)]>='b')and(_position[Integer(sq)]<='r'))then Result:=Black
  1712.  else if ((_position[Integer(sq)]>='B')and(_position[Integer(sq)]<='R'))then Result:=White;
  1713. end;
  1714.  
  1715. function TChessBrd.ColorOfPiece (piece:Char): Integer;
  1716. var
  1717.     i: String;
  1718.     r: Integer;
  1719. begin
  1720.     i:='NBRQnbrq';
  1721.  
  1722.     Result:=NoPiece;
  1723.  
  1724.     for r:=1 to 8 do
  1725.     begin
  1726.          if (piece=i[r]) then Break;
  1727.          if (r=8) then Exit;
  1728.     end;
  1729.  
  1730.     Result:=Integer ((piece>='B')and(piece<='R'));
  1731. end;
  1732.  
  1733.  
  1734. // Returns XPos of a int according to ChessBoard coordinates (A-H)
  1735. function TChessBrd.XPos (sq: Square): Integer;
  1736. begin
  1737.     Result:=(1+(Integer(sq)-1) mod 8);
  1738. end;
  1739.  
  1740. // Returns YPos of a int according to ChessBoard coordinates (1-8)
  1741. function TChessBrd.YPos (sq: Square): Integer;
  1742. begin
  1743.     Result:=8-((Integer(sq)-1) shr 3);
  1744. end;
  1745.  
  1746. function TChessBrd.MouseToSquare (x,y: Integer): Square;
  1747. begin
  1748.     if (x>=1)and(x<=8)and(y>=1)and (y<=8) then
  1749.         Result:=Square(8*(8-y)+x)
  1750.     else Result:=None;
  1751. end;
  1752.  
  1753.  
  1754. // Expects a two character string, for instance 'e4' and returns a Square value
  1755. function TChessBrd.StringToSquare (str: String): Square;
  1756. begin
  1757.    str:=Lowercase(str);
  1758.    Result:=None;
  1759.    if (Length(str)=2)and
  1760.       (Integer(str[1])>=Integer('a'))and
  1761.       (Integer(str[1])<=Integer('h'))and
  1762.       (Integer(str[2])>=Integer('1'))and
  1763.       (Integer(str[2])<=Integer('8')) then
  1764.        Result:=Square(Integer(str[1])-Integer('a')+1+8*(8-Integer(str[2])-Integer('0')));
  1765. end;
  1766.  
  1767. // Retrieves the coords of the upperleft corner of a square
  1768. // writes into x and y
  1769. procedure TChessBrd.SquareToCoords (sq: Square; var x,y: Integer);
  1770. var
  1771.     a,b: Integer;
  1772. begin
  1773.     a:=XPos(sq)-1;
  1774.     b:=8-YPos(sq);
  1775.     if (_whiteOnTop) then
  1776.     begin
  1777.         a:=7-a;
  1778.         b:=7-b;
  1779.     end;
  1780.  
  1781.     x:=BoardX+a*_SizeOfSquare;
  1782.     y:=BoardY+b*_SizeOfSquare;
  1783. end;
  1784.  
  1785. function TChessBrd.SetupPosition (pos: MoveInfo; moveno: Integer; whiteMoves:Boolean): Boolean;
  1786. var
  1787.     i: String;
  1788.     r,n: Integer;
  1789.     Label BreakOut;
  1790. begin
  1791.     Result:=FALSE;
  1792.  
  1793.     CancelThinking;
  1794.  
  1795.     i:=' pnbrqkPNBRQK';
  1796.  
  1797.     if  (moveno>200)or
  1798.         ((pos.EnPassant<>None)and(YPos(pos.EnPassant)<>3)and
  1799.          (YPos(pos.EnPassant)<>6)) then Exit;
  1800.  
  1801.     for r:=1 to 64 do
  1802.     begin
  1803.         for n:=1 to 13 do
  1804.         begin
  1805.             if (pos.position[r]=i[n]) then goto BreakOut;
  1806.         end;
  1807.         Exit;
  1808.  
  1809.     BreakOut:
  1810.     end;
  1811.  
  1812.     StrPCopy(@_position,pos.position);
  1813.     _whiteToMove:=_whiteToMove;
  1814.     FirstTurn:=_whiteToMove;
  1815.     _CurrentMove:=moveno;
  1816.     FirstMove:=moveno;
  1817.  
  1818.     _castlingallowed:=pos.Castling;
  1819.     _EnPassant:=pos.EnPassant;
  1820.  
  1821.     Paint;
  1822.     Result:=TRUE;
  1823. end;
  1824.  
  1825. procedure  TChessBrd.NewGame;
  1826. begin
  1827.     SetNewGame;
  1828.     Paint;
  1829. end;
  1830.  
  1831. procedure TChessbrd.SetNewGame;
  1832. begin
  1833.     CancelThinking;
  1834.     _position:='_rnbqkbnrpppppppp                                PPPPPPPPRNBQKBNR';
  1835.  
  1836.     _whiteToMove:=TRUE;
  1837.     _CurrentMove:=1;
  1838.     FirstMove:=1;
  1839.     FirstTurn:=TRUE;
  1840.     LastMove:=1;
  1841.     LastTurn:=TRUE;
  1842.  
  1843.     _EnPassant:=None;
  1844.  
  1845.     Include (_castlingallowed,WhiteKingSide);
  1846.     Include (_castlingallowed,WhiteQueenSide);
  1847.     Include (_castlingallowed,BlackKingSide);
  1848.     Include (_castlingallowed,BlackQueenSide);
  1849. end;
  1850.  
  1851.  
  1852.  
  1853. function TChessBrd.Move(oldSq,newSq: Square): Boolean;
  1854. begin
  1855.     CancelThinking;
  1856.     Result:=PerformMove(oldsq,newsq);
  1857.     stopThinking:=FALSE;
  1858.     Think;
  1859.  
  1860. end;
  1861.  
  1862.  
  1863. function TChessBrd.PerformMove (oldsq, newsq: Square): Boolean;
  1864. var
  1865.     check,draw,stillmove: Boolean;
  1866.     oldpiece: Char;
  1867.     sq: Square;
  1868.     r: Integer;
  1869.     bcount,wcount: Integer;
  1870. begin
  1871.     GameEnded:=FALSE;
  1872.  
  1873.     if (MoveIsLegal(oldsq,newsq)=FALSE)then
  1874.     begin
  1875.         Result:=FALSE;
  1876.         Exit;
  1877.     end;
  1878.  
  1879.     check:=(WhiteInCheckAfter(oldsq,newsq)or BlackInCheckAfter(oldsq,newsq));
  1880.     draw:=FALSE;
  1881.  
  1882.     MoveList[_CurrentMove,1-Integer(_whiteToMove)].position:=StrPas(@_position[1]);
  1883.     MoveList[_CurrentMove,1-Integer(_whiteToMove)].Castling:=_castlingallowed;
  1884.     MoveList[_CurrentMove,1-Integer(_whiteToMove)].EnPassant:=_EnPassant;
  1885.     MoveList[_CurrentMove,1-Integer(_whiteToMove)].OldSquare:=Square(oldsq);
  1886.     MoveList[_CurrentMove,1-Integer(_whiteToMove)].NewSquare:=Square(newsq);
  1887.  
  1888.     ClearSquare(oldsq);
  1889.  
  1890.     if (_AnimateMoves) and ((oldSq<>squareClick1)or(newSq<>squareClick2)) then
  1891.     begin
  1892.         DrawBoardLines;
  1893.         Animate (oldSq,newSq,_animationDelay);
  1894.     end;
  1895.  
  1896.     oldpiece:=_position[Integer(newsq)];
  1897.     _position[Integer(newsq)]:=_position[Integer(oldsq)];
  1898.     _position[Integer(oldsq)]:=' ';
  1899.  
  1900.     ClearSquare(newsq);
  1901.     DrawPiece(newsq,_position[Integer(newsq)]);
  1902.     DrawBoardLines;
  1903.  
  1904.     if (_whiteToMove=FALSE) then _CurrentMove:=_CurrentMove+1;
  1905.     _whiteToMove:=not _whiteToMove;
  1906.  
  1907.     LastMove:=_CurrentMove;
  1908.     LastTurn:=_whiteToMove;
  1909.  
  1910.     //Call OnLegalMove event handler
  1911.     if (@_legalmove<>nil) then
  1912.         _legalmove(Self,oldsq,newsq);
  1913.  
  1914.     //Eventually call OnCapture event handler (also in En Passant)
  1915.     if (oldpiece<>' ')and(@_capture<>nil)then
  1916.         _capture(Self,oldsq,newsq,oldpiece);
  1917.  
  1918.     //More to do if last move was a promotion
  1919.     if ((((_position[Integer(newsq)])='p')or(_position[Integer(newsq)]='P'))and
  1920.         ((YPos(newsq)=8) or (YPos(newsq)=1)))then
  1921.     begin
  1922.         if (@_promotion<>nil)then
  1923.         begin
  1924.              _promotion(Self,oldsq,newsq,PromoteTo);
  1925.         end;
  1926.  
  1927.         DoPromotion(newsq);
  1928.         check:=(WhiteInCheckAfter(newsq,newsq))or(BlackInCheckAfter(newsq,newsq));
  1929.     end;
  1930.  
  1931.     //More to do if last move was En Passant capture
  1932.     if (_EnPassant=newsq)then
  1933.     begin
  1934.         if (YPos(newsq)=6)and (_position[Integer(newsq)]='P') then
  1935.         begin
  1936.             sq:=MouseToSquare(XPos(newsq),5);
  1937.             if (@_capture<>nil)then
  1938.                 _capture(Self,oldsq,newsq,_position[Integer(sq)]);
  1939.             _position[Integer(sq)]:=' ';
  1940.             ClearSquare(sq);
  1941.             DrawBoardLines;
  1942.         end
  1943.         else if (YPos(newsq)=3)and (_position[Integer(newsq)]='p')then
  1944.         begin
  1945.             sq:=MouseToSquare(XPos(newsq),4);
  1946.             if (@_capture<>nil)then
  1947.                 _capture(Self,oldsq,newsq,_position[Integer(sq)]);
  1948.             _position[Integer(sq)]:=' ';
  1949.             ClearSquare(sq);
  1950.             DrawBoardLines;
  1951.         end;
  1952.     end;
  1953.  
  1954.     //More to do if last move allows En Passant continuation
  1955.     if (((_position[Integer(newsq)]='P')and(YPos(oldsq)=2)and(YPos(newsq)=4))or
  1956.         ((_position[Integer(newsq)]='p')and(YPos(oldsq)=7)and(YPos(newsq)=5)))then
  1957.     begin
  1958.         _EnPassant:=Square ((Integer(oldsq)+Integer(newsq)) shr 1);
  1959.     end
  1960.  
  1961.     else _EnPassant:=None;
  1962.  
  1963.     //More to do if last move was castling
  1964.     if (_position[Integer(newsq)]='K')and(oldsq=E1) then
  1965.     begin
  1966.         if (Square(newsq)=G1)then
  1967.         begin
  1968.             _position[Integer(F1)]:='R';
  1969.             _position[Integer(H1)]:=' ';
  1970.             ClearSquare(H1);
  1971.             DrawPiece(F1,'R');
  1972.             DrawBoardLines;
  1973.             if (@_castle<>nil)then
  1974.                 _castle(Self,oldsq,newsq);
  1975.         end
  1976.         else if (Square(newsq)=C1)then
  1977.         begin
  1978.             _position[Integer(D1)]:='R';
  1979.             _position[Integer(A1)]:=' ';
  1980.             ClearSquare(A1);
  1981.             DrawPiece(D1,'R');
  1982.             DrawBoardLines;
  1983.             if (@_castle<>nil)then
  1984.                 _castle(Self,oldsq,newsq);
  1985.         end;
  1986.     end
  1987.     else if (_position[Integer(newsq)]='k')and(Square(oldsq)=E8)then
  1988.     begin
  1989.         if (Square(newsq)=G8)then
  1990.         begin
  1991.             _position[Integer(F8)]:='r';
  1992.             _position[Integer(H8)]:=' ';
  1993.             ClearSquare(H8);
  1994.             DrawPiece(F8,'r');
  1995.             DrawBoardLines;
  1996.             if (@_castle<>nil)then
  1997.                 _castle(Self,oldsq,newsq);
  1998.         end
  1999.         else if (Square(newsq)=C8)then
  2000.         begin
  2001.             _position[Integer(D8)]:='r';
  2002.             _position[Integer(A8)]:=' ';
  2003.             ClearSquare(A8);
  2004.             DrawPiece(D8,'r');
  2005.             DrawBoardLines;
  2006.             if (@_castle<>nil)then
  2007.                 _castle(Self,oldsq,newsq);
  2008.         end;
  2009.     end;
  2010.  
  2011.     //Eventually Remove Castling Allowance
  2012.  
  2013.     case Square(oldsq) of
  2014.         //if a rook moved
  2015.         A1: begin
  2016.             Exclude(_castlingallowed,WhiteQueenSide);
  2017.             end;
  2018.         H1: begin
  2019.             Exclude (_castlingallowed,WhiteKingSide);
  2020.             end;
  2021.         A8: begin
  2022.             Exclude (_castlingallowed,BlackQueenSide);
  2023.             end;
  2024.         H8: begin
  2025.             Exclude (_castlingallowed,BlackKingSide);
  2026.             end;
  2027.  
  2028.         //or if a king moved
  2029.         E1: begin
  2030.             Exclude (_castlingallowed,WhiteQueenSide);
  2031.             Exclude (_castlingallowed,WhiteKingSide);
  2032.             end;
  2033.         E8: begin
  2034.             Exclude (_castlingallowed,BlackQueenSide);
  2035.             Exclude (_castlingallowed,BlackKingSide);
  2036.             end;
  2037.     end;
  2038.  
  2039.     //More to do if there's mate or stalemate
  2040.  
  2041.     stillmove:=LegalMoveAvailable();
  2042.     if (check)then
  2043.     begin
  2044.         if (@_check<>nil)then
  2045.             _check(Self,oldsq,newsq);
  2046.         if (stillmove=FALSE)and(@_mate<>nil)then
  2047.         begin
  2048.             GameEnded:=TRUE;
  2049.             _mate(Self,oldsq,newsq);
  2050.         end;
  2051.     end
  2052.     else
  2053.     begin
  2054.         if (stillmove=FALSE) then
  2055.         begin
  2056.             if (@_stalemate<>nil) then _stalemate(Self,oldsq,newsq);
  2057.             draw:=TRUE;
  2058.  
  2059.         end;
  2060.     end;
  2061.  
  2062.     //More to do if there's only no more mating material at all on the board
  2063.     bcount:=0;
  2064.     wcount:=0;
  2065.     for r:=1 to 64 do
  2066.     begin
  2067.          case _position[r] of
  2068.             'r': wcount:=wcount+5;
  2069.             'q': wcount:=wcount+5;
  2070.             'p': wcount:=wcount+5;
  2071.             'b': wcount:=wcount+3;
  2072.             'n': wcount:=wcount+2;
  2073.             'R': bcount:=bcount+5;
  2074.             'Q': bcount:=bcount+5;
  2075.             'P': bcount:=bcount+5;
  2076.             'B': bcount:=bcount+3;
  2077.             'N': bcount:=bcount+2;
  2078.         end;
  2079.     end;
  2080.  
  2081.     if (wcount<5)and(bcount<5) then
  2082.     begin
  2083.         if (@_noMatingMaterial<>nil) then _noMatingMaterial(Self);
  2084.         draw:=TRUE;
  2085.     end;
  2086.  
  2087.     MoveList[_CurrentMove,1-Integer(_whiteToMove)].position:=StrPas(@_position[1]);
  2088.     MoveList[_CurrentMove,1-Integer(_whiteToMove)].Castling:=_castlingallowed;
  2089.     MoveList[_CurrentMove,1-Integer(_whiteToMove)].enPassant:=_EnPassant;
  2090.     LastMove:=_CurrentMove;
  2091.     LastTurn:=_whiteToMove;
  2092.  
  2093.     // Or a Threefold Position in the game
  2094.     if (CheckForThreefoldPosition=TRUE) then
  2095.     begin
  2096.         if (@_threefoldPosition<>nil) then _threefoldPosition(Self);
  2097.         draw:=TRUE;
  2098.     end;
  2099.  
  2100.     if (draw)and(@_draw<>nil) then
  2101.     begin
  2102.         GameEnded:=TRUE;
  2103.         _draw(Self);
  2104.     end;
  2105.  
  2106.     if (@_paint<>nil) then _paint(Self);
  2107.  
  2108.     Result:=TRUE;
  2109. end;
  2110.  
  2111. function TChessBrd.MoveBackward: Boolean;
  2112. begin
  2113.      if (_whiteToMove)then
  2114.         Result:=(GotoMove  (_CurrentMove-1, FALSE))
  2115.      else Result:=(GotoMove (_CurrentMove, TRUE));
  2116. end;
  2117.  
  2118. function TChessBrd.MoveForward: Boolean;
  2119. begin
  2120.     if (_whiteToMove)then
  2121.         Result:=GotoMove  (_CurrentMove, FALSE)
  2122.     else Result:=GotoMove (_CurrentMove+1, TRUE);
  2123. end;
  2124.  
  2125.  
  2126. function TChessBrd.GotoMove (moveno: Integer; whiteMoves: Boolean): Boolean;
  2127. var
  2128.     oldpos: String;
  2129. begin
  2130.  
  2131.     Result:=FALSE;
  2132.  
  2133.     CancelThinking;
  2134.  
  2135.     if (moveno>LastMove)or((moveno=LastMove)and(LastTurn)and(whiteMoves=FALSE))then
  2136.     begin
  2137.         Exit;
  2138.     end;
  2139.  
  2140.     if (moveno<FirstMove)or((moveno=FirstMove)and(FirstTurn=FALSE)and(whiteMoves))then
  2141.     begin
  2142.         Exit;
  2143.     end;
  2144.  
  2145.     _CurrentMove:=moveno;
  2146.     _whiteToMove:=whiteMoves;
  2147.  
  2148.     oldpos   :=StrPas(@_position[1]);
  2149.     StrPCopy(@_position[1],MoveList[_CurrentMove,1-Integer(_whiteToMove)].position);
  2150.     _EnPassant:=MoveList[_CurrentMove,1-Integer(_whiteToMove)].EnPassant;
  2151.     _castlingallowed :=MoveList[_CurrentMove,1-Integer(_whiteToMove)].Castling;
  2152.  
  2153.     UpdateChessBoard(oldpos);
  2154.  
  2155.     Result:=TRUE;
  2156. end;
  2157.  
  2158. function  TChessBrd.LegalMoveAvailable: Boolean;
  2159. var
  2160.     r,n: Square;
  2161. begin
  2162.     Result:=TRUE;
  2163.  
  2164.     if (_whiteToMove)then
  2165.         begin
  2166.         for r:=A8 to H1 do
  2167.         if (ColorOfPieceOnSquare(Square(r))=White)then
  2168.             begin
  2169.             for n:=A8 to H1 do
  2170.                  if (MoveIsLegal(r,n)and (WhiteInCheckAfter(r,n)=FALSE))then
  2171.                      Exit;
  2172.             end;
  2173.         end
  2174.     else
  2175.         begin
  2176.         for r:=A8 to H1 do
  2177.         if (ColorOfPieceOnSquare(r)=Black)then
  2178.             begin
  2179.             for n:=A8 to H1 do
  2180.                  if (MoveIsLegal(r,n)and (BlackInCheckAfter(r,n)=FALSE))then
  2181.                     Exit;
  2182.             end;
  2183.         end;
  2184.  
  2185.     Result:=FALSE;
  2186. end;
  2187.  
  2188. //-------------------------------------------------------------
  2189. //-------------------PRIVATE Stuff here------------------------
  2190. //-------------------------------------------------------------
  2191.  
  2192. function TChessBrd.CheckForThreefoldPosition: Boolean;
  2193. var
  2194.     turn,t,move,m: Integer;
  2195.     count: Integer;
  2196. begin
  2197.     count:=0;
  2198.  
  2199.     move:=_CurrentMove;
  2200.     m:=move;
  2201.  
  2202.     if _WhiteToMove then turn:=0 else turn:=1;
  2203.     t:=turn;
  2204.  
  2205.     while (TRUE) do
  2206.         begin
  2207.         t:=t-1;
  2208.         if (t<0) then
  2209.             begin
  2210.             t:=1;
  2211.             m:=m-1;
  2212.             end;
  2213.         if (m<1) then Break;
  2214.         if MoveList[move,turn].position=MoveList[m,t].position then
  2215.             count:=count+1;
  2216.         end;
  2217.  
  2218.     Result:=(count>=2);
  2219. end;
  2220.  
  2221.  
  2222.  
  2223. function TChessBrd.MoveIsLegal (oldsq, newsq: Square): Boolean;
  2224. var
  2225.     piece: Char;
  2226. begin
  2227.     Result:=FALSE;
  2228.  
  2229.     piece:=Char(Integer(UpCase(_position[Integer(oldsq)]))+32);
  2230.  
  2231.     if (oldsq<A8)or(oldsq>H1)or(newsq<A8)or(newsq>H1)or
  2232.        (CheckForThreefoldPosition=TRUE) then
  2233.         Exit;
  2234.  
  2235.     //Turn to the right color ?
  2236.     if (_whiteToMove)then
  2237.         begin
  2238.         if (ColorOfPieceOnSquare(oldsq)<>White) then Exit;
  2239.         end
  2240.     else
  2241.         begin
  2242.         if (ColorOfPieceOnSquare(oldsq)<>Black) then Exit;
  2243.         end;
  2244.     // Old int does't contain a piece ?
  2245.     if (ColorOfPieceOnSquare(oldsq)=NoPiece) then
  2246.          Exit;
  2247.  
  2248.     // Can't take piece of own color
  2249.     if (ColorOfPieceOnSquare(oldsq)=ColorOfPieceOnSquare(newsq)) then
  2250.            Exit;
  2251.  
  2252.     Result:=TRUE;
  2253.  
  2254.     case piece of
  2255.         'p':  begin
  2256.               Result:=CheckLegalPawnMove(oldsq,newsq);
  2257.               end;
  2258.         'n':  begin
  2259.               Result:=CheckLegalKnightMove(oldsq,newsq);
  2260.               end;
  2261.         'b':  begin
  2262.               Result:=CheckLegalBishopMove(oldsq,newsq);
  2263.               end;
  2264.         'r':  begin
  2265.               Result:=CheckLegalRookMove(oldsq,newsq);
  2266.               end;
  2267.         'q':  begin
  2268.               Result:=CheckLegalQueenMove(oldsq,newsq);
  2269.               end;
  2270.         'k':  begin
  2271.               Result:=CheckLegalKingMove(oldsq,newsq);
  2272.               end;
  2273.     end;
  2274.  
  2275.     if (Result)then
  2276.         begin
  2277.         if (ColorOfPieceOnSquare(oldsq)=Black)and
  2278.             (BlackInCheckAfter(oldsq,newsq)=TRUE)then
  2279.              Result:=FALSE
  2280.         else if (ColorOfPieceOnSquare(oldsq)=White)and
  2281.             (WhiteInCheckAfter(oldsq,newsq)=TRUE)then
  2282.              Result:=FALSE;
  2283.         end;
  2284. end;
  2285.  
  2286. //Checks whether black is in check after the specified move
  2287. function TChessBrd.BlackInCheckAfter(oldsq, newsq: Square): Boolean;
  2288. var
  2289.     v: Char;
  2290.     pos: String;
  2291.     x,y,r,res: Integer;
  2292.     kingsq: Square;
  2293. begin
  2294.     Result:=TRUE;
  2295.  
  2296.     pos:=StrPas(@_position[1]);
  2297.  
  2298.     v:=pos[Integer(oldsq)];
  2299.     pos[Integer(oldsq)]:=' ';
  2300.     pos[Integer(newsq)]:=v;
  2301.  
  2302.     for r:=1 to 65 do
  2303.      begin
  2304.      res:=r;
  2305.      if (pos[r]='k') then
  2306.          Break;
  2307.      end;
  2308.  
  2309.     kingsq:=Square(res);
  2310.     if (res>64) then
  2311.         Exit;
  2312.  
  2313.     //pawn check
  2314.     for x:=-1 to 1 do
  2315.      if (x<>0)and(pos[Integer(MouseToSquare(XPos(kingsq)+x,YPos(kingsq)-1))]='P') then
  2316.        Exit;
  2317.  
  2318.     //knight check
  2319.     for y:=-1 to 1 do
  2320.      if (abs(y)=1) then
  2321.       for x:=-2 to 2 do
  2322.        if (abs(x)=2)and(pos[Integer(MouseToSquare(XPos(kingsq)+x,YPos(kingsq)+y))]='N')then
  2323.          Exit;
  2324.  
  2325.     for y:=-2 to 2 do
  2326.      if (abs(y)=2) then
  2327.       for x:=-1 to 1 do
  2328.        if (x<>0)and(pos[Integer(MouseToSquare(XPos(kingsq)+x,YPos(kingsq)+y))]='N')then
  2329.             Exit;
  2330.  
  2331.     //bishop (and queen) check
  2332.     for y:=-1 to 1 do
  2333.      if (y<>0) then
  2334.       for x:=-1 to 1 do
  2335.        if (x<>0) then
  2336.         for r:=1 to 7 do
  2337.          begin
  2338.           v:=pos[Integer(MouseToSquare(XPos(kingsq)+x*r,YPos(kingsq)+y*r))];
  2339.           if (v='Q')or(v='B')or((v='K')and(r=1))then
  2340.              Exit;
  2341.           if (v<>' ') then
  2342.              Break;
  2343.          end;
  2344.  
  2345.     //rook (and queen) check
  2346.     for x:=-1 to 1 do
  2347.      if (x<>0) then
  2348.         for r:=1 to 7 do
  2349.         begin
  2350.              v:=pos[Integer(MouseToSquare(XPos(kingsq)+x*r,YPos(kingsq)))];
  2351.              if (v='Q')or(v='R')or((v='K')and(r=1))then
  2352.              begin
  2353.                 Exit;
  2354.              end;
  2355.              if (v<>' ')then
  2356.                Break;
  2357.         end;
  2358.  
  2359.     for y:=-1  to 1 do
  2360.       begin
  2361.       if (y<>0) then
  2362.         for r:=1  to 7 do
  2363.         begin
  2364.              v:=pos[Integer(MouseToSquare(XPos(kingsq),YPos(kingsq)+r*y))];
  2365.              if (v='Q')or(v='R')or ((v='K')and(r=1))then
  2366.                  begin
  2367.                  Result:=TRUE;
  2368.                  Exit;
  2369.                  end;
  2370.              if (v<>' ')then
  2371.                  Break;
  2372.         end;
  2373.       end;
  2374.  
  2375. Result:=FALSE;
  2376. end;
  2377.  
  2378. //Checks whether white is in check after the specified move
  2379. function TChessBrd.WhiteInCheckAfter(oldsq, newsq: Square): Boolean;
  2380. var
  2381.     x,y,r,res: Integer;
  2382.     kingsq: Square;
  2383.     v: Char;
  2384.     pos: String;
  2385. begin
  2386.     Result:=TRUE;
  2387.  
  2388.     pos:=StrPas(@_position[1]);
  2389.  
  2390.     //Can move to same Square
  2391.     v:=pos[Integer(oldsq)];
  2392.     pos[Integer(oldsq)]:=' ';
  2393.     pos[Integer(newsq)]:=v;
  2394.  
  2395.     for r:=1 to 65 do
  2396.        begin
  2397.        res:=r;
  2398.        if (pos[r]='K') then
  2399.           Break;
  2400.        end;
  2401.     kingsq:=Square(res);
  2402.     if (res>64) then
  2403.         begin
  2404.         Result:=FALSE;
  2405.         Exit;
  2406.         end;
  2407.  
  2408.     //pawn check
  2409.     for x:=-1 to 1 do
  2410.         if (x<>0)and(pos[Integer(MouseToSquare(XPos(kingsq)+x,YPos(kingsq)+1))]='p') then
  2411.             Exit;
  2412.  
  2413.     //knight check
  2414.     for y:=-1 to 1 do
  2415.      if(y<>0) then
  2416.       for x:=-2 to 2 do
  2417.         if (abs(x)=2)and(pos[Integer(MouseToSquare(XPos(kingsq)+x,YPos(kingsq)+y))]='n')then
  2418.             Exit;
  2419.  
  2420.     for y:=-2 to 2 do
  2421.      if (abs(y)=2)then
  2422.       for x:=-1 to 1 do
  2423.         if (x<>0)and (pos[Integer(MouseToSquare(XPos(kingsq)+x,YPos(kingsq)+y))]='n')then
  2424.           Exit;
  2425.  
  2426.  
  2427.     //bishop (and queen) check
  2428.     for y:=-1  to 1 do
  2429.       if (y<>0) then
  2430.         for x:=-1 to 1 do
  2431.             if (x<>0) then
  2432.              for r:=1 to 7 do
  2433.              begin
  2434.                   v:=pos[Integer(MouseToSquare(XPos(kingsq)+x*r,YPos(kingsq)+y*r))];
  2435.                   if (v='q')or(v='b')or ((v='k')and(r=1))then
  2436.                      Exit;
  2437.                   if (v<>' ') then
  2438.                     Break;
  2439.              end;
  2440.  
  2441.     //rook (and queen) check
  2442.     for x:=-1 to 1 do
  2443.      if (x<>0) then
  2444.        for r:=1 to 7 do
  2445.         begin
  2446.              v:=pos[Integer(MouseToSquare(XPos(kingsq)+x*r,YPos(kingsq)))];
  2447.              if (v='q')or(v='r')or((v='k')and(r=1))then
  2448.                 Exit;
  2449.              if (v<>' ')then
  2450.                  break;
  2451.         end;
  2452.  
  2453.     for y:=-1 to 1 do
  2454.       if (y<>0) then
  2455.         for r:=1 to 7 do
  2456.           begin
  2457.             v:=pos[Integer(MouseToSquare(XPos(kingsq),YPos(kingsq)+r*y))];
  2458.             if (v='q')or(v='r')or((v='k')and(r=1))then
  2459.               Exit;
  2460.             if (v<>' ') then
  2461.               Break;
  2462.           end;
  2463.  
  2464. Result:=FALSE;
  2465. end;
  2466.  
  2467. //Checks whether a pawn move is legal, assuming the king isn't in check
  2468. function TChessBrd.CheckLegalPawnMove(oldsq,newsq: Square): Boolean;
  2469. var
  2470.     deltax: Integer;
  2471. begin
  2472.     Result:=TRUE;
  2473.  
  2474.     deltax:=abs(XPos(newsq)-XPos(oldsq));
  2475.  
  2476.     if (ColorOfPieceOnSquare(oldsq)=White)then
  2477.     begin
  2478.         if (YPos(newsq)=YPos(oldsq)+1)then
  2479.         begin
  2480.             if (deltax=0)then
  2481.                 begin
  2482.                 if (_position[Integer(newsq)]=' ')then
  2483.                     Exit;
  2484.                 end
  2485.             else if (deltax=1)then
  2486.                 begin
  2487.                 if (ColorOfPieceOnSquare(newsq)=Black)or
  2488.                     (_EnPassant=newsq)then
  2489.                     Exit;
  2490.                 end;
  2491.         end
  2492.         else if ((YPos(oldsq)=2)and (YPos(newsq)=4))then
  2493.         begin
  2494.             if (deltax=0)and(_position[Integer(newsq)]=' ')
  2495.                and  (_position[(Integer(oldsq)+Integer(newsq)) shr 1]=' ') then Exit;
  2496.         end;
  2497.  
  2498.     end
  2499.     else if (ColorOfPieceOnSquare(oldsq)=Black)then
  2500.     begin
  2501.         if (YPos(newsq)=YPos(oldsq)-1)then
  2502.         begin
  2503.             if (deltax=0)then
  2504.                 begin
  2505.                 if (_position[Integer(newsq)]=' ') then Exit;
  2506.                 end
  2507.             else if (deltax=1)then
  2508.                 begin
  2509.                 if (ColorOfPieceOnSquare(newsq)=White)or
  2510.                     (_EnPassant=newsq)then
  2511.                      Exit;
  2512.                 end;
  2513.         end
  2514.         else if (YPos(oldsq)=7)and(YPos(newsq)=5)then
  2515.         begin
  2516.             if (deltax=0)and(_position[Integer(newsq)]=' ')and
  2517.                 (_position[Integer((Integer(oldsq)+Integer(newsq)) shr 1)]=' ')then
  2518.                     Exit;
  2519.         end;
  2520.     end;
  2521.  
  2522. Result:=FALSE;
  2523. end;
  2524.  
  2525. //Checks whether a knight move is legal, assuming the king isn't in check
  2526. function TChessBrd.CheckLegalKnightMove(oldsq,newsq: Square): Boolean;
  2527. var
  2528.     deltax,deltay: Integer;
  2529. begin
  2530.     deltax:=abs(XPos(oldsq)-XPos(newsq));
  2531.     deltay:=abs(YPos(oldsq)-YPos(newsq));
  2532.     Result:=(((deltax=2)and(deltay=1))or((deltax=1)and (deltay=2)));
  2533. end;
  2534.  
  2535. //Checks whether a bishop move is legal, assuming the king isn't in check
  2536. function  TChessBrd.CheckLegalBishopMove(oldsq, newsq: Square): Boolean;
  2537. var
  2538.     x,y,r,n,m,p: Integer;
  2539.     v: Square;
  2540. begin
  2541.     Result:=TRUE;
  2542.  
  2543.     x:=XPos(oldsq);
  2544.     y:=YPos(oldsq);
  2545.     p:=ColorOfPieceOnSquare(oldsq);
  2546.  
  2547.     for n:=-1 to 1 do
  2548.       if (n<>0) then
  2549.         for m:=-1 to 1 do
  2550.           if (m<>0) then
  2551.             for r:=1 to 7 do
  2552.              begin
  2553.               v:=MouseToSquare(x+n*r,y+m*r);
  2554.               if ((ColorOfPieceOnSquare(v)=NoPiece)or(ColorOfPieceOnSquare(v)<>p))then
  2555.                begin
  2556.                 if (v=newsq) then Exit;
  2557.                end;
  2558.               if (ColorOfPieceOnSquare(v)<>NoPiece)then break;
  2559.              end;
  2560.  
  2561.     Result:=FALSE;
  2562. end;
  2563.  
  2564. //Checks whether a rook move is legal, assuming the king isn't in check
  2565. function TChessBrd.CheckLegalRookMove(oldsq, newsq: Square): Boolean;
  2566. var
  2567.     x,y,r,n,p: Integer;
  2568.     v: Square;
  2569. begin
  2570.     Result:=TRUE;
  2571.  
  2572.     x:=XPos(oldsq);
  2573.     y:=YPos(oldsq);
  2574.     p:=ColorOfPieceOnSquare(oldsq);
  2575.  
  2576.     for n:=-1 to 1 do
  2577.      if (n<>0) then
  2578.         for r:=1 to 7 do
  2579.          begin
  2580.             v:=MouseToSquare(x+n*r,y);
  2581.             if ((ColorOfPieceOnSquare(v)=NoPiece)or(ColorOfPieceOnSquare(v)<>p))then
  2582.             begin
  2583.                 if (v=newsq) then Exit;
  2584.             end;
  2585.             if (ColorOfPieceOnSquare(v)<>NoPiece) then Break;
  2586.         end;
  2587.  
  2588.     for n:=-1 to 1 do
  2589.      if (n<>0) then
  2590.         for r:=1 to 7 do
  2591.         begin
  2592.             v:=MouseToSquare(x,y+n*r);
  2593.             if ((ColorOfPieceOnSquare(v)=NoPiece)or(ColorOfPieceOnSquare(v)<>p))then
  2594.             begin
  2595.                 if (v=newsq) then Exit;
  2596.             end;
  2597.             if (ColorOfPieceOnSquare(v)<>NoPiece) then Break;
  2598.         end;
  2599.  
  2600.     Result:=FALSE;
  2601. end;
  2602.  
  2603. //Checks whether a queen move is legal, assuming the king isn't in check
  2604. function TChessBrd.CheckLegalQueenMove(oldsq, newsq: Square): Boolean;
  2605. begin
  2606.     Result:=CheckLegalBishopMove(oldsq,newsq);
  2607.     if (Result=FALSE) then Result:=CheckLegalRookMove(oldsq,newsq);
  2608. end;
  2609.  
  2610. //Checks whether a king move is legal, assuming the king isn't in check
  2611. function TChessBrd.CheckLegalKingMove(oldsq,newsq: Square): Boolean;
  2612. var
  2613.     deltax,deltay: Integer;
  2614. begin
  2615.     Result:=TRUE;
  2616.  
  2617.     deltax:=abs(XPos(oldsq)-XPos(newsq));
  2618.     deltay:=abs(YPos(oldsq)-YPos(newsq));
  2619.  
  2620.     if ((deltax<=1)and (deltay<=1))then
  2621.         Exit;
  2622.  
  2623.     if (Square(oldsq)=E1)and(Square(newsq)=G1)then
  2624.     begin
  2625.         if (WhiteKingSide in _castlingallowed) and  (_position[Integer(H1)]='R') and
  2626.             (_position[Integer(G1)]=' ') and  (_position[Integer(F1)]=' ') and
  2627.             (not WhiteInCheckAfter(E1,E1)) and
  2628.             (not WhiteInCheckAfter(E1,F1)) and
  2629.             (not WhiteInCheckAfter(E1,G1)) then
  2630.                 Exit;
  2631.     end;
  2632.     if (oldsq=E1)and(newsq=C1) then
  2633.     begin
  2634.         if (WhiteQueenSide in _castlingallowed) and(_position[Integer(A1)]='R')and
  2635.            (_position[Integer(B1)]=' ')and(_position[Integer(C1)]=' ')and (_position[Integer(D1)]=' ') and
  2636.             (not WhiteInCheckAfter(E1,E1)) and
  2637.             (not WhiteInCheckAfter(E1,D1)) and
  2638.             (not WhiteInCheckAfter(E1,C1)) then
  2639.                 Exit;
  2640.     end;
  2641.     if (oldsq=E8)and(newsq=G8)then
  2642.     begin
  2643.         if (BlackKingSide in _castlingallowed)and(_position[Integer(H8)]='r')and
  2644.             (_position[Integer(G8)]=' ')and(_position[Integer(F8)]=' ') and
  2645.             (not BlackInCheckAfter(E8,E8)) and
  2646.             (not BlackInCheckAfter(E8,F8))and
  2647.             (not BlackInCheckAfter(E8,G8)) then
  2648.                 Exit;
  2649.     end;
  2650.     if (oldsq=E8)and(newsq=C8)then
  2651.     begin
  2652.         if (BlackQueenSide in _castlingallowed) and (_position[Integer(A8)]='r') and
  2653.            (_position[Integer(B8)]=' ')and(_position[Integer(C8)]=' ')and
  2654.            (_position[Integer(D8)]=' ')and
  2655.             (not BlackInCheckAfter(E8,E8)) and
  2656.             (not BlackInCheckAfter(E8,D8)) and
  2657.             (not BlackInCheckAfter(E8,C8)) then
  2658.                 Exit;
  2659.     end;
  2660.  
  2661.     Result:=FALSE;
  2662. end;
  2663.  
  2664. procedure  TChessBrd.InitializeBitmap;
  2665. begin
  2666.       Default.Handle:=LoadBitmap(hInstance, StrPCopy(@buf,SetAndrew40Str));
  2667. end;
  2668.  
  2669. //-------------------------------------------------------------------------------
  2670. // Implementation of TChessThread (containing mainly Tom's Source)
  2671. //-------------------------------------------------------------------------------
  2672.  
  2673. constructor TChessThread.Create;
  2674. begin
  2675.     InitValues;
  2676.     inherited Create(TRUE);
  2677. end;
  2678.  
  2679.  
  2680. // The execution point of the thread
  2681. procedure TChessThread.Execute;
  2682. begin
  2683.     repeat
  2684.     begin
  2685.         if ((ComputerPlaysWhite^)and(WhiteToMove^))or
  2686.            ((ComputerPlaysBlack^)and(WhiteToMove^=FALSE)) then
  2687.         begin
  2688.              Priority:=ThinkingPriority^;
  2689.              Thinking:=TRUE;
  2690.              ThinkAboutAMove;
  2691.              if (StopThinkingNow=FALSE) then
  2692.              begin
  2693.                  makemove(pv[0,0].b);
  2694.                  gen;
  2695.                  Thinking:=FALSE;
  2696.                  Synchronize(PerformMove);
  2697.              end;
  2698.         end;
  2699.         Synchronize (ThinkingFinished)
  2700.     end;
  2701.     until (Terminated=TRUE);
  2702. end;
  2703.  
  2704. procedure TChessThread.ThinkAboutAMove;
  2705. var
  2706.     x,y,r,v,i: Integer;
  2707.     ch: Char;
  2708. begin
  2709.     for r:=0 to 63 do
  2710.     begin
  2711.         v:=ColorOfPiece(Square(r+1));
  2712.         if (v=Black) then color[r]:=DARK
  2713.         else if (v=White) then color[r]:=LIGHT
  2714.         else color[r]:=EMPTY;
  2715.         ch:=Position[r+1];
  2716.         if (Integer(ch)>=Integer('A'))and(Integer(ch)<=Integer('Z')) then
  2717.             ch:=Char(Byte(ch)+32);
  2718.         case ch of
  2719.             'p':piece[r]:=PAWN;
  2720.             'n':piece[r]:=KNIGHT;
  2721.             'b':piece[r]:=BISHOP;
  2722.             'r':piece[r]:=ROOK;
  2723.             'q':piece[r]:=QUEEN;
  2724.             'k':piece[r]:=KING;
  2725.            else piece[r]:=EMPTY;
  2726.         end;
  2727.     end;
  2728.  
  2729.     if (WhiteToMove^=TRUE)then
  2730.     begin
  2731.         side:=LIGHT;
  2732.         xside:=DARK;
  2733.     end
  2734.     else
  2735.     begin
  2736.         side:=DARK;
  2737.         xside:=LIGHT;
  2738.     end;
  2739.  
  2740.     castle:=0;
  2741.     if (WhiteKingSide in Castling^) then
  2742.         castle:=castle or 1;
  2743.     if (WhiteQueenSide in Castling^) then
  2744.         castle:=castle or 2;
  2745.     if (BlackKingSIde in Castling^) then
  2746.         castle:=castle or 4;
  2747.     if (BlackQueenSide in Castling^) then
  2748.         castle:=castle or 8;
  2749.  
  2750.     ep:=Integer(EnPassant^)-1;
  2751.     fifty:=0;
  2752.     ply:=0;
  2753.     gen_begin[0]:=0;
  2754.  
  2755.     nodes:=0;
  2756.     init_eval;
  2757.  
  2758.     for x:=0 to 63 do
  2759.     for y:=0 to 63 do
  2760.         history[x,y]:=0;
  2761.  
  2762.     follow_pv:=TRUE;
  2763.  
  2764.     for i:=1 to SearchDepth^ do
  2765.     begin
  2766.         if (StopThinkingNow=FALSE) then
  2767.         begin
  2768.             follow_pv:=TRUE;
  2769.             search(-10000,10000,i);
  2770.         end;
  2771.     end;
  2772.  
  2773. end;
  2774.  
  2775. //---------------------------------------------------------------------------
  2776. // Synchronized Methods
  2777. //---------------------------------------------------------------------------
  2778.  
  2779. procedure TChessThread.ThinkingFinished;
  2780. begin
  2781.     EndFunc(Self);
  2782. end;
  2783.  
  2784. // Synchronizer - Modifies VCL
  2785. procedure TChessThread.PerformMove;
  2786. begin
  2787.      if (Movefunc(Square(Integer(pv[0,0].b.src)+1),Square(Integer(pv[0,0].b.dst)+1))=FALSE) then
  2788.      begin
  2789. //       Tom's engine does not recognize the threefold position rule
  2790. //       so the exception may occur after a draw.
  2791. //
  2792. //       raise EChessException.Create('Engine tried to perform illegal move');
  2793.      end
  2794. end;
  2795.  
  2796. procedure TChessThread.IntCopy (dest,source: pInt; count: Integer);
  2797. var
  2798.    r: Integer;
  2799. begin
  2800.     if (dest=nil)or(source=nil) then Exit;
  2801.     for r:=1 to count do
  2802.     begin
  2803.         dest^:=source^;
  2804.         Inc(source);
  2805.         Inc(dest);
  2806.     end;
  2807. end;
  2808.  
  2809.  
  2810. function TChessThread.ColorOfPiece (sq: Square): Integer;
  2811. begin
  2812.     if (Position[Integer(sq)]>='b')and(Position[Integer(sq)]<='r') then Result:=Black
  2813.     else if (Position[Integer(sq)]>='B')and(Position[Integer(sq)]<='R') then Result:=White
  2814.     else Result:=NoPiece;
  2815. end;
  2816.  
  2817.  
  2818. // sort_pv() is called when the search function is following
  2819. // the PV (Principal Variation). It looks through the current
  2820. // ply's move list to see if the PV move is there. If so,
  2821. // it adds 10,000,000 to the move's score so it's played first
  2822. // by the search function. If not, follow_pv remains FALSE and
  2823. // search() stops calling sort_pv().
  2824.  
  2825. procedure TChessThread.sort_pv;
  2826. var
  2827.     i: Integer;
  2828.     m1,m2: Move_Bytes;
  2829. begin
  2830.     follow_pv:=FALSE;
  2831.     for i:=gen_begin[ply] to gen_end[ply]-1 do
  2832.     begin
  2833.         m1:=gen_dat[i].m.b;
  2834.         m2:=pv[0,ply].b;
  2835.  
  2836.         if(m1.src=m2.src)and(m2.dst=m2.dst)then
  2837. //            (m1.promote=m2.promote)and(m1.bits=m2.bits)then
  2838.         begin
  2839.             follow_pv:=TRUE;
  2840.             gen_dat[i].score:=gen_dat[i].score+10000000;
  2841.             Exit;
  2842.         end;
  2843.     end;
  2844. end;
  2845.  
  2846. // sort() searches the current ply's move list from 'from'
  2847. // to the end to find the move with the highest score. Then it
  2848. // swaps that move and the 'from' move so the move with the
  2849. // highest score gets searched next, and hopefully produces
  2850. // a cutoff.
  2851. procedure TChessThread.sort(src: Integer);
  2852. var
  2853.    i:  Integer;
  2854.    bs: Integer;  // best score
  2855.    bi: Integer;  // best i
  2856.    g:  gen_rec;
  2857. begin
  2858.     bs:=-1;
  2859.     bi:=0;
  2860.     for i:=src to gen_end[ply]-1 do
  2861.     begin
  2862.         if(gen_dat[i].score>bs) then
  2863.         begin
  2864.             bs:=gen_dat[i].score;
  2865.             bi:=i;
  2866.         end;
  2867.     end;
  2868.  
  2869.     g:=gen_dat[src];
  2870.     gen_dat[src]:=gen_dat[bi];
  2871.     gen_dat[bi]:=g;
  2872. end;
  2873.  
  2874.  
  2875. // quiesce() is a recursive minimax search function with
  2876. // alpha-beta cutoffs. In other words, negamax. It basically
  2877. // only searches capture sequences and allows the evaluation
  2878. // function to cut the search off (and set alpha). The idea
  2879. // is to find a position where there isn't a lot going on
  2880. // so the static evaluation function will work.
  2881. function TChessThread.quiesce(alpha,beta: Integer): Integer;
  2882. var
  2883.     i,j,x: Integer;
  2884.     c,f: Boolean;
  2885. begin
  2886.     nodes:=nodes+1;
  2887.     pv_length[ply]:=ply;
  2888.     c:=in_check(side);
  2889.  
  2890.     // if we're in check, try all moves to get out. (not
  2891.     // necessary, just something I decided to do)
  2892.     // otherwise, use the evaluation function.
  2893.  
  2894.     if(c) then
  2895.     begin
  2896.         gen;
  2897.     end
  2898.     else
  2899.     begin
  2900.         x:=eval;
  2901.         if(x>=beta) then
  2902.         begin
  2903.             Result:=beta;
  2904.             Exit;
  2905.         end;
  2906.         if(x>alpha) then
  2907.             alpha:=x;
  2908.         gen_caps;
  2909.     end;
  2910.  
  2911.     if(follow_pv) then  sort_pv;     // are we following the PV?
  2912.  
  2913.     f:=FALSE;
  2914.  
  2915.     // loop through the moves
  2916.     for i:=gen_begin[ply] to gen_end[ply]-1 do
  2917.     begin
  2918.         sort(i);
  2919.         if(makemove(gen_dat[i].m.b)=FALSE) then
  2920.             continue;
  2921.         f:=TRUE;  // we found a legal move!
  2922.         x:=-quiesce(-beta,-alpha);
  2923.         takeback;
  2924.         if(x>alpha) then
  2925.         begin
  2926.             if(x>=beta) then
  2927.             begin
  2928.                 Result:=beta;
  2929.                 Exit;
  2930.             end;
  2931.  
  2932.             alpha:=x;
  2933.  
  2934.             // update the PV
  2935.             pv[ply,ply]:=gen_dat[i].m;
  2936.             for j:=ply+1 to pv_length[ply+1]-1 do
  2937.             begin
  2938.                 pv[ply,j]:=pv[ply+1,j];
  2939.             end;
  2940.             pv_length[ply]:=pv_length[ply+1];
  2941.         end;
  2942.     end;
  2943.  
  2944.     // if we're in check and there aren't any legal moves,
  2945.     // well, we lost
  2946.  
  2947.     if(f=false)and(c=true) then
  2948.         Result:=(-10000+ply)
  2949.     else Result:=alpha;
  2950. end;
  2951.  
  2952. // search() does just that, in negamax fashion
  2953. function TChessThread.search(alpha,beta,depth: Integer): Integer;
  2954. var
  2955.     i,j,x: Integer;
  2956.     c,f: Boolean;
  2957. begin
  2958.     if (StopThinkingNow=FALSE) then
  2959.     begin
  2960.         // we're as deep as we want to be; call quiesce() to get
  2961.         // a reasonable score and return it.
  2962.  
  2963.         if(depth=0) then
  2964.         begin
  2965.             Result:=quiesce(alpha,beta);
  2966.             Exit;
  2967.         end;
  2968.  
  2969.         nodes:=nodes+1;
  2970.         pv_length[ply]:=ply;
  2971.  
  2972.         // are we in check? if so, we want to search deeper
  2973.         c:=in_check(side);
  2974.         if(c) then
  2975.             depth:=depth+1;
  2976.  
  2977.         gen;
  2978.         if(follow_pv) then  // are we following the PV?
  2979.             sort_pv;
  2980.         f:=FALSE;
  2981.  
  2982.         // loop through the moves
  2983.         for i:=gen_begin[ply] to gen_end[ply]-1 do
  2984.         begin
  2985.             if (StopThinkingNow) then Break;
  2986.  
  2987.             sort(i);
  2988.             if(makemove(gen_dat[i].m.b)=FALSE)then
  2989.                 continue;
  2990.  
  2991.             f:=TRUE;
  2992.  
  2993.             x:=-search(-beta,-alpha,depth-1);
  2994.  
  2995.             takeback;
  2996.  
  2997.             if(x>alpha) then
  2998.             begin
  2999.                 // this move caused a cutoff, so increase the history
  3000.                 // value so it gets ordered high next time we can
  3001.                 // search it
  3002.  
  3003.                 history[Integer(gen_dat[i].m.b.src),Integer(gen_dat[i].m.b.dst)]:=
  3004.                 history[Integer(gen_dat[i].m.b.src),Integer(gen_dat[i].m.b.dst)]+depth;
  3005.  
  3006.                 if(x>=beta) then
  3007.                 begin
  3008.                     Result:=beta;
  3009.                     Exit;
  3010.                 end;
  3011.  
  3012.                 alpha:=x;
  3013.  
  3014.                 // update the PV
  3015.                 pv[ply,ply]:=gen_dat[i].m;
  3016.                 for j:=ply+1 to pv_length[ply+1]-1 do
  3017.                 begin
  3018.                     pv[ply,j]:=pv[ply+1,j];
  3019.                 end;
  3020.  
  3021.                 pv_length[ply]:=pv_length[ply+1];
  3022.             end;
  3023.         end;
  3024.  
  3025.         // no legal moves? then we're in checkmate or stalemate
  3026.         if(f=false) then
  3027.         begin
  3028.             if(c) then
  3029.             begin
  3030.                 Result:=(-10000+ply);
  3031.                 Exit;
  3032.             end
  3033.             else
  3034.             begin
  3035.                 Result:=0;
  3036.                 Exit;
  3037.             end;
  3038.         end;
  3039.  
  3040.         // fifty move draw rule
  3041.  
  3042.         if(fifty>100) then
  3043.             Result:=0 else
  3044.         Result:=alpha;
  3045.     end
  3046.     else Result:=0;
  3047. end;
  3048.  
  3049. // in_check() returns TRUE if side s is in check and FALSE
  3050. // otherwise. It just scans the board to find side s's king
  3051. // and calls attack() to see if it's being attacked.
  3052. function TChessThread.in_check(s: Integer): Boolean;
  3053. var
  3054.     i: Integer;
  3055. begin
  3056.     for i:=0 to 63 do
  3057.     begin
  3058.         if(color[i]=s)and(piece[i]=KING)then
  3059.         begin
  3060.             Result:=attack(i,s xor 1);
  3061.             Exit;
  3062.         end;
  3063.     end;
  3064.     Result:=FALSE;
  3065. end;
  3066.  
  3067. // attack returns TRUE if square sq is being attacked by side
  3068. // s and FALSE otherwise.
  3069. function TChessThread.attack(sq,s: Integer ): Boolean;
  3070. var
  3071.     r,i,j,n: Integer;
  3072. begin
  3073.     for i:=0 to 63 do
  3074.     begin
  3075.         if(color[i]=s) then
  3076.          begin
  3077.             if(piece[i]=PAWN)then
  3078.              begin
  3079.                 if(s=LIGHT) then
  3080.                 begin
  3081.                     if ((i and 7)<>0)and(i-9=sq) then
  3082.                     begin
  3083.                         Result:=TRUE;
  3084.                         Exit;
  3085.                     end;
  3086.                     if((i and 7)<>7)and(i-7=sq) then
  3087.                     begin
  3088.                         Result:=TRUE;
  3089.                         Exit;
  3090.                     end;
  3091.                 end
  3092.                 else
  3093.                 begin
  3094.                     if((i and 7)<>0)and(i+7=sq) then
  3095.                     begin
  3096.                         Result:=TRUE;
  3097.                         Exit;
  3098.                     end;
  3099.                     if((i and 7)<>7)and(i+9=sq) then
  3100.                     begin
  3101.                         Result:=TRUE;
  3102.                         Exit;
  3103.                     end;
  3104.                 end;
  3105.             end
  3106.             else
  3107.                 for j:=0 to offsets[piece[i]]-1 do
  3108.                 begin
  3109.                     n:=i;
  3110.                     for r:=1 to $FFFF do
  3111.                     begin
  3112.                         n:=mailbox[mailbox64[n]+offset[piece[i],j]];
  3113.                         if (n=-1) then Break;
  3114.                         if (n=sq) then
  3115.                         begin
  3116.                             Result:=TRUE;
  3117.                             Exit;
  3118.                         end;
  3119.                         if(color[n]<>EMPTY)or(slide[piece[i]]=FALSE) then Break;
  3120.                     end;
  3121.                 end;
  3122.          end;
  3123.     end;
  3124.     Result:=FALSE;
  3125. end;
  3126.  
  3127.  
  3128. // gen() generates pseudo-legal moves for the current position.
  3129. // It scans the board to find friendly pieces and then determines
  3130. // what squares they attack. When it finds a piece/square
  3131. // combination, it calls gen_push to put the move on the "move
  3132. // stack."
  3133.  
  3134. procedure TChessThread.gen;
  3135. var
  3136.     r,i,j,n: Integer;
  3137. begin
  3138.  
  3139.     // so far, we have no moves for the current ply
  3140.     gen_end[ply]:=gen_begin[ply];
  3141.     for i:=0 to 63 do
  3142.     begin
  3143.         if(color[i]=side) then
  3144.         begin
  3145.             if(piece[i]=PAWN) then
  3146.             begin
  3147.                 if(side=LIGHT) then
  3148.                  begin
  3149.                     if((i and 7)<>0)and(color[i-9]=DARK) then
  3150.                         gen_push(i,i-9,17);
  3151.  
  3152.                     if((i and 7)<>7) and (color[i-7]=DARK) then
  3153.                         gen_push(i,i-7,17);
  3154.                     if(color[i-8]=EMPTY) then
  3155.                     begin
  3156.                         gen_push(i,i-8,16);
  3157.                         if(i>=48)and(color[i-16]=EMPTY) then
  3158.                             gen_push(i,i-16,24);
  3159.                     end;
  3160.                 end
  3161.                 else
  3162.                 begin
  3163.                     if((i and 7)<>0)and(color[i+7]=LIGHT) then
  3164.                         gen_push(i,i+7,17);
  3165.                     if((i and 7)<>7)and(color[i+9]=LIGHT) then
  3166.                         gen_push(i,i+9,17);
  3167.                     if(color[i+8]=EMPTY) then
  3168.                     begin
  3169.                         gen_push(i,i+8,16);
  3170.                         if(i<=15)and(color[i+16]=EMPTY) then
  3171.                             gen_push(i,i+16,24);
  3172.                     end;
  3173.                 end;
  3174.             end
  3175.             else
  3176.             begin
  3177.                 for j:=0 to offsets[piece[i]]-1 do
  3178.                 begin
  3179.                     n:=i;
  3180.                     for r:=1 to $FFFF do
  3181.                     begin
  3182.                         n:=mailbox[mailbox64[n]+offset[piece[i],j]];
  3183.                         if(n=-1) then  Break;
  3184.                         if(color[n]<>EMPTY) then
  3185.                         begin
  3186.                             if(color[n]=xside) then
  3187.                                 gen_push(i,n,1);
  3188.                             break;
  3189.                         end;
  3190.                         gen_push(i,n,0);
  3191.  
  3192.                         if (slide[piece[i]]=FALSE) then Break;
  3193.                     end;
  3194.                 end;
  3195.             end;
  3196.         end;
  3197.     end;
  3198.  
  3199.  
  3200.     // generate castle moves
  3201.     if(side=LIGHT) then
  3202.     begin
  3203.      if((castle and 1)<>0) then
  3204.             gen_push(60,62,2);
  3205.         if((castle and 2)<>0) then
  3206.             gen_push(60,58,2);
  3207.     end
  3208.     else
  3209.     begin
  3210.         if((castle and 4)<>0)then
  3211.             gen_push(4,6,2);
  3212.         if((castle and 8)<>0) then
  3213.             gen_push(4,2,2);
  3214.     end;
  3215.  
  3216.     // generate en passant moves
  3217.     if(ep<>-1) then
  3218.     begin
  3219.         if(side=LIGHT) then
  3220.         begin
  3221.             if((ep and 7)<>0) and(color[ep+7]=LIGHT)and(piece[ep+7]=PAWN)then
  3222.                 gen_push(ep+7,ep,21);
  3223.             if((ep and 7)<>7)and(color[ep+9]=LIGHT)and(piece[ep+9]=PAWN)then
  3224.                 gen_push(ep+9,ep,21);
  3225.         end
  3226.         else
  3227.         begin
  3228.             if((ep and 7)<>0)and(color[ep-9]=DARK)and(piece[ep-9]=PAWN)then
  3229.                 gen_push(ep-9,ep,21);
  3230.             if((ep and 7)<>7)and(color[ep-7]=DARK)and(piece[ep-7]=PAWN)then
  3231.                 gen_push(ep-7,ep,21);
  3232.         end;
  3233.     end;
  3234.  
  3235.     // the next ply's moves need to start where the current
  3236.     // ply's end
  3237.     gen_begin[ply+1]:=gen_end[ply];
  3238. end;
  3239.  
  3240.  
  3241. // gen_caps() is basically a copy of gen() that's modified to
  3242. // only generate capture and promote moves. It's used by the
  3243. // quiescence search.
  3244. procedure TChessThread.gen_caps;
  3245. var
  3246.     r,i,j,n: Integer;
  3247. begin
  3248.     gen_end[ply]:=gen_begin[ply];
  3249.     for i:=0 to 63 do
  3250.     begin
  3251.         if(color[i]=side) then
  3252.         begin
  3253.             if(piece[i]=PAWN) then
  3254.             begin
  3255.                 if(side=LIGHT) then
  3256.                 begin
  3257.                     if((i and 7)<>0)and(color[i-9]=DARK)then
  3258.                         gen_push(i,i-9,17);
  3259.                     if((i and 7)<>7)and(color[i-7]=DARK)then
  3260.                         gen_push(i,i-7,17);
  3261.                     if(i<=15)and(color[i-8]=EMPTY)then
  3262.                         gen_push(i,i-8,16);
  3263.                 end;
  3264.                 if(side=DARK) then
  3265.                 begin
  3266.                     if((i and 7)<>0)and(color[i+7]=LIGHT)then
  3267.                         gen_push(i,i+7,17);
  3268.                     if((i and 7)<>7)and(color[i+9]=LIGHT)then
  3269.                         gen_push(i,i+9,17);
  3270.                     if(i>=48)and(color[i+8]=EMPTY)then
  3271.                         gen_push(i,i+8,16);
  3272.                 end;
  3273.             end
  3274.             else
  3275.                 for j:=0 to offsets[piece[i]]-1 do
  3276.                 begin
  3277.                     n:=i;
  3278.                     for r:=1 to $FFFF do
  3279.                     begin
  3280.                         n:=mailbox[mailbox64[n]+offset[piece[i],j]];
  3281.                         if(n=-1) then Break;
  3282.                         if(color[n]<>EMPTY) then
  3283.                         begin
  3284.                             if(color[n]=xside)then
  3285.                                 gen_push(i,n,1);
  3286.                             break;
  3287.                         end;
  3288.                         if (slide[piece[i]]=FALSE) then Break;
  3289.                     end;
  3290.                 end;
  3291.         end;
  3292.     end;
  3293.  
  3294.     if(ep<>-1) then
  3295.     begin
  3296.         if(side=LIGHT) then
  3297.         begin
  3298.             if((ep and 7)<>0)and(color[ep+7]=LIGHT)and(piece[ep+7]=PAWN)then
  3299.                 gen_push(ep+7,ep,21);
  3300.             if((ep and 7)<>7)and(color[ep+9]=LIGHT)and(piece[ep+9]=PAWN)then
  3301.                 gen_push(ep+9,ep,21);
  3302.         end
  3303.         else
  3304.         begin
  3305.             if((ep and 7)<>0)and(color[ep-9]=DARK)and(piece[ep-9]=PAWN)then
  3306.                 gen_push(ep-9,ep,21);
  3307.             if((ep and 7)<>7)and(color[ep-7]=DARK)and(piece[ep-7]=PAWN)then
  3308.                 gen_push(ep-7,ep,21);
  3309.         end;
  3310.     end;
  3311.     gen_begin[ply+1]:=gen_end[ply];
  3312. end;
  3313.  
  3314.  
  3315. // gen_push() puts a move on the move stack, unless it's a
  3316. // pawn promotion that needs to be handled by gen_promote().
  3317. // It also assigns a score to the move for alpha-beta move
  3318. // ordering. If the move is a capture, it uses MVV/LVA
  3319. // (Most Valuable Victim/Least Valuable Attacker). Otherwise,
  3320. // it uses the move's history heuristic value. Note that
  3321. // 1,000,000 is added to a capture move's score, so it
  3322. // always gets ordered above a "normal" move.
  3323.  
  3324. procedure TChessThread.gen_push(src,dst,bits: Integer);
  3325. var
  3326.     g: pGenRec;
  3327. begin
  3328.     if((bits and 16)<>0) then
  3329.     begin
  3330.         if(side=LIGHT) then
  3331.         begin
  3332.             if(dst<=8) then
  3333.             begin
  3334.                 gen_promote(src,dst,bits);
  3335.                 Exit;
  3336.             end;
  3337.         end
  3338.         else
  3339.         begin
  3340.             if(dst>=56) then
  3341.             begin
  3342.                 gen_promote(src,dst,bits);
  3343.                 Exit;
  3344.             end;
  3345.         end;
  3346.     end;
  3347.  
  3348.     g:=@gen_dat[gen_end[ply]];
  3349.     gen_end[ply]:=gen_end[ply]+1;
  3350.     g^.m.b.src:=src;
  3351.     g^.m.b.dst:=dst;
  3352.     g^.m.b.promote:=0;
  3353.     g^.m.b.bits:=bits;
  3354.     if((bits and 1)<>0) then
  3355.         g^.score:=1000000+(piece[dst]*10)-piece[src]
  3356.     else
  3357.         g^.score:=history[src,dst];
  3358. end;
  3359.  
  3360.  
  3361. // gen_promote() is just like gen_push(), only it puts 4 moves
  3362. // on the move stack, one for each possible promotion piece
  3363. procedure TChessThread.gen_promote(src,dst,bits: Integer);
  3364. var
  3365.     i: Integer;
  3366.     g: pGenRec;
  3367. begin
  3368.     for i:=KNIGHT to QUEEN do
  3369.     begin
  3370.         g:=@gen_dat[gen_end[ply]];
  3371.         gen_end[ply]:=gen_end[ply]+1;
  3372.         g^.m.b.src:=src;
  3373.         g^.m.b.dst:=dst;
  3374.         g^.m.b.promote:=i;
  3375.         g^.m.b.bits:=(bits or 32);
  3376.         g^.score:=1000000+(i*10);
  3377.     end;
  3378. end;
  3379.  
  3380.  
  3381. // makemove() makes a move. If the move is illegal, it
  3382. // undoes whatever it did and returns FALSE. Otherwise, it
  3383. // returns TRUE.
  3384. function TChessThread.makemove(m: move_bytes): Boolean;
  3385. begin
  3386.  
  3387.     // test to see if a castle move is legal and move the rook
  3388.     // (the king is moved with the usual move code later)
  3389.  
  3390.     if((m.bits and 2)<>0) then
  3391.     begin
  3392.         if(in_check(side)) then
  3393.         begin
  3394.             Result:=FALSE;
  3395.             Exit;
  3396.         end;
  3397.         case (m.dst) of
  3398.             62: begin;
  3399.                     if(color[61]<>EMPTY)or(color[62]<>EMPTY)or
  3400.                       (attack(61,xside))or(attack(62,xside)) then
  3401.                     begin
  3402.                         Result:=FALSE;
  3403.                         Exit;
  3404.                     end;
  3405.                     color[61]:=LIGHT;
  3406.                     piece[61]:=ROOK;
  3407.                     color[63]:=EMPTY;
  3408.                     piece[63]:=EMPTY;
  3409.                 end;
  3410.             58: begin
  3411.                     if(color[57]<>EMPTY)or(color[58]<>EMPTY)or(color[59]<>EMPTY)or
  3412.                         (attack(58,xside))or(attack(59,xside)) then
  3413.                     begin
  3414.                         Result:=FALSE;
  3415.                         Exit;
  3416.                     end;
  3417.                     color[59]:=LIGHT;
  3418.                     piece[59]:=ROOK;
  3419.                     color[56]:=EMPTY;
  3420.                     piece[56]:=EMPTY;
  3421.                 end;
  3422.             6:  begin
  3423.                     if(color[5]<>EMPTY)or(color[6]<>EMPTY)or
  3424.                       (attack(5,xside))or(attack(6,xside)) then
  3425.                     begin
  3426.                         Result:=FALSE;
  3427.                         Exit;
  3428.                     end;
  3429.                     color[5]:=DARK;
  3430.                     piece[5]:=ROOK;
  3431.                     color[7]:=EMPTY;
  3432.                     piece[7]:=EMPTY;
  3433.                 end;
  3434.             2:  begin
  3435.                 if(color[1]<>EMPTY)or(color[2]<>EMPTY)or(color[3]<>EMPTY)or
  3436.                         attack(2,xside)or attack(3,xside) then
  3437.                 begin
  3438.                     Result:=FALSE;
  3439.                     Exit;
  3440.                 end;
  3441.                 color[3]:=DARK;
  3442.                 piece[3]:=ROOK;
  3443.                 color[0]:=EMPTY;
  3444.                 piece[0]:=EMPTY;
  3445.                 end;
  3446.         end;
  3447.     end;
  3448.  
  3449.     // back up information so we can take the move back later.
  3450.     hist_dat[ply].m.b:=m;
  3451.     hist_dat[ply].capture:=piece[m.dst];
  3452.     hist_dat[ply].castle:=castle;
  3453.     hist_dat[ply].ep:=ep;
  3454.     hist_dat[ply].fifty:=fifty;
  3455.     ply:=ply+1;
  3456.  
  3457.     // update the castle, en passant, and
  3458.     // fifty-move-draw variables
  3459.     castle:=castle and (castle_mask[m.src] and castle_mask[m.dst]);
  3460.     if((m.bits and 8)<>0) then
  3461.     begin
  3462.         if(side=LIGHT) then
  3463.             ep:=m.dst+8
  3464.         else
  3465.             ep:=m.dst-8;
  3466.     end
  3467.     else
  3468.         ep:=-1;
  3469.     if((m.bits and 17)<>0) then
  3470.         fifty:=0
  3471.     else
  3472.         fifty:=fifty+1;
  3473.  
  3474.     // move the piece
  3475.     color[m.dst]:=side;
  3476.     if((m.bits and 32)<>0) then
  3477.         piece[m.dst]:=m.promote
  3478.     else
  3479.         piece[m.dst]:=piece[m.src];
  3480.     color[m.src]:=EMPTY;
  3481.     piece[m.src]:=EMPTY;
  3482.  
  3483.     // erase the pawn if this is an en passant move
  3484.     if((m.bits and 4)<>0) then
  3485.     begin
  3486.         if(side=LIGHT) then
  3487.         begin
  3488.             color[m.dst+8]:=EMPTY;
  3489.             piece[m.dst+8]:=EMPTY;
  3490.         end
  3491.         else
  3492.         begin
  3493.             color[m.dst-8]:=EMPTY;
  3494.             piece[m.dst-8]:=EMPTY;
  3495.         end;
  3496.     end;
  3497.  
  3498.     // switch sides and test for legality (if we can capture
  3499.     // the other guy's king, it's an illegal position and
  3500.     // we need to take the move back)
  3501.     side:=side xor 1;
  3502.     xside:=xside xor 1;
  3503.     if(in_check(xside)) then
  3504.     begin
  3505.         takeback();
  3506.         Result:=FALSE;
  3507.         Exit;
  3508.     end;
  3509.     Result:=TRUE;
  3510. end;
  3511.  
  3512.  
  3513. // takeback() is very similar to makemove(), only backwards :)
  3514. procedure TChessThread.takeback;
  3515. var
  3516.     m: move_bytes;
  3517.     src,dst: Integer;
  3518. begin
  3519.     src:=0;
  3520.     dst:=0;
  3521.     side:=side xor 1;
  3522.     xside:=xside xor 1;
  3523.     ply:=ply-1;
  3524.     m:=hist_dat[ply].m.b;
  3525.     castle:=hist_dat[ply].castle;
  3526.     ep:=hist_dat[ply].ep;
  3527.     fifty:=hist_dat[ply].fifty;
  3528.     color[m.src]:=side;
  3529.     if((m.bits and 32)<>0) then
  3530.         piece[m.src]:=PAWN
  3531.     else
  3532.         piece[m.src]:=piece[m.dst];
  3533.     if(hist_dat[ply].capture=EMPTY) then
  3534.     begin
  3535.         color[m.dst]:=EMPTY;
  3536.         piece[m.dst]:=EMPTY;
  3537.     end
  3538.     else
  3539.     begin
  3540.         color[m.dst]:=xside;
  3541.         piece[m.dst]:=hist_dat[ply].capture;
  3542.     end;
  3543.     if((m.bits and 2)<>0) then
  3544.     begin
  3545.         case(m.dst) of
  3546.             62: begin src:=61; dst:=63; end;
  3547.             58: begin src:=59; dst:=56; end;
  3548.             6:  begin src:=5;  dst:=7; end;
  3549.             2:  begin src:=3;  dst:=0; end;
  3550.         end;
  3551.         color[dst]:=side;
  3552.         piece[dst]:=ROOK;
  3553.         color[src]:=EMPTY;
  3554.         piece[src]:=EMPTY;
  3555.     end;
  3556.     if((m.bits and 4)<>0) then
  3557.     begin
  3558.         if(side=LIGHT) then
  3559.         begin
  3560.             color[m.dst+8]:=xside;
  3561.             piece[m.dst+8]:=PAWN;
  3562.         end
  3563.         else
  3564.         begin
  3565.             color[m.dst-8]:=xside;
  3566.             piece[m.dst-8]:=PAWN;
  3567.         end;
  3568.     end;
  3569. end;
  3570.  
  3571.  
  3572. function TChessThread.eval: Integer;
  3573. var
  3574.     x,y,i,c,xc,f: Integer;
  3575.     score: Array[0..1]of Integer; //score for each side
  3576.     pawns: Array[0..1,0..9] of Integer; // the number of pawns of each color on each file
  3577. begin
  3578.     score[DARK]:=0;
  3579.     score[LIGHT]:=0;
  3580.  
  3581.     //memset(pawns,0,sizeof(pawns));
  3582.  
  3583.     for x:=0 to 1 do
  3584.     for y:=0 to 9 do
  3585.         pawns[x,y]:=0;
  3586.  
  3587.     // loop through to set up the pawns array and to add up the
  3588.     // piece/square table values for each piece.
  3589.     for i:=0 to 63 do
  3590.     begin
  3591.         if(color[i]=EMPTY) then continue;
  3592.         if(piece[i]=PAWN) then
  3593.             pawns[color[i],(i and 7)+1]:=
  3594.             pawns[color[i],(i and 7)+1]+1;
  3595.         score[color[i]]:=score[color[i]]+pcsq[color[i],piece[i],i];
  3596.     end;
  3597.  
  3598.     // now that we have the pawns array set up, evaluate the pawns and rooks
  3599.     for i:=0 to 63 do
  3600.     begin
  3601.         if(color[i]=EMPTY) then continue;
  3602.         c:=color[i];  // set up c, xc, and f so we don't have to type a lot
  3603.         xc:=c xor 1;
  3604.         f:=(i and 7)+1;
  3605.         if(piece[i]=PAWN) then
  3606.         begin
  3607.             if(pawns[c,f]>1) then  // this pawn is doubled
  3608.                 score[c]:=score[c]-5;
  3609.             if(pawns[c,f-1]=0)and(pawns[c,f+1]=0)then
  3610.             begin                  // isolated
  3611.                 score[c]:=score[c]-20;
  3612.                 if(pawns[xc,f]=0) then
  3613.                     score[c]:=score[c]-10;
  3614.             end;
  3615.             if(pawns[xc,f-1]=0)and  // passed
  3616.                     (pawns[xc,f]=0)and(pawns[xc,f+1]=0) then
  3617.                 score[c]:=score[c]+2*pcsq[c,PAWN,i];
  3618.         end;
  3619.         if(piece[i]=ROOK) then
  3620.         begin
  3621.             if(pawns[c,f]=0) then
  3622.             begin  // the rook is on a half-open file
  3623.                 score[c]:=score[c]+10;
  3624.                 if(pawns[xc,f]=0) then // actually, it's totally open
  3625.                     score[c]:=score[c]+5;
  3626.             end;
  3627.         end;
  3628.     end;
  3629.  
  3630.     // return the score relative to the side to move (i.e.,
  3631.     // a positive score means the side to move is winning)
  3632.     if(side=LIGHT) then
  3633.     begin
  3634.         Result:=(score[LIGHT]-score[DARK]);
  3635.     end
  3636.     else Result:=(score[DARK]-score[LIGHT]);
  3637. end;
  3638.  
  3639. procedure TChessThread.init_eval;
  3640. var
  3641.     x,y,z,i,material,king_sq: Integer;
  3642. begin
  3643.     king_sq:=0;
  3644.  
  3645.     for x:=0 to 1 do
  3646.     for y:=0 to 5 do
  3647.     for z:=0 to 63 do
  3648.         pcsq[x,y,z]:=0;
  3649.  
  3650.  
  3651.     // initialize the no-brainer piece/square tables
  3652.     for i:=0 to 63 do
  3653.     begin
  3654.         pcsq[LIGHT,BISHOP,i]:=value[BISHOP]+minor_pcsq[i];
  3655.         pcsq[LIGHT,KNIGHT,i]:=value[KNIGHT]+minor_pcsq[i];
  3656.         pcsq[LIGHT,PAWN,i]  :=value[PAWN]+pawn_pcsq[i];
  3657.         pcsq[LIGHT,QUEEN,i] :=value[QUEEN];
  3658.         pcsq[LIGHT,ROOK,i]  :=value[ROOK];
  3659.         pcsq[DARK,BISHOP,i] :=value[BISHOP]+minor_pcsq[flip[i]];
  3660.         pcsq[DARK,KNIGHT,i] :=value[KNIGHT]+minor_pcsq[flip[i]];
  3661.         pcsq[DARK,PAWN,i]   :=value[PAWN]+pawn_pcsq[flip[i]];
  3662.         pcsq[DARK,QUEEN,i]  :=value[QUEEN];
  3663.         pcsq[DARK,ROOK,i]   :=value[ROOK];
  3664.     end;
  3665.  
  3666.     // now scan the board to see how much piece material the
  3667.     //   enemy has and figure out what side of the board the
  3668.     //   king is on
  3669.     material:=0;
  3670.     for i:=0 to 63 do
  3671.     begin
  3672.         if(color[i]=DARK)and(piece[i]<>PAWN)then
  3673.             material:=material+value[piece[i]];
  3674.         if(color[i]=LIGHT)and(piece[i]=KING)then
  3675.             king_sq:=i;
  3676.     end;
  3677.     if(material>1400)then
  3678.      begin  // use the middlegame tables
  3679.         for i:=0 to 63 do
  3680.             pcsq[LIGHT,KING,i]:=king_pcsq[i];
  3681.         if((king_sq and 7)>=5) then
  3682.             for i:=0 to 63 do
  3683.                 pcsq[LIGHT,PAWN,i]:=
  3684.                 pcsq[LIGHT,PAWN,i]+kingside_pawn_pcsq[i];
  3685.         if((king_sq and 7)<=2) then
  3686.             for i:=0 to 63 do
  3687.                 pcsq[LIGHT,PAWN,i]:=
  3688.                 pcsq[LIGHT,PAWN,i]+queenside_pawn_pcsq[i];
  3689.     end
  3690.     else
  3691.         for i:=0 to 63 do
  3692.             pcsq[LIGHT,KING,i]:=endgame_king_pcsq[i];
  3693.  
  3694.     // do the same for black
  3695.     material:=0;
  3696.     for i:=0 to 63 do
  3697.     begin
  3698.         if(color[i]=LIGHT)and(piece[i]<>PAWN)then
  3699.             material:=material+value[piece[i]];
  3700.         if(color[i]=DARK)and(piece[i]=KING)then
  3701.             king_sq:=i;
  3702.     end;
  3703.     if(material>1400) then
  3704.     begin
  3705.         for i:=0 to 63 do
  3706.             pcsq[DARK,KING,i]:=king_pcsq[flip[i]];
  3707.         if((king_sq and 7)>=5) then
  3708.             for i:=0 to 63 do
  3709.                 pcsq[DARK,PAWN,i]:=
  3710.                 pcsq[DARK,PAWN,i]+kingside_pawn_pcsq[flip[i]];
  3711.         if((king_sq and 7)<=2) then
  3712.             for i:=0 to 63 do
  3713.                 pcsq[DARK,PAWN,i]:=
  3714.                 pcsq[DARK,PAWN,i]+queenside_pawn_pcsq[flip[i]];
  3715.     end
  3716.     else
  3717.         for i:=0 to 63 do
  3718.             pcsq[DARK,KING,i]:=endgame_king_pcsq[flip[i]];
  3719. end;
  3720.  
  3721. procedure TChessThread.InitValues;
  3722. const
  3723.     _flip: Array[0..63] of Integer=(
  3724.               56,  57,  58,  59,  60,  61,  62,  63,
  3725.               48,  49,  50,  51,  52,  53,  54,  55,
  3726.               40,  41,  42,  43,  44,  45,  46,  47,
  3727.               32,  33,  34,  35,  36,  37,  38,  39,
  3728.               24,  25,  26,  27,  28,  29,  30,  31,
  3729.               16,  17,  18,  19,  20,  21,  22,  23,
  3730.                8,   9,  10,  11,  12,  13,  14,  15,
  3731.                0,   1,   2,   3,   4,   5,   6,   7);
  3732.  
  3733.     _pawn_pcsq: Array[0..63] of Integer=(
  3734.               0,   0,   0,   0,   0,   0,   0,   0,
  3735.               5,  10,  15,  20,  20,  15,  10,   5,
  3736.               4,   8,  12,  16,  16,  12,   8,   4,
  3737.               3,   6,   9,  12,  12,   9,   6,   3,
  3738.               2,   4,   6,   8,   8,   6,   4,   2,
  3739.               1,   2,   3,   4,   4,   3,   2,   1,
  3740.               0,   0,   0, -20, -20,   0,   0,   0,
  3741.               0,   0,   0,   0,   0,   0,   0,   0);
  3742.  
  3743.     _kingside_pawn_pcsq: Array[0..63] of Integer=(
  3744.               0,   0,   0,   0,   0,   0,   0,   0,
  3745.               0,   0,   0,   0,   0,   0,   0,   0,
  3746.               0,   0,   0,   0,   0,   0,   0,   0,
  3747.               0,   0,   0,   0,   0,   0,   0,   0,
  3748.               0,   0,   0,   0,   0,   5,   5,   5,
  3749.               0,   0,   0,   0,   0,  10,  10,  10,
  3750.               0,   0,   0,   0,   0,  20,  20,  20,
  3751.               0,   0,   0,   0,   0,   0,   0,   0);
  3752.  
  3753.     _queenside_pawn_pcsq: Array[0..63] of Integer=(
  3754.               0,   0,   0,   0,   0,   0,   0,   0,
  3755.               0,   0,   0,   0,   0,   0,   0,   0,
  3756.               0,   0,   0,   0,   0,   0,   0,   0,
  3757.               0,   0,   0,   0,   0,   0,   0,   0,
  3758.               5,   5,   5,   0,   0,   0,   0,   0,
  3759.              10,  10,  10,   0,   0,   0,   0,   0,
  3760.              20,  20,  20,   0,   0,   0,   0,   0,
  3761.               0,   0,   0,   0,   0,   0,   0,   0);
  3762.    _minor_pcsq: Array[0..63] of Integer=(
  3763.             -10, -10, -10, -10, -10, -10, -10, -10,
  3764.             -10,   0,   0,   0,   0,   0,   0, -10,
  3765.             -10,   0,   5,   5,   5,   5,   0, -10,
  3766.             -10,   0,   5,  10,  10,   5,   0, -10,
  3767.             -10,   0,   5,  10,  10,   5,   0, -10,
  3768.             -10,   0,   5,   5,   5,   5,   0, -10,
  3769.             -10,   0,   0,   0,   0,   0,   0, -10,
  3770.             -20, -20, -20, -20, -20, -20, -20, -20);
  3771.    _king_pcsq: Array[0..63] of Integer=(
  3772.             -40, -40, -40, -40, -40, -40, -40, -40,
  3773.             -40, -40, -40, -40, -40, -40, -40, -40,
  3774.             -40, -40, -40, -40, -40, -40, -40, -40,
  3775.             -40, -40, -40, -40, -40, -40, -40, -40,
  3776.             -40, -40, -40, -40, -40, -40, -40, -40,
  3777.             -40, -40, -40, -40, -40, -40, -40, -40,
  3778.             -20, -20, -20, -20, -20, -20, -20, -20,
  3779.             -10,   0,  10, -20,   0, -20,  10,   0);
  3780.  
  3781.     _endgame_king_pcsq: Array[0..63] of Integer=(
  3782.              -5,  -5,  -5,  -5,  -5,  -5,  -5,  -5,
  3783.              -5,   0,   0,   0,   0,   0,   0,  -5,
  3784.              -5,   0,   5,   5,   5,   5,   0,  -5,
  3785.              -5,   0,   5,  10,  10,   5,   0,  -5,
  3786.              -5,   0,   5,  10,  10,   5,   0,  -5,
  3787.              -5,   0,   5,   5,   5,   5,   0,  -5,
  3788.              -5,   0,   0,   0,   0,   0,   0,  -5,
  3789.              -5,  -5,  -5,  -5,  -5,  -5,  -5,  -5);
  3790.  
  3791.     _mailbox: Array[0..119] of Integer=(
  3792.              -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  3793.              -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  3794.              -1,  0,  1,  2,  3,  4,  5,  6,  7, -1,
  3795.              -1,  8,  9, 10, 11, 12, 13, 14, 15, -1,
  3796.              -1, 16, 17, 18, 19, 20, 21, 22, 23, -1,
  3797.              -1, 24, 25, 26, 27, 28, 29, 30, 31, -1,
  3798.              -1, 32, 33, 34, 35, 36, 37, 38, 39, -1,
  3799.              -1, 40, 41, 42, 43, 44, 45, 46, 47, -1,
  3800.              -1, 48, 49, 50, 51, 52, 53, 54, 55, -1,
  3801.              -1, 56, 57, 58, 59, 60, 61, 62, 63, -1,
  3802.              -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  3803.              -1, -1, -1, -1, -1, -1, -1, -1, -1, -1);
  3804.  
  3805.    _mailbox64: Array[0..63] of Integer=(
  3806.              21, 22, 23, 24, 25, 26, 27, 28,
  3807.              31, 32, 33, 34, 35, 36, 37, 38,
  3808.              41, 42, 43, 44, 45, 46, 47, 48,
  3809.              51, 52, 53, 54, 55, 56, 57, 58,
  3810.              61, 62, 63, 64, 65, 66, 67, 68,
  3811.              71, 72, 73, 74, 75, 76, 77, 78,
  3812.              81, 82, 83, 84, 85, 86, 87, 88,
  3813.              91, 92, 93, 94, 95, 96, 97, 98);
  3814.  
  3815.     _offsets: Array[0..5] of Integer=(0, 8, 4, 4, 8, 8);
  3816.  
  3817.     _offset: Array[0..5,0..7] of Integer=(
  3818.              (0, 0, 0, 0, 0, 0, 0, 0),
  3819.              (-21, -19, -12, -8, 8, 12, 19, 21),
  3820.              (-11, -9, 9, 11, 0, 0, 0, 0),
  3821.              (-10, -1, 1, 10, 0, 0, 0, 0),
  3822.              (-11, -10, -9, -1, 1, 9, 10, 11),
  3823.              (-11, -10, -9, -1, 1, 9, 10, 11));
  3824.  
  3825.     _castle_mask: Array[0..63] of Integer=(
  3826.              7, 15, 15, 15,  3, 15, 15, 11,
  3827.             15, 15, 15, 15, 15, 15, 15, 15,
  3828.             15, 15, 15, 15, 15, 15, 15, 15,
  3829.             15, 15, 15, 15, 15, 15, 15, 15,
  3830.             15, 15, 15, 15, 15, 15, 15, 15,
  3831.             15, 15, 15, 15, 15, 15, 15, 15,
  3832.             15, 15, 15, 15, 15, 15, 15, 15,
  3833.             13, 15, 15, 15, 12, 15, 15, 14);
  3834.  
  3835.     _value: Array[0..5] of Integer=(100, 300, 300, 500, 900, 10000);
  3836.  
  3837.     _init_color: Array[0..63] of Integer=(
  3838.             1, 1, 1, 1, 1, 1, 1, 1,
  3839.             1, 1, 1, 1, 1, 1, 1, 1,
  3840.             6, 6, 6, 6, 6, 6, 6, 6,
  3841.             6, 6, 6, 6, 6, 6, 6, 6,
  3842.             6, 6, 6, 6, 6, 6, 6, 6,
  3843.             6, 6, 6, 6, 6, 6, 6, 6,
  3844.             0, 0, 0, 0, 0, 0, 0, 0,
  3845.             0, 0, 0, 0, 0, 0, 0, 0);
  3846.  
  3847.     _init_piece: Array[0..63] of Integer=(
  3848.             3, 1, 2, 4, 5, 2, 1, 3,
  3849.             0, 0, 0, 0, 0, 0, 0, 0,
  3850.             6, 6, 6, 6, 6, 6, 6, 6,
  3851.             6, 6, 6, 6, 6, 6, 6, 6,
  3852.             6, 6, 6, 6, 6, 6, 6, 6,
  3853.             6, 6, 6, 6, 6, 6, 6, 6,
  3854.             0, 0, 0, 0, 0, 0, 0, 0,
  3855.             3, 1, 2, 4, 5, 2, 1, 3);
  3856. begin
  3857.  
  3858.     IntCopy (@flip[0],@_flip[0],64);
  3859.     IntCopy (@pawn_pcsq[0],@_pawn_pcsq[0],64);
  3860.     IntCopy (@kingside_pawn_pcsq[0],@_kingside_pawn_pcsq[0],64);
  3861.     IntCopy (@queenside_pawn_pcsq[0],@_queenside_pawn_pcsq[0],64);
  3862.     IntCopy (@minor_pcsq[0],@_minor_pcsq[0],64);
  3863.     IntCopy (@king_pcsq[0],@_king_pcsq[0],64);
  3864.     IntCopy (@endgame_king_pcsq[0],@_endgame_king_pcsq[0],64);
  3865.     IntCopy (@mailbox[0],@_mailbox[0],120);
  3866.     IntCopy (@mailbox64[0],@_mailbox64[0],64);
  3867.  
  3868.     slide[0]:=FALSE;
  3869.     slide[1]:=FALSE;
  3870.     slide[2]:=TRUE;
  3871.     slide[3]:=TRUE;
  3872.     slide[4]:=TRUE;
  3873.     slide[5]:=FALSE;
  3874.  
  3875.     IntCopy (@offsets[0],@_offsets[0],6);
  3876.     IntCopy (@offset[0,0],@_offset[0,0],48);
  3877.     IntCopy (@castle_mask[0],@_castle_mask[0],64);
  3878.     IntCopy (@value[0],@_value[0],6);
  3879.  
  3880.     piece_char[0]:='P';
  3881.     piece_char[1]:='N';
  3882.     piece_char[2]:='B';
  3883.     piece_char[3]:='R';
  3884.     piece_char[4]:='Q';
  3885.     piece_char[5]:='K';
  3886.  
  3887.     IntCopy (@init_color[0],@_init_color[0],64);
  3888.     IntCopy (@init_piece[0],@_init_piece[0],64);
  3889.  
  3890. end;
  3891.  
  3892. end.
  3893.  
  3894.