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

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