home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 9 / 09.iso / l / l040 / 10.ddi / CHESS.ZIP / LEVAL.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1992-10-27  |  48.1 KB  |  1,508 lines

  1. {************************************************}
  2. {                                                }
  3. {   Chess - Shared DLL Example                   }
  4. {   CHESS.DLL Primary search engine.             }
  5. {   Copyright (c) 1992 by Borland International  }
  6. {                                                }
  7. {************************************************}
  8.  
  9. unit LEval;
  10.  
  11. {$R-,Q-,S-,W-}
  12.  
  13. interface
  14.  
  15. function FindMove(MaxLevel: integer): integer;
  16. procedure InitPawnStrTables;
  17.  
  18. implementation
  19.  
  20. uses Strings, GameRec, LBoard, LMovegen, LMoves, LTimer, TaskMgr, GameTask;
  21.  
  22. type
  23.   { File numbers }
  24.   FileType = 0..7;
  25.   { Rank numbers }
  26.   RankType = 0..7;
  27.  
  28. { Evaluation parameters }
  29. const
  30.  
  31.   { Value of Pieces used in Evaluation }
  32.   PieceValue: array[Empty..Pawn] of integer =
  33.     (0, $1000, $900, $4C0, $300, $300, $100);
  34.  
  35.   { Tolerance Width }
  36.   Tolerance = 8;
  37.  
  38.   { Used to calculate distance to center }
  39.   DistAn: array[0..7] of Integer = (3,2,1,0,0,1,2,3);
  40.  
  41.   { The Value of a Pawn is the sum of Rank and file values.
  42.     The file Value is equal to PawnFileFactor * (Rank Number + 2) }
  43.   PawnRank: array [RankType] of Integer = (0,0, 0, 2, 4, 8,30,0);
  44.   PassPawnRank: array [RankType] of Integer = (0,0,10,20,40,60,70,0);
  45.   PawnFileFactor:  array [FileType] of Integer = (0,0,2,5,6,2,0,0);
  46.  
  47.   { Value of castling (Long..Short) }
  48.   CastValue:      array[CastDirType] of Integer = (4,32);
  49.  
  50.   { Value of exchanging Pieces (not pawns) when ahead }
  51.   ExchangeValue = 32;
  52.  
  53.   { Pawnstructure values }
  54.   IsolatedPawn  = 20;   { Isolated Pawn. Double isolated Pawn is 3 * 20 }
  55.   DoublePawn    =  8;   { Double Pawn }
  56.   SidePawn      =  6;   { Having a Pawn On the side }
  57.   ChainPawn     =  3;   { Being covered by a Pawn }
  58.   CoverPawn     =  3;   { Covering a Pawn }
  59.   NotMovePawn   =  3;   { Penalty for moving Pawn }
  60.  
  61.   { Penalty for Bishop blocking d2/e2 Pawn }
  62.   BishopBlockValue   = 20;
  63.  
  64.   { Bonus for Rook behind passed Pawn }
  65.   RookBehindPassPawn = 16;
  66.  
  67.   { Values for calculating importance of each Square (AttVal) }
  68.   SquareRankValue: array [RankType] of byte = (0,0,0,0,1,2,4,4);
  69.  
  70. { Pawnstructure table.
  71.   One and Dob are SETs of FILEs, and contains
  72.   the FILEs which has One respectively more pawns.
  73.   The table is updated and evaluated at each Ply in the Search.
  74.   FileBitTab is used to lookup a file in a set of FILEs }
  75. type
  76.   SetofFile   = byte;
  77.   PawnBitRec  = record
  78.                   One,Dob: SetofFile;
  79.                  end;
  80.   PawnBitType = array [ColorType] of PawnBitRec;
  81.  
  82. const
  83.   FileBitTab: array [FileType] of SetofFile = (1,2,4,8,$10,$20,$40,$80);
  84.  
  85.  
  86. { Calculates the Value of the Piece On the Square }
  87. function PiecePosVal(Piece:  PieceType; Color:  ColorType;
  88.   Square: SquareType): Integer;
  89. begin
  90.    PiecePosVal := PieceValue[Piece] + CC.PVTable[Color,Piece,Square];
  91. end;
  92.  
  93. { Pawn strength tables }
  94.  
  95. var
  96.   PawnStrDob: array[0..255] of Byte;
  97.   PawnStrIso: array[0..255] of Byte;
  98.  
  99. { Initialize the pawn strength tables }
  100. procedure InitPawnStrTables;
  101. var
  102.   I: Integer;
  103.  
  104.    function BitCount(B: SetOFFile): Integer; assembler;
  105.    asm
  106.     XOR    AX,AX
  107.     MOV    DL,B
  108.     MOV    CX,8
  109.     CLC
  110. @@1:    SHR    DL,1
  111.     JNC    @@2
  112.     INC    AX
  113. @@2:    JZ    @@3
  114.     LOOP    @@1
  115. @@3:
  116.    end;
  117.  
  118. begin
  119.   for I := 0 to 255 do
  120.   begin
  121.     PawnStrDob[I] := BitCount(I) * DoublePawn;
  122.     PawnStrIso[I] := BitCount(I) * IsolatedPawn;
  123.   end;
  124. end;
  125.  
  126. { Calculate the pawn strength from the pawn strength tables }
  127. function PawnStrVal(var PB: PawnBitRec): Integer; near; assembler;
  128. asm
  129.     XOR    AX,AX
  130.     LES    DI,PB
  131.         MOV    AL,ES:[DI].PawnBitRec.One
  132.     MOV    CX,AX
  133.         MOV    BX,AX
  134.     SHR    CX,1
  135.         SHL    BX,1
  136.         OR    CX,BX
  137.         NOT    CX
  138.         MOV    BX,AX
  139.         AND    BX,CX
  140.         MOV    AL,ES:[DI].PawnBitRec.Dob
  141.         MOV    SI,AX
  142.         MOV    AL,BYTE PTR PawnStrDob[SI]
  143.         ADD    AL,BYTE PTR PawnStrIso[BX]
  144.         ADC    AH,0
  145.     AND    BL,ES:[DI].PawnBitRec.Dob
  146.         ADD    AL,BYTE PTR PawnStrIso[BX]
  147.         ADC    AH,0
  148.         ADD    AL,BYTE PTR PawnStrIso[BX]
  149.         ADC    AH,0
  150.         NEG    AX
  151. end;
  152.  
  153. { Finds a move in the position.
  154.   On exit :
  155.      MAINLINE contains principal variation.
  156.      MAINEVALU contains evaluation of the line
  157. }
  158. function FindMove(MaxLevel: Integer): Integer;
  159. var
  160.   { Value of root position in the Search }
  161.   RootValue: MaxType;
  162.  
  163.   { Total material and material advantage }
  164.   TotalMaterial,PawnTotalMaterial,Material: Integer;
  165.  
  166.   { Material Level of the game (early middlegame = 43 - 32, endgame = 0) }
  167.   MaterialLevel: 0..60;
  168.  
  169.   PawnBit: array[-1..MaxPly] of PawnBitType;
  170.  
  171.   Mating: Boolean;   { Mating Evaluation function is used }
  172.  
  173.   { Calculates Piece-Value table for the static Evaluation function }
  174.   procedure CalcPVTable;
  175.   type
  176.     { Pawn table, containing the squares with a Pawn }
  177.       PawnTabType = array[RankType] of SetofFile;
  178.  
  179.   var
  180.     PawnTab:      array[ColorType] of PawnTabType;
  181.  
  182.     { Bit tables for static Pawn structure Evaluation }
  183.     PawnFileTab, Bit,
  184.     OpPassTab, BehindOpPass,
  185.     LeftSideTab, RightSideTab ,SideTab,
  186.     LeftChainTab, RightChainTab,ChainTab,
  187.     LeftCoverTab, RightCoverTab: SetofFile;
  188.  
  189.     { Importance of an attack of the Square }
  190.     AttackValue:  array[ColorType,SquareType] of 0..120;
  191.  
  192.     { Value of squares controlled from the Square }
  193.     PVControl: array[ColorType,Rook..Bishop,SquareType] of 0..250;
  194.  
  195.     LosingColor: ColorType;   { The Color which is being mated }
  196.     PosVal: Integer;          { The positional Value of Piece }
  197.     AttVal: Integer;          { The attack Value of the sqaure }
  198.     Line: FileType;           { The file of the Piece }
  199.     Rank, Row: RankType;      { The Rank and Row of the Piece }
  200.     Dist,                     { Distance to center }
  201.     KingDist: 0..14;          { Distance to opponents King }
  202.     Cast: CastType;           { Possible castlings }
  203.     Direct: Boolean;          { Indicates Direct attack }
  204.     Cnt: Integer;             { Counter for attack values }
  205.     StrVal: Integer;          { Pawnstructure Value }
  206.     Color,
  207.     OppColor: ColorType;      { Color and opponents Color }
  208.     PieceCount: PieceType;    { Piece counter }
  209.     Square: SquareType;       { Square counter }
  210.     Dir: DirType;             { Direction counter }
  211.     Sq: EdgeSquareType;       { Square counter }
  212.     Temp,Temp2: Integer;      { Temporaries }
  213.     TempColor: ColorType;
  214.  
  215.   begin
  216.     { Calculate SAMMAT, PAWNSAMMAT and Material }
  217.     Mating := False;
  218.     TotalMaterial := 0;
  219.     PawnTotalMaterial := 0;
  220.     Material := 0;
  221.     with CC do
  222.     begin
  223.       for Square := 0 to $77 do
  224.         if (Square and $88) = 0 then
  225.           with Board[Square] do
  226.             if Piece <> Empty then
  227.               if Piece <> King then
  228.               begin
  229.                 Temp := PieceValue[Piece];
  230.                 TotalMaterial := TotalMaterial + Temp;
  231.                 if Piece = Pawn then
  232.                   PawnTotalMaterial := PawnTotalMaterial + PieceValue[Pawn];
  233.                 if Color = White then Temp := -Temp;
  234.                 Material := Material - Temp;
  235.               end;
  236.       MaterialLevel := Max(0,TotalMaterial - $2000) div $100;
  237.  
  238.       { set Mating if weakest Player has less that the equivalence of
  239.         two Bishops and the advantage is at least a Rook for a Bishop }
  240.       if Material < 0 then
  241.         LosingColor := White
  242.       else
  243.         LosingColor := Black;
  244.       Mating := ((TotalMaterial - abs(Material)) div 2 <=
  245.         PieceValue[Bishop] * 2) and (Abs(Material) >= PieceValue[Rook] -
  246.         PieceValue[Bishop]);
  247.  
  248.       { Calculate ATTACKVAL (importance of each Square) }
  249.       for Rank := 0 to 7 do
  250.         for Line := 0 to 7 do
  251.         begin
  252.           Square := Rank shl 4 + Line;
  253.  
  254.           { Center importance }
  255.           AttVal := Max(0,8 - 3 * (DistAn[Rank] + DistAn[Line]));
  256.  
  257.           { Rank importance }
  258.           for Color := White to Black do
  259.           begin
  260.             AttackValue[Color,Square] := SquareRankValue[Rank] * 3 *
  261.                                          (MaterialLevel + 8) shr 5 + AttVal;
  262.             Square := Square xor $70;
  263.           end;
  264.         end; { for }
  265.        for Color := White to Black do
  266.        begin
  267.          OppColor := ColorType(1 - ord(Color));
  268.          CalcCastling(OppColor,Cast);
  269.          if not (Short in Cast) and (MaterialLevel > 0) then
  270.             { Importance of the 8 squares around the Opponent's King }
  271.             with PieceTab[OppColor,0] do
  272.                for Dir := 0 to 7 do
  273.                begin
  274.                  Sq := ISquare + DirTab[Dir];
  275.                  if (Sq and $88) = 0 then
  276.                     AttackValue[Color,Sq] := AttackValue[Color,Sq] +
  277.                       12 * (MaterialLevel + 8) shr 5;
  278.                end;
  279.        end; { for }
  280.  
  281.        { Calculate PVControl }
  282.        for Square := $77 downto 0 do
  283.          if (Square and $88) = 0 then
  284.            for Color := White to Black do
  285.              for PieceCount := Rook to Bishop do
  286.                 PVControl[Color,PieceCount,Square] := 0;
  287.  
  288.        for Square := $77 downto 0 do
  289.          if (Square and $88) = 0 then
  290.            for Color := White to Black do
  291.            begin
  292.              for Dir := 7 downto 0 do
  293.              begin
  294.                if Dir < 4 then
  295.                   PieceCount := Rook
  296.                else
  297.                   PieceCount := Bishop;
  298.                { Count Value of all Attacks from the Square in
  299.                  the Direction.
  300.                  The Value of attacking a Square is Found in ATTACKVAL.
  301.                  Indirect Attacks (e.g. a Rook attacking through
  302.                  another Rook) counts for a Normal attack,
  303.                  Attacks through another Piece counts half }
  304.                Cnt := 0;
  305.                Sq := Square;
  306.                Direct := True;
  307.                repeat
  308.                   { Get Next Square }
  309.                   Sq := Sq + DirTab[Dir];
  310.                   if (Sq and $88) <> 0 then Break;
  311.                   Temp:=AttackValue[Color,Sq];
  312.                   if Direct then                     { Add AttackValue }
  313.                      Inc(Cnt, Temp)
  314.                   else
  315.                      Inc(Cnt, Temp shr 1);
  316.                   with Board[Sq] do
  317.                     if Piece <> Empty then
  318.                       if (Piece <> PieceCount) and (Piece <> Queen) then
  319.                          Direct := False;
  320.                until Board[Sq].Piece = Pawn;
  321.                Inc(PVControl[Color,PieceCount,Square],Cnt shr 2);
  322.              end { for Dir };
  323.           end { for Color };
  324.  
  325.        { Calculate PVTable, Value by Value }
  326.        for Square := $77 downto 0 do
  327.          if (Square and $88) = 0 then
  328.          begin
  329.            for Color := White to Black do
  330.            begin
  331.              OppColor := ColorType(1 - ord(Color));
  332.              Line := Square and 7;
  333.              Row := Square shr 4;
  334.              Rank := Row;
  335.              if Color = Black then Rank := 7 - Rank;
  336.              Dist := DistAn[Rank] + DistAn[Line];
  337.              with PieceTab[OppColor,0] do
  338.                 KingDist := abs(Square shr 4 - ISquare shr 4) +
  339.                   (Square - ISquare) and 7;
  340.              for PieceCount := King to Pawn do
  341.              begin
  342.                 { Calculate POSITIONAL Value for the Piece On the Square }
  343.                 PosVal := 0;
  344.                 if Mating and (PieceCount <> Pawn) then
  345.                 begin
  346.                   { Mating Evaluation }
  347.                   if PieceCount = King then
  348.                     if Color = LosingColor then
  349.                     begin
  350.                       PosVal := 128 - 16 * DistAn[Rank] - 12 * DistAn[Line];
  351.                       if DistAn[Rank] = 3 then
  352.                         PosVal := PosVal - 16;
  353.                     end
  354.                     else
  355.                     begin
  356.                       PosVal := 128 - 4 * KingDist;
  357.                       if (DistAn[Rank] >= 2) or (DistAn[Line] = 3) then
  358.                         PosVal := PosVal - 16;
  359.                     end;
  360.                 end { Mating }
  361.                 else
  362.                 begin
  363.                   Temp := PVControl[Color,Rook,Square];
  364.                   Temp2:= PVControl[Color,Bishop,Square];
  365.  
  366.                   { Normal Evaluation function }
  367.                   case PieceCount of
  368.                      King:
  369.                        if MaterialLevel <= 0 then PosVal := -2 * Dist;
  370.                      Queen:
  371.                        PosVal := (Temp + Temp2) shr 2;
  372.                      Rook:
  373.                        PosVal := Temp;
  374.                      Bishop:
  375.                        PosVal := Temp2;
  376.                      Knight:
  377.                        begin
  378.                          Cnt := 0;
  379.                          for Dir := 0 to 7 do
  380.                          begin
  381.                            Sq := Square + KnightDir[Dir];
  382.                            if (Sq and $88) = 0 then
  383.                              Cnt := Cnt + AttackValue[Color,Sq];
  384.                          end;
  385.                          PosVal := Cnt shr 1 - Dist * 3;
  386.                        end;
  387.                      Pawn:
  388.                        if (Rank <> 0) and (Rank <> 7) then
  389.                          PosVal := PawnRank[Rank] + PawnFileFactor[Line] *
  390.                            (Rank + 2) - 12;
  391.                   end { case };
  392.                 end; { else }
  393.                 PVTable[Color,PieceCount,Square] := PosVal;
  394.              end { for PieceCount };
  395.            end { for Color };
  396.        end { for Square };
  397.  
  398.        { Calculate PawnTab (indicates which squares contain pawns) }
  399.        for Color := White to Black do
  400.          for Rank := 0 to 7 do
  401.            PawnTab[Color,Rank] := 0;
  402.        for Square := $77 downto 0 do
  403.          if (Square and $88) = 0 then
  404.            with Board[Square] do
  405.              if Piece = Pawn then
  406.              begin
  407.                Rank := Square shr 4;
  408.                if Color = Black then Rank := 7 - Rank;
  409.                PawnTab[Color,Rank] :=
  410.                  PawnTab[Color,Rank] or FileBitTab[Square and 7];
  411.              end; { if }
  412.        for Color := White to Black do   { Initialize PawnBit }
  413.          with PawnBit[-1,Color] do
  414.          begin
  415.            One := 0;
  416.            Dob := 0;
  417.            for Rank := 1 to 6 do
  418.            begin
  419.              Temp := PawnTab[Color,Rank];
  420.              Dob := Dob or One and Temp;
  421.              One := One or Temp;
  422.            end;
  423.          end;
  424.  
  425.        { Calculate PawnStructureValue }
  426.        RootValue := PawnStrVal(PawnBit[-1,Player]) - PawnStrVal(PawnBit[-1,Opponent]);
  427.  
  428.        { Calculate static Value for Pawn structure }
  429.        for Color := White to Black do
  430.        begin
  431.          OppColor := ColorType(1 - ord(Color));
  432.          PawnFileTab := 0;
  433.          LeftSideTab := 0;
  434.          RightSideTab := 0;
  435.          OpPassTab := $FF;
  436.          BehindOpPass := 0;
  437.          for Rank := 1 to 6 do { Squares where opponents pawns are passed pawns }
  438.          begin
  439.            OpPassTab := OpPassTab and not (PawnFileTab or
  440.                                LeftSideTab or RightSideTab);
  441.            { Squares behind the opponents passed pawns }
  442.            BehindOpPass := BehindOpPass or
  443.                           (OpPassTab and PawnTab[OppColor,7 - Rank]);
  444.            { Squares which are covered by a Pawn }
  445.            LeftChainTab := LeftSideTab;
  446.            RightChainTab := RightSideTab;
  447.            PawnFileTab  := PawnTab[Color,Rank];         { Squares with pawns }
  448.            { Squares with a Pawn beside them }
  449.            LeftSideTab  := (PawnFileTab shl 1) and $FF;
  450.            RightSideTab := (PawnFileTab shr 1) and $FF;
  451.            SideTab      := LeftSideTab  or RightSideTab;
  452.            ChainTab     := LeftChainTab or RightChainTab;
  453.            { Squares covering a Pawn }
  454.            Temp := PawnTab[Color,Succ(Rank)];
  455.            LeftCoverTab := (Temp shl 1) and $FF;
  456.            RightCoverTab := (Temp shr 1) and $FF;
  457.            Sq := Rank shl 4;
  458.            if Color = Black then Sq := Sq xor $70;
  459.            Bit := 1;
  460.            while Bit <> 0 do
  461.            begin
  462.              StrVal := 0;
  463.              if (Bit and SideTab) <> 0 then
  464.                StrVal := SidePawn
  465.              else if (Bit and ChainTab) <> 0 then
  466.                StrVal := ChainPawn;
  467.              if (Bit and LeftCoverTab) <> 0 then
  468.                StrVal := StrVal + CoverPawn;
  469.              if (Bit and RightCoverTab) <> 0 then
  470.                StrVal := StrVal + CoverPawn;
  471.              if (Bit and PawnFileTab) <> 0 then
  472.                StrVal := StrVal + NotMovePawn;
  473.              PVTable[Color,Pawn,Sq] := PVTable[Color,Pawn,Sq] + StrVal;
  474.              if (MaterialLevel <= 0) or (OppColor <> ProgramColor) then
  475.              begin
  476.                if (Bit and OpPassTab) <> 0 then                 { Passed pawns }
  477.                  PVTable[OppColor,Pawn,Sq] :=
  478.                    PVTable[OppColor,Pawn,Sq] + PassPawnRank[7 - Rank];
  479.                if (Bit and BehindOpPass) <> 0 then { Rooks behind passed pawns }
  480.                begin
  481.                  Temp := Sq xor $10;
  482.                  for TempColor := Black to White do
  483.                  begin
  484.                    PVTable[TempColor,Rook,Sq] :=
  485.                      PVTable[TempColor,Rook,Sq] + RookBehindPassPawn;
  486.                    if Rank = 6 then
  487.                      PVTable[TempColor,Rook,Temp] :=
  488.                        PVTable[TempColor,Rook,Temp] + RookBehindPassPawn;
  489.                  end; { for }
  490.                end; { if }
  491.              end; { if }
  492.              Sq := Succ(Sq);
  493.              Bit := (Bit shl 1) and $FF;
  494.            end; { while }
  495.          end; { for }
  496.        end; { for }
  497.  
  498.        { Calculate penalty for blocking center pawns with a Bishop }
  499.        for Sq := 3 to 4 do
  500.        begin
  501.          with Board[Sq + $10] do
  502.            if (Piece = Pawn) and (Color = White) then
  503.              PVTable[White,Bishop,Sq + $20] :=
  504.                PVTable[White,Bishop,Sq + $20] - BishopBlockValue;
  505.          with Board[Sq + $60] do
  506.            if (Piece = Pawn) and (Color = Black) then
  507.              PVTable[Black,Bishop,Sq + $50] :=
  508.                PVTable[Black,Bishop,Sq + $50] - BishopBlockValue;
  509.        end; { for }
  510.  
  511.        { Calculate RootValue }
  512.        for Square := $77 downto 0 do
  513.          if (Square and $88) = 0 then
  514.            with Board[Square] do
  515.              if Piece <> Empty then
  516.                if Color = Player then
  517.                  RootValue := RootValue + PiecePosVal(Piece,Player,Square)
  518.                else
  519.                  RootValue := RootValue - PiecePosVal(Piece,Opponent,Square);
  520.     end;  { with CC^ }
  521.   end; { CalcPVTable }
  522.  
  523.  
  524.   { Updates PawnBit and calculates Value when a Pawn is
  525.     removed from Line }
  526.   function DecPawnStrVal(Color: ColorType; Line: FileType): Integer;
  527.   var
  528.     Temp: Integer;
  529.   begin
  530.     with PawnBit[CC.Depth,Color] do
  531.     begin
  532.        Temp := not FileBitTab[Line];
  533.        One := One and Temp or Dob;
  534.        Dob := Dob and Temp;
  535.     end;
  536.     DecPawnStrVal := PawnStrVal(PawnBit[CC.Depth,Color]) -
  537.       PawnStrVal(PawnBit[Pred(CC.Depth),Color]);
  538.   end; { DecPawnStrVal }
  539.  
  540.   { Updates PawnBit and calculates Value when a Pawn moves
  541.     from Old to New1 file }
  542.   function MovePawnStrVal(Color: ColorType; New1, Old: FileType): Integer;
  543.   var
  544.     Temp, Temp2: Integer;
  545.   begin
  546.      with PawnBit[CC.Depth,Color] do
  547.      begin
  548.         Temp := FileBitTab[New1];
  549.         Temp2 := not FileBitTab[Old];
  550.         Dob := Dob or One and Temp;
  551.         One := One and Temp2 or Dob or Temp;
  552.         Dob := Dob and Temp2;
  553.      end; { with }
  554.      MovePawnStrVal := PawnStrVal(PawnBit[CC.Depth,Color]) -
  555.        PawnStrVal(PawnBit[Pred(CC.Depth),Color]);
  556.   end; { MovePawnStrVal }
  557.  
  558.   { Calculates STATIC Evaluation of the Move }
  559.   function StateValu(MoveIt: MoveType): Integer;
  560.   var
  561.     Value: Integer;
  562.     CastSquare,CornerSquare,EpSquare: SquareType;
  563.   begin { StateValu }
  564.     with CC, MoveIt do
  565.     begin
  566.       Value := 0;
  567.       if Spe then
  568.         if MovPiece = King then
  569.         begin
  570.           GenCastSquare(New1,CastSquare,CornerSquare);          { Castling }
  571.           Value := PiecePosVal(Rook,Player,CastSquare) -
  572.                    PiecePosVal(Rook,Player,CornerSquare);
  573.           if New1 > Old then
  574.             Inc(Value, CastValue[Short])
  575.           else
  576.             Inc(Value, CastValue[Long]);
  577.         end
  578.         else
  579.           if MovPiece = Pawn then
  580.           begin
  581.             EpSquare := New1 - PawnDir[Player];             { E.p. capture }
  582.             Value := PiecePosVal(Pawn,Opponent,EpSquare);
  583.           end
  584.           else
  585.             { Pawnpromotion }
  586.             Value := PiecePosVal(MovPiece,Player,Old) -
  587.               PiecePosVal(Pawn, Player, Old) +
  588.               DecPawnStrVal(Player, Old and 7);
  589.       if Content <> Empty then                              { Normal moves }
  590.       begin
  591.         Value := Value + PiecePosVal(Content,Opponent,New1);
  592.         { Penalty for exchanging Pieces when behind in material }
  593.         if abs(MainEvalu) >= $100 then
  594.           if Content <> Pawn then
  595.             if (ProgramColor = Opponent) = (MainEvalu >= 0) then
  596.               Dec(Value,ExchangeValue);
  597.       end; { if }
  598.       PawnBit[Depth] := PawnBit[Pred(Depth)];          { Calculate PawnBit }
  599.       if (MovPiece = Pawn) and ((Content <> Empty) or Spe) then
  600.         Value := Value + MovePawnStrVal(Player,New1 and 7,Old and 7);
  601.       if (Content = Pawn) or Spe and (MovPiece = Pawn) then
  602.         Value := Value - DecPawnStrVal(Opponent,New1 and 7);
  603.       { Calculate Value of Move }
  604.       StateValu := Value + PiecePosVal(MovPiece,Player,New1) -
  605.         PiecePosVal(MovPiece,Player,Old);
  606.     end; { with }
  607.   end; { StateValu }
  608.  
  609.   var
  610.     KillingMove: array[ 0..MaxPly,0..1] of MoveType;
  611.     CheckTab: array[-1..MaxPly] of Boolean;       { Table of checks }
  612.     { Square of eventual pawn On 7th Rank }
  613.     PassedPawn: array[-2..MaxPly] of EdgeSquareType;
  614.  
  615.   { Initializes KillingMove, CheckTab and PassedPawn }
  616.   procedure ClearKillMove;
  617.   const
  618.     rank7: array[ColorType] of SquareType = ($60, $10);
  619.   var
  620.     Dep: DepthType;
  621.     Col: ColorType;
  622.     Sq: SquareType;
  623.     i : byte;
  624.   begin
  625.     {Clear KillingMove }
  626.     FillChar(KillingMove, SizeOf(KillingMove), 0);
  627.     CheckTab[-1] := False;                        { No Check at First Ply }
  628.     PassedPawn[-2] := -1;
  629.     PassedPawn[-1] := -1;
  630.     { Place eventual pawns On 7th Rank in PassedPawn }
  631.     for Col := White to Black do
  632.       for Sq := rank7[Col] to rank7[Col] + 7 do
  633.         with CC, Board[Sq] do
  634.           if (Piece = Pawn) and (Color = Col) then
  635.             if Col = Player then
  636.               PassedPawn[-2] := Sq
  637.             else
  638.               PassedPawn[-1] := Sq;
  639.   end; { ClearKillMove }
  640.  
  641.   var
  642.     SkipSearch: Boolean;
  643.  
  644.   { Communicates with the user }
  645.   procedure CallSmallTalk;
  646.   var
  647.     SearchStateDepth: DepthType;
  648.     StoredMove: MoveType;
  649.     Msg: Word;
  650.     OpAn: Boolean;
  651.  
  652.      { Backup the Search and setup Talk surroundings }
  653.      procedure GetProgramState;
  654.      var
  655.        OldPlayer: ColorType;
  656.      begin
  657.        with CC do
  658.        begin
  659.           SearchStateDepth := Depth;
  660.           while Depth > 0 do
  661.           begin
  662.              Dec(Depth);
  663.              OldPlayer := Opponent;
  664.              Opponent := Player;
  665.              Player   := OldPlayer;
  666.              Perform(MovTab[Depth],True);
  667.           end;
  668.           Dec(Depth);
  669.           if OpAn then
  670.             TakeBackMove(MovTab[Depth]);
  671.         end;
  672.      end; { GetProgramState }
  673.  
  674.      { Restore the Search surroundings }
  675.      procedure GetSearchState;
  676.      var
  677.        OldPlayer: ColorType;
  678.      begin
  679.        with CC do
  680.        begin
  681.          if OpAn then
  682.            MakeMove(MovTab[Depth + 1]);
  683.          Inc(Depth);
  684.          while Depth < SearchStateDepth do
  685.          begin
  686.            Perform(MovTab[Depth],False);
  687.            OldPlayer := Player;
  688.            Player   := Opponent;
  689.            Opponent := OldPlayer;
  690.            Inc(Depth);
  691.          end;
  692.        end;
  693.      end; { GetSearchState }
  694.  
  695.      function WaitFor(Send, Receive: Word): Word;
  696.      var
  697.        Msg: Word;
  698.      begin
  699.        repeat
  700.          Msg := Message(Send);
  701.        until Msg in [tmAbort, Receive];
  702.        WaitFor := Msg;
  703.      end;
  704.  
  705.   begin { CallSmallTalk }
  706.    with CC do
  707.    begin
  708.      if TaskTimer.TimeExpired then
  709.      begin
  710.        OpAn := OppAnalysis in State;
  711.        GetProgramState;           {  Save Search surroundings }
  712.        StoredMove := MovTab[Depth + 1];
  713.  
  714.        Msg := Message(tmTimeExpired);
  715.        case Msg of
  716.          tmEnterMove:
  717.            begin
  718.              SkipSearch := True;
  719.              Include(State, MovePending);
  720.              if (OppAnalysis in State) and EqMove(KeyMove,StoredMove) then
  721.              begin
  722.                Exclude(State, MovePending);
  723.                 Exclude(State, OppAnalysis);
  724.                SkipSearch := False;
  725.                EnterKeyMove;
  726.                repeat until Message(tmFindMove) = tmFindMove;
  727.                Include(State, Analysis);
  728.                if WaitFor(tmFindMove, tmResume) <> tmAbort then
  729.                  Clock.Start
  730.                else
  731.                begin
  732.                  Exclude(State, Analysis);
  733.                  SkipSearch := True;
  734.                end;
  735.              end;
  736.            end;
  737.          tmAbort:
  738.            begin
  739.              Exclude(State, Analysis);
  740.              Exclude(State, OppAnalysis);
  741.              SkipSearch := True;
  742.            end;
  743.          tmResume:
  744.            SkipSearch := False;
  745.        end;
  746.        GetSearchState;            {  Restore Search surroundings }
  747.      end;
  748.    end;
  749.   end;
  750.  
  751.   type
  752.     InfType = record
  753.       PrincipVar: Boolean;      { Principal Variation Search }
  754.       Value,                    { Static incremental Evaluation }
  755.       Evaluation: MaxType;      { Evaluation of position }
  756.     end;
  757.  
  758.   var
  759.     StartInf: InfType;          { Inf at First Ply }
  760.     AlphaWindow: MaxType;       { Alpha window Value }
  761.     RepeatEvalu: MaxType;       { MainEvalu at Ply One }
  762.  
  763.   { Performs the Search.
  764.     On entry :
  765.        Player is Next to Move.
  766.        MovTab[Depth - 1] contains Last Move.
  767.        Alpha, Beta contains the Alpha - Beta window.
  768.        Ply contains the Depth of the Search.
  769.        Inf contains various informations.
  770.  
  771.     On Exit :
  772.        BestLine contains the principal variation.
  773.        Search contains the Evaluation for Player }
  774.   function Search(Alpha, Beta: MaxType; Ply: Integer; Inf: InfType;
  775.     var BestLine: LineType): MaxType;
  776.   var
  777.     Line: LineType;            { Best Line at Next Ply }
  778.     CaptureSearch: Boolean;    { Indicates capture Search }
  779.     MaxVal: MaxType;           { Maximal Evaluation (returned in Search) }
  780.     NextPly: Integer;          { Depth of Search at Next Ply }
  781.     NextInf: InfType;          { Information at Next Ply }
  782.     ZeroWindow: Boolean;       { Zero-Width Alpha-Beta-window }
  783.  
  784.     { Move type }
  785.     MovGenType: (Main, SpecialCap, Kill, Normal);
  786.  
  787.     { Update KillingMove using BestMove }
  788.     procedure UpdateKill(BestMove: MoveType);
  789.     begin
  790.       with CC, BestMove do
  791.         if MovPiece <> Empty then
  792.         begin
  793.           { Update KillingMove unless the Move is a capture of
  794.             Last moved Piece }
  795.           if (MovTab[Depth - 1].MovPiece = Empty) or
  796.               (New1 <> MovTab[Depth - 1].New1) then
  797.             if (KillingMove[Depth,0].MovPiece = Empty) or
  798.               EqMove(BestMove,KillingMove[Depth,1]) then
  799.             begin
  800.               KillingMove[Depth,1] := KillingMove[Depth,0];
  801.               KillingMove[Depth,0] := BestMove;
  802.             end
  803.             else
  804.               if not EqMove(BestMove,KillingMove[Depth,0]) then
  805.                 KillingMove[Depth,1] := BestMove;
  806.         end; { if }
  807.     end; { UpdateKill }
  808.  
  809.  
  810.     { Test if Move has been generated before }
  811.     function GeneratedBefore: Boolean;
  812.     var
  813.       i: 0..1;
  814.     begin
  815.       GeneratedBefore := True;
  816.       with CC do
  817.       begin
  818.         if MovGenType <> Main then
  819.         begin
  820.           if EqMove(MovTab[Depth],BestLine[Depth]) then Exit;
  821.           if not CaptureSearch then
  822.             if MovGenType <> Kill then
  823.               for i := 0 to 1 do
  824.                 if EqMove(MovTab[Depth], KillingMove[Depth,i]) then Exit;
  825.         end;
  826.       end;
  827.       GeneratedBefore := False;
  828.     end; { GeneratedBefore }
  829.  
  830.     { Tests Cut-off. CutVal contains the maximal Possible Evaluation }
  831.     function Cut(CutVal: MaxType): Boolean;
  832.     begin
  833.       Cut := False;
  834.       if CutVal <= Alpha then
  835.       begin
  836.         Cut := True;
  837.         if MaxVal < CutVal then MaxVal := CutVal;
  838.       end;
  839.     end; { Cut }
  840.  
  841.     { Performs Move, calculates Evaluation, tests Cut-off etc. }
  842.     function Update: Boolean;
  843.     var
  844.       Selection: Boolean;
  845.     label AcceptMove,TakeBackMove,CutMove;
  846.     begin    { Update }
  847.       with CC do
  848.       begin
  849.         with MovTab[Depth] do
  850.         begin
  851.           Inc(Nodes);
  852.           NextPly := Ply - 1;                         { Calculate next ply }
  853.           { MateSearch }
  854.           if Level = MateSearch then
  855.           begin
  856.             { Perform Move On the Board }
  857.             Perform(MovTab[Depth],False);
  858.  
  859.             { Check if Move is Legal }
  860.             if Attacks(Opponent,PieceTab[Player,0].ISquare) then
  861.               goto TakeBackMove;
  862.             if Depth = 0 then
  863.               LegalMoves := LegalMoves + 1;
  864.             CheckTab[Depth] := False;
  865.             PassedPawn[Depth] := -1;
  866.             NextInf.Value := 0;
  867.             NextInf.Evaluation := 0;
  868.             if NextPly <= 0 then { Calculate Check and Perform evt. Cut-off }
  869.             begin
  870.               if NextPly = 0 then
  871.               CheckTab[Depth] := Attacks(Player,PieceTab[Opponent,0].ISquare);
  872.               if not CheckTab[Depth] then
  873.               begin
  874.                 if Cut(NextInf.Value) then goto TakeBackMove;
  875.               end;
  876.            end;
  877.            goto AcceptMove;
  878.          end;
  879.  
  880.          { Make special limited CaptureSearch at First iteration }
  881.          if MaxDepth <= 1 then
  882.            if CaptureSearch and (Depth >= 2) then
  883.              if not ((Content < MovPiece) or (MovGenType = SpecialCap) or
  884.                  (Old = MovTab[Depth - 2].New1)) then
  885.                goto CutMove;
  886.  
  887.          { Calculate Next static incremental Evaluation }
  888.          NextInf.Value := -Inf.Value + StateValu(MovTab[Depth]);
  889.  
  890.          { Calculate CheckTab (only checks with moved Piece are calculated).
  891.            Giving Check does not Count as a Ply }
  892.          CheckTab[Depth] := PieceAttacks(MovPiece,Player,New1,
  893.            PieceTab[Opponent, 0].ISquare);
  894.          if CheckTab[Depth] then NextPly := Ply;
  895.  
  896.          { Calculate PassedPawn. Moving a Pawn to 7th Rank does not Count
  897.            as a Ply }
  898.          PassedPawn[Depth] := PassedPawn[Depth - 2];
  899.          if MovPiece = Pawn then
  900.            if (New1 < $18) or (New1 >= $60) then
  901.            begin
  902.              PassedPawn[Depth] := New1;
  903.              NextPly := Ply;
  904.            end;
  905.  
  906.            { Perform Selection at Last Ply and in capture Search }
  907.            Selection := (NextPly <= 0) and not CheckTab[Depth] and
  908.              (Depth > 0);
  909.            if Selection then                            { Check Evaluation }
  910.            if Cut(NextInf.Value + 0) then goto CutMove;
  911.  
  912.            { Perform Move On the Board }
  913.            Perform(MovTab[Depth],False);
  914.  
  915.            { Check if move is legal }
  916.            if Attacks(Opponent,PieceTab[Player,0].ISquare) then
  917.              goto TakeBackMove;
  918.            if PassedPawn[Depth] >= 0 then               { Check PassedPawn }
  919.              with Board[PassedPawn[Depth]] do
  920.                if (Piece <> Pawn) or (Color <> Player) then
  921.                  PassedPawn[Depth] := -1;
  922.  
  923.            { Count Number of Legal moves at Ply 0 }
  924.            if Depth = 0 then
  925.              LegalMoves := LegalMoves + 1;
  926.  
  927.            { Calculate Random }
  928.            if Depth = 0 then
  929.              NextInf.Value := NextInf.Value + Random(4);
  930.  
  931.            { Calculate the Evaluation for the position }
  932.            NextInf.Evaluation := NextInf.Value;
  933.          end { with };
  934.  
  935.       AcceptMove:
  936.          Update := False;
  937.          Exit;
  938.  
  939.       TakeBackMove:
  940.          Perform(MovTab[Depth],True);
  941.  
  942.       CutMove:
  943.        end;  { with CC^ }
  944.        Update := True;
  945.     end { Update };
  946.  
  947.     { Calculate Draw bonus/penalty, and set Draw if the game is a Draw }
  948.     function DrawGame: Boolean;
  949.     var
  950.       DrawCount: 0..4;
  951.       SearchRepeat: RepeatType;
  952.       SearchFifty: FiftyType;
  953.     begin
  954.       DrawGame := False;
  955.       with CC do
  956.       begin
  957.         if Depth = 1 then
  958.         begin
  959.           SearchFifty := FiftyMoveCnt;
  960.           SearchRepeat := Repetition(False);
  961.  
  962.           { 3rd Repetition is Draw }
  963.           if SearchRepeat >= 3 then
  964.           begin
  965.             DrawGame := True;
  966.             NextInf.Evaluation := 0;
  967.             Exit;
  968.           end;
  969.           DrawCount := 0;
  970.           if SearchFifty >= 96 then
  971.             { 48 moves without Pawn }
  972.             DrawCount := 3
  973.           else if SearchRepeat >= 2 then
  974.             { 2nd Repetition }
  975.             DrawCount := 2
  976.           else
  977.  
  978.           { 10 moves without Pawn }
  979.           if SearchFifty >= 20 then
  980.             DrawCount := 1;
  981.           Inc(NextInf.Value, (RepeatEvalu div 4) * DrawCount);
  982.           Inc(NextInf.Evaluation, (RepeatEvalu div 4) * DrawCount);
  983.         end; { if }
  984.  
  985.         if Depth >= 3 then
  986.         begin
  987.           SearchRepeat := Repetition(True);
  988.           if SearchRepeat >= 2 then
  989.           begin
  990.             { Immediate Repetition }
  991.             DrawGame := True;
  992.             NextInf.Evaluation := 0;
  993.             Exit;
  994.           end;
  995.         end; { if }
  996.       end; { with }
  997.     end; { DrawGame }
  998.  
  999.     { Update BestLine and MainEvalu using Line and MaxVal }
  1000.     procedure UpdateBestLine;
  1001.     begin
  1002.       BestLine := Line;
  1003.       with CC do
  1004.       begin
  1005.         BestLine[Depth] := MovTab[Depth];
  1006.         if Depth = 0 then
  1007.         begin
  1008.           MainEvalu := MaxVal;
  1009.           if Level = MateSearch then
  1010.             MaxVal := AlphaWindow;
  1011.         end;
  1012.       end;
  1013.     end { UpdateBestLine };
  1014.  
  1015.  
  1016.     { The inner loop of the Search procedure. MovTab[Depth] contains
  1017.       the Move }
  1018.     function LoopBody: Boolean;
  1019.     var
  1020.       OldPlayer:    ColorType;
  1021.       LastAnalysis: Boolean;
  1022.     label RepeatSearch,NotSearch;
  1023.     begin    { LoopBody }
  1024.       LoopBody := False;
  1025.       if GeneratedBefore then Exit;
  1026.       with CC do
  1027.       begin
  1028.  
  1029.         { Initialize Line }
  1030.         if Depth < MaxPly then
  1031.         begin
  1032.           Line[Depth + 1] := ZeroMove;
  1033.           if MovGenType = Main then
  1034.             Line := BestLine;
  1035.         end;
  1036.  
  1037.         { PrincipVar indicates Principal Variation Search.
  1038.           ZeroWindow indicates zero - Width Alpha - Beta window }
  1039.         NextInf.PrincipVar := False;
  1040.         ZeroWindow := False;
  1041.         if Inf.PrincipVar then
  1042.           if MovGenType = Main then
  1043.             NextInf.PrincipVar := BestLine[Depth + 1].MovPiece <> Empty
  1044.           else
  1045.             ZeroWindow := MaxVal >= Alpha;
  1046.  
  1047.       RepeatSearch :
  1048.  
  1049.         { Update and test Cut-off }
  1050.         if Update then Exit;
  1051.  
  1052.         { Stop evt. Search }
  1053.         if Level = MateSearch then
  1054.            if (NextPly <= 0) and not CheckTab[Depth] then goto NotSearch;
  1055.         if DrawGame then goto NotSearch;
  1056.         if Depth >= MaxPly then goto NotSearch;
  1057.  
  1058.         { Analyse NextPly using a recursive call to Search }
  1059.         OldPlayer := Player; Player := Opponent; Opponent := OldPlayer;
  1060.         Inc(Depth);
  1061.         if ZeroWindow then
  1062.           NextInf.Evaluation := -Search(-Alpha - 1,- Alpha,NextPly,NextInf,Line)
  1063.         else
  1064.           NextInf.Evaluation := -Search(-Beta,- Alpha,NextPly,NextInf,Line);
  1065.         Dec(Depth);
  1066.         OldPlayer := Opponent;   Opponent := Player;   Player := OldPlayer;
  1067.  
  1068.       NotSearch :
  1069.         { Take Back Move }
  1070.         Perform(MovTab[Depth], True);
  1071.         if SkipSearch then
  1072.         begin
  1073.            LoopBody := True;
  1074.            Exit;
  1075.         end;
  1076.         LastAnalysis := Analysis in State;
  1077.  
  1078.         { Check elapsed tic time and test SkipSearch }
  1079.         CallSmallTalk;
  1080.  
  1081.         if (not SkipSearch) and (Analysis in State) {and ((Depth = 0) or
  1082.             not LastAnalysis) {and (MainEvalu > AlphaWindow)} then
  1083.           SkipSearch := Clock.TimeExpired;
  1084.  
  1085.         if (Analysis in State) and (MaxDepth <= 1) then
  1086.           SkipSearch := False;
  1087.  
  1088.         { Update MaxVal }
  1089.         MaxVal := Max(MaxVal,NextInf.Evaluation);
  1090.  
  1091.         { Update evt. BestLine }
  1092.         if EqMove(BestLine[Depth],MovTab[Depth]) then
  1093.           UpdateBestLine;
  1094.  
  1095.         { Update Alpha and test Cut-off }
  1096.         if Alpha < MaxVal then
  1097.         begin
  1098.           UpdateBestLine;
  1099.           if MaxVal >= Beta then
  1100.           begin
  1101.             { Cut-off }
  1102.             LoopBody := True;
  1103.             Exit;
  1104.           end;
  1105.  
  1106.           { Adjust MaxVal (Tolerance Search) }
  1107.           if (Ply >= 2) and Inf.PrincipVar and not ZeroWindow then
  1108.             MaxVal := Min(MaxVal + Tolerance,Beta - 1);
  1109.           Alpha := MaxVal;
  1110.           if ZeroWindow and not SkipSearch then
  1111.           begin
  1112.             { repeat Search with full window }
  1113.             ZeroWindow := False;
  1114.             goto RepeatSearch;
  1115.           end;
  1116.         end;
  1117.       end;  { with CC^ }
  1118.       LoopBody := SkipSearch;
  1119.     end { LoopBody };
  1120.  
  1121.  
  1122.     { Generate Pawn promotions }
  1123.     function PawnPromotionGen: Boolean;
  1124.     var   Promote: PieceType;
  1125.     begin
  1126.       PawnPromotionGen := True;
  1127.       with CC, MovTab[Depth] do
  1128.       begin
  1129.         Spe := True;
  1130.         for Promote := Queen to Knight do
  1131.         begin
  1132.           MovPiece := Promote;
  1133.           if LoopBody then Exit;
  1134.         end;
  1135.         Spe := False;
  1136.       end;
  1137.       PawnPromotionGen := False;
  1138.     end; { PawnPromotionGen }
  1139.  
  1140.     { Generates captures of the Piece On NewSq }
  1141.     function CapMovGen(NewSq: SquareType): Boolean;
  1142.     var
  1143.       NextSq, Sq: EdgeSquareType;
  1144.       i:  IndexType;
  1145.     begin
  1146.       CapMovGen := True;
  1147.       with CC, MovTab[Depth] do
  1148.       begin
  1149.         Content := Board[NewSq].Piece;
  1150.         Spe := False;
  1151.         New1 := NewSq;
  1152.  
  1153.         { Pawn captures }
  1154.         MovPiece := Pawn;
  1155.         NextSq := New1 - PawnDir[Player];
  1156.         for Sq := NextSq - 1 to NextSq + 1 do
  1157.           with Board[Sq] do
  1158.             if (Sq <> NextSq) and ((Sq and $88) = 0) and
  1159.               (Piece = Pawn) and (Color = Player) then
  1160.             begin
  1161.               Old := Sq;
  1162.               if (New1 < 8) or (New1 >= $70) then
  1163.               begin
  1164.                 if PawnPromotionGen then Exit;
  1165.               end
  1166.               else
  1167.                 if LoopBody then Exit;
  1168.             end;
  1169.  
  1170.         { Other captures }
  1171.         for i := OfficerNo[Player] downto 0 do
  1172.           with PieceTab[Player,i] do
  1173.             if (IPiece <> Empty) and (IPiece <> Pawn) and
  1174.               PieceAttacks(IPiece, Player, ISquare, NewSq) then
  1175.             begin
  1176.               Old := ISquare;
  1177.               MovPiece := IPiece;
  1178.               if LoopBody then Exit;
  1179.             end;
  1180.       end;
  1181.       CapMovGen := False;
  1182.     end; { CapMovGen }
  1183.  
  1184.     { Generates non captures for the Piece On OldSq }
  1185.     function NonCapMovGen(OldSq: SquareType): Boolean;
  1186.     var
  1187.       First, Last, Dir: DirType;
  1188.       Direction: Integer;
  1189.       NewSq: EdgeSquareType;
  1190.     begin
  1191.       NonCapMovGen := True;
  1192.       with CC, MovTab[Depth] do
  1193.       begin
  1194.         Spe := False;
  1195.         Old := OldSq;
  1196.         MovPiece := Board[OldSq].Piece;
  1197.         Content := Empty;
  1198.         case MovPiece of
  1199.           King:
  1200.             for Dir := 7 downto 0 do
  1201.             begin
  1202.               NewSq := Old + DirTab[Dir];
  1203.               if (NewSq and $88) = 0 then
  1204.                 if Board[NewSq].Piece = Empty then
  1205.                 begin
  1206.                   New1 := NewSq;
  1207.                   if LoopBody then Exit;
  1208.                 end;
  1209.             end;
  1210.           Knight:
  1211.             for Dir := 7 downto 0 do
  1212.             begin
  1213.               NewSq := Old + KnightDir[Dir];
  1214.               if (NewSq and $88) = 0 then
  1215.                 if Board[NewSq].Piece = Empty then
  1216.                 begin
  1217.                   New1 := NewSq;
  1218.                   if LoopBody then Exit;
  1219.                 end;
  1220.             end;
  1221.           Queen,
  1222.           Rook,
  1223.           Bishop:
  1224.             begin
  1225.               First := 7;
  1226.               Last := 0;
  1227.               if MovPiece = Rook then First := 3;
  1228.               if MovPiece = Bishop then Last := 4;
  1229.               for Dir := First downto Last do
  1230.               begin
  1231.                 Direction := DirTab[Dir];
  1232.                 NewSq := Old + Direction;
  1233.                 while (NewSq and $88) = 0 do
  1234.                 begin
  1235.                   if Board[NewSq].Piece <> Empty then Break;
  1236.                   New1 := NewSq;
  1237.                   if LoopBody then Exit;
  1238.                   NewSq := New1 + Direction;
  1239.                 end;
  1240.               end;
  1241.             end;
  1242.           Pawn:
  1243.             begin
  1244.               { One Square forward }
  1245.               New1 := Old + PawnDir[Player];
  1246.               if Board[New1].Piece = Empty then
  1247.                 if (New1 < 8) or (New1 >= $70) then
  1248.                 begin
  1249.                   if PawnPromotionGen then Exit;
  1250.                 end
  1251.                 else
  1252.                 begin
  1253.                   if LoopBody then Exit;
  1254.                   if (Old < $18) or (Old >= $60) then
  1255.                   begin
  1256.                     { Two squares forward }
  1257.                     New1 := New1 + (New1 - Old);
  1258.                     if Board[New1].Piece = Empty then
  1259.                        if LoopBody then Exit;
  1260.                   end;
  1261.                 end;
  1262.             end;
  1263.         end { case };
  1264.       end { with };
  1265.       NonCapMovGen := False;
  1266.     end { NonCapMovGen };
  1267.  
  1268.     { Castling moves }
  1269.     function CastlingMovGen: Boolean;
  1270.     var
  1271.       CastDir: CastDirType;
  1272.     begin
  1273.       CastlingMovGen := True;
  1274.       with CC, MovTab[Depth] do
  1275.       begin
  1276.         Spe := True;
  1277.         MovPiece := King;
  1278.         Content := Empty;
  1279.         for CastDir := Short downto Long do
  1280.           with CastMove[Player,CastDir] do
  1281.           begin
  1282.             New1 := CastNew;
  1283.             Old := CastOld;
  1284.             if KillMovGen(MovTab[Depth]) then
  1285.               if LoopBody then Exit;
  1286.           end;
  1287.       end;
  1288.       CastlingMovGen := False;
  1289.     end; { CastlingMovGen }
  1290.  
  1291.     { E.p. captures }
  1292.     function EpCapMovGen: Boolean;
  1293.     var
  1294.       Sq: EdgeSquareType;
  1295.     begin
  1296.       EpCapMovGen := True;
  1297.       with CC, MovTab[Depth - 1] do
  1298.         if MovPiece = Pawn then
  1299.           if abs(New1 - Old) >= $20 then
  1300.           begin
  1301.             MovTab[Depth].Spe := True;
  1302.             MovTab[Depth].MovPiece := Pawn;
  1303.             MovTab[Depth].Content := Empty;
  1304.             MovTab[Depth].New1 := (New1 + Old) div 2;
  1305.             for Sq := New1 - 1 to New1 + 1 do if Sq <> New1 then
  1306.               if (Sq and $88) = 0 then
  1307.               begin
  1308.                 MovTab[Depth].Old := Sq;
  1309.                 if KillMovGen(MovTab[Depth]) then
  1310.                   if LoopBody then Exit;
  1311.               end;
  1312.           end;
  1313.       EpCapMovGen := False;
  1314.     end { EpCapMovGen };
  1315.  
  1316.  
  1317.     { Generates the Next Move to be analysed.
  1318.       Controls the order of the movegeneration.
  1319.          The moves are generated in the order :
  1320.          Main variation
  1321.          Captures of Last moved Piece
  1322.          Killing moves
  1323.          Other captures
  1324.          Pawnpromovtions
  1325.          Castling
  1326.          Normal moves
  1327.          E.p. captures
  1328.     }
  1329.     procedure SearchMovGen;
  1330.     var
  1331.       Index: IndexType;
  1332.       KillNo: 0..1;
  1333.     begin
  1334.       with CC, MovTab[Depth] do
  1335.       begin
  1336.         { Generate Move from Main variation }
  1337.         if BestLine[Depth].MovPiece <> Empty then
  1338.         begin
  1339.           MovTab[Depth] := BestLine[Depth];
  1340.           MovGenType := Main;
  1341.           if LoopBody then Exit;
  1342.         end;
  1343.  
  1344.         { Captures of Last moved Piece }
  1345.         with MovTab[Depth - 1] do
  1346.           if MovPiece <> Empty then if MovPiece <> King then
  1347.           begin
  1348.             MovGenType := SpecialCap;
  1349.             if CapMovGen(New1) then Exit;
  1350.           end;
  1351.  
  1352.         { Killing moves }
  1353.         MovGenType := Kill;
  1354.         if not CaptureSearch then
  1355.           for KillNo := 0 to 1 do
  1356.           begin
  1357.             MovTab[Depth] := KillingMove[Depth,KillNo];
  1358.             if MovPiece <> Empty then
  1359.               if KillMovGen(MovTab[Depth]) then
  1360.                 if LoopBody then Exit;
  1361.           end;
  1362.  
  1363.         { Captures }
  1364.         MovGenType := Normal;
  1365.         for Index := 1 to PawnNo[Opponent] do
  1366.           with PieceTab[Opponent,Index] do
  1367.             if IPiece <> Empty then
  1368.               with MovTab[Depth - 1] do
  1369.                 if (MovPiece = Empty) or (ISquare <> New1) then
  1370.                   if CapMovGen(ISquare) then Exit;
  1371.  
  1372.         { Pawn promotions }
  1373.         if CaptureSearch then
  1374.           if PassedPawn[Depth - 2] >= 0 then
  1375.             with Board[PassedPawn[Depth - 2]] do
  1376.               if (Piece = Pawn) and (Color = Player) then
  1377.                 if NonCapMovGen(PassedPawn[Depth - 2]) then Exit;
  1378.  
  1379.         { Non-captures }
  1380.         if not CaptureSearch then
  1381.         begin
  1382.           { Castling }
  1383.           if CastlingMovGen then Exit;
  1384.  
  1385.           { other moves }
  1386.           for Index := PawnNo[Player] downto 0 do
  1387.             with PieceTab[Player,Index] do
  1388.               if IPiece <> Empty then
  1389.                 if NonCapMovGen(ISquare) then Exit;
  1390.         end;
  1391.  
  1392.         { E.p. captures }
  1393.         if EpCapMovGen then Exit;
  1394.       end;
  1395.     end { SearchMovGen };
  1396.  
  1397.   label Stop;
  1398.   begin { Search }
  1399.     with CC do
  1400.     begin
  1401.  
  1402.      { Perform CaptureSearch if Ply<=0 and not Check }
  1403.      CaptureSearch := (Ply <= 0) and not CheckTab[Depth - 1];
  1404.      if CaptureSearch then                     { Initialize MaxVal }
  1405.      begin
  1406.        MaxVal := -Inf.Evaluation;
  1407.        if Alpha < MaxVal then
  1408.        begin
  1409.          Alpha := MaxVal;
  1410.          if MaxVal >= Beta then goto Stop;
  1411.        end;
  1412.      end
  1413.      else
  1414.        MaxVal := -(LoseValue - Depth * DepthFactor);
  1415.      SearchMovGen;   { The Search loop }
  1416.      if SkipSearch then goto Stop;
  1417.      if MaxVal = -(LoseValue - Depth * DepthFactor) then   { test stalemate }
  1418.        if not Attacks(Opponent,PieceTab[Player,0].ISquare) then
  1419.        begin
  1420.          MaxVal := 0;
  1421.          goto Stop;
  1422.        end;
  1423.      UpdateKill(BestLine[Depth]);
  1424.     end;  { with }
  1425.   Stop:
  1426.     Search := MaxVal;
  1427.   end { Search };
  1428.  
  1429.   { Perform the Search }
  1430.   function CallSearch(Alpha,Beta: MaxType): MaxType;
  1431.   var
  1432.     MaxVal: MaxType;
  1433.   begin
  1434.     with CC do
  1435.     begin
  1436.       StartInf.PrincipVar := MainLine[0].MovPiece <> Empty;
  1437.       LegalMoves := 0;
  1438.       MaxVal := Search(Alpha,Beta,MaxDepth,StartInf,MainLine);
  1439.       if LegalMoves = 0 then MainEvalu := MaxVal;
  1440.       CallSearch := MaxVal;
  1441.     end;
  1442.   end; { CallSearch }
  1443.  
  1444.   { Checks whether the Search Time is used }
  1445.   function TimeUsed: Boolean;
  1446.   begin
  1447.     TimeUsed := False;
  1448.     with CC do
  1449.       if Analysis in State then
  1450.         TimeUsed := Clock.TimeExpired;
  1451.   end; { TimeUsed }
  1452.  
  1453. var
  1454.   MaxVal: MaxType;
  1455.   CalcPVTime: real;
  1456. begin { FindMove }
  1457.   with CC do
  1458.   begin
  1459.  
  1460.     { Initialize variables }
  1461.     Clock.Start;
  1462.     Nodes := 0;
  1463.     SkipSearch := False;
  1464.     ClearKillMove;
  1465.  
  1466.     { Calculate the P-V table }
  1467.     CalcPVTable;
  1468.     CalcPVTime := Clock.GetElapsedTime;
  1469.  
  1470.     { Initiate the search }
  1471.     StartInf.Value := -RootValue;
  1472.     StartInf.Evaluation := -RootValue;
  1473.     MaxDepth := 0;
  1474.     MainLine[0] := ZeroMove;
  1475.     MainEvalu := RootValue;
  1476.     AlphaWindow := MaxInt;
  1477.  
  1478.     { The iterative search loop }
  1479.     repeat
  1480.  
  1481.       { Update various variables }
  1482.       if MaxDepth <= 1 then RepeatEvalu := MainEvalu;
  1483.       AlphaWindow := Min(AlphaWindow,MainEvalu - $80);
  1484.       if Level = MateSearch then
  1485.       begin
  1486.         AlphaWindow := $6000;
  1487.         if MaxDepth > 0 then Inc(MaxDepth);
  1488.       end;
  1489.       Inc(MaxDepth);
  1490.  
  1491.       { Perform the search }
  1492.       MaxVal := CallSearch(AlphaWindow,$7F00);
  1493.       if (MaxVal <= AlphaWindow) and not SkipSearch and
  1494.         (Level <> MateSearch) and (LegalMoves > 0) then
  1495.       begin
  1496.  
  1497.         { repeat the search if the value falls below the Alpha - window }
  1498.         MainEvalu := AlphaWindow;
  1499.         MaxVal := CallSearch(-$7F00,AlphaWindow - Tolerance * 2);
  1500.         LegalMoves := 2;
  1501.       end;
  1502.     until SkipSearch or TimeUsed or (MaxDepth >= MaxLevel) or
  1503.       (LegalMoves <= 1) or (abs(MainEvalu) >= MateValue - 24 * DepthFactor);
  1504.     Clock.Stop;
  1505.   end; { with }
  1506. end; { FindMove }
  1507.  
  1508. end.