
uses
  SysUtils, Classes, Chess, Move, Moves, Castling, Board, StrUtils;

function IsLegal(const APos: TPosition; const AMove: TMove): boolean;
var
  LPos: TPosition;
var
  LList: array[0..0] of integer;
  LCount: integer;
begin
  Initialize(LList);
  LPos := APos;
  result := FALSE;
  if DoMove(LPos, AMove) then
    with LPos do
      result := (
        GenerateMoves(LPos)
        //GenerateMoves(LPos, LList, LCount, TRUE, TRUE)
        and Pieces[not Side]
        and Kings
      ) = 0;
end;

function Test(const AFen: string; const ADepth, AExpectedResult: integer; const AId: string = ''): integer;
var
  LRes: array of integer;

  procedure GetMovesCount(const APos: TPosition; const ARecurse: integer);
  var
    LList, LList2: array[0..199] of TMove;
    LCount, LLegalCount, i: integer;
    LPos: TPosition;
  begin
    result := 0;
    Initialize(LList);
    Initialize(LList2);
    GenerateMoves(APos, LList, LCount);
    GenerateCastling(APos, LList, LCount);
    LLegalCount := 0;
    for i := 0 to Pred(LCount) do
      if IsLegal(APos, LList[i]) then
      begin
        LList2[LLegalCount] := LList[i];
        Inc(LLegalCount);
      end;
    Inc(LRes[Pred(ADepth - ARecurse)], LLegalCount);
    
    if ARecurse > 0 then
      for i := 0 to Pred(LLegalCount) do
      begin
        LPos := APos;
        if DoMove(LPos, LList2[i]) then
          GetMovesCount(LPos, Pred(ARecurse))
        else
        begin
          WriteLn('Unexpected error');
          Exit;
        end;
      end;
  end;

var
  i: integer;
  t: cardinal;
  
var
  LPos: TPosition;
  
begin
  if FALSE then
    ExecuteProcess(
      '/home/roland/Documents/pascal/echecs/chess-image/chess-image',
      [
        Format('--position=%s', [AFen]),
        Format('--output=%s.png', [AId]),
        '--coordinates'
      ]
    );
  
  LPos := CNewPos;
  LPos := EncodePosition(AFen);
  
  Initialize(LRes);
  SetLength(LRes, ADepth);
  for i := 0 to Pred(ADepth) do
    LRes[i] := 0;
  
  t := GetTickCount64;
  GetMovesCount(LPos, Pred(ADepth));
  t := GetTickCount64 - t;
  
  result := LRes[Pred(ADepth)];
  
  WriteLn(StringOfChar('=', 120));
  
  WriteLn(Format('Position    : %s [%s]', [AFen, AId]));
  WriteLn('Depth       : ', ADepth);
{
  WriteLn('Time elapsed: ', FormatDateTime('hh:nn:ss:zzz', t / (1000 * SECSPERDAY)));
}
  
  WriteLn(Format('Result      : %d [%s]', [
    result,
    IfThen(result = AExpectedResult, 'SUCCESS', Format('ERROR, %d expected', [AExpectedResult]))
  ]));
  
  SetLength(LRes, 0);
end;
  
begin
  Test(CStartPos, 4, 197281, 'startpos');
  Test(CStartPos, 5, 4865609, 'startpos');
  
  Test('8/PPP4k/8/8/8/8/4Kppp/8 w - - 0 1', 1, 18, 'cinnamon-3');
  Test('8/PPP4k/8/8/8/8/4Kppp/8 w - - 0 1', 2, 290, 'cinnamon-3');
  Test('8/PPP4k/8/8/8/8/4Kppp/8 w - - 0 1', 3, 5044, 'cinnamon-3');
  Test('8/PPP4k/8/8/8/8/4Kppp/8 w - - 0 1', 4, 89363, 'cinnamon-3');
  Test('8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 1', 4, 43238, 'cinnamon-4');
  Test('8/3K4/2p5/p2b2r1/5k2/8/8/1q6 b - - 1 67', 4, 54703, 'cinnamon-5');
  Test('r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1', 3, 97862, 'roce-2');
  
{ https://gist.github.com/peterellisjones/8c46c28141c162d1d8a0f0badbc9cff9 }
  Test('r6r/1b2k1bq/8/8/7B/8/8/R3K2R b KQ - 3 2', 1, 8, 'peter-01');
  Test('8/8/8/2k5/2pP4/8/B7/4K3 b - d3 0 3', 1, 8, 'peter-02');
  Test('r1bqkbnr/pppppppp/n7/8/8/P7/1PPPPPPP/RNBQKBNR w KQkq - 2 2', 1, 19, 'peter-03');
  Test('r3k2r/p1pp1pb1/bn2Qnp1/2qPN3/1p2P3/2N5/PPPBBPPP/R3K2R b KQkq - 3 2', 1, 5, 'peter-04');
  Test('2kr3r/p1ppqpb1/bn2Qnp1/3PN3/1p2P3/2N5/PPPBBPPP/R3K2R b KQ - 3 2', 1, 44, 'peter-05');
  Test('rnb2k1r/pp1Pbppp/2p5/q7/2B5/8/PPPQNnPP/RNB1K2R w KQ - 3 9', 1, 39, 'peter-06');
  Test('2r5/3pk3/8/2P5/8/2K5/8/8 w - - 5 4', 1, 9, 'peter-07');
  
{ https://talkchess.com/viewtopic.php?p=508921#p508921 }
  Test('3k4/3p4/8/K1P4r/8/8/8/8 b - - 0 1', 6, 1134888, 'martin-01');
  Test('8/8/8/8/k1p4R/8/3P4/3K4 w - - 0 1', 6, 1134888, 'martin-01-2');
  Test('8/8/4k3/8/2p5/8/B2P2K1/8 w - - 0 1', 6, 1015133, 'martin-02');
  Test('8/b2p2k1/8/2P5/8/4K3/8/8 b - - 0 1', 6, 1015133, 'martin-02-2');
  Test('8/8/1k6/2b5/2pP4/8/5K2/8 b - d3 0 1', 6, 1440467, 'martin-03');
  Test('8/5k2/8/2Pp4/2B5/1K6/8/8 w - d6 0 1', 6, 1440467, 'martin-03-2');
  Test('5k2/8/8/8/8/8/8/4K2R w K - 0 1', 1, 15, 'martin-04');
  Test('5k2/8/8/8/8/8/8/4K2R w K - 0 1', 2, 66, 'martin-04');
  Test('5k2/8/8/8/8/8/8/4K2R w K - 0 1', 3, 1198, 'martin-04');
  Test('5k2/8/8/8/8/8/8/4K2R w K - 0 1', 4, 6399, 'martin-04');
  Test('5k2/8/8/8/8/8/8/4K2R w K - 0 1', 5, 120330, 'martin-04');
  Test('5k2/8/8/8/8/8/8/4K2R w K - 0 1', 6, 661072, 'martin-04');
  Test('4k2r/8/8/8/8/8/8/5K2 b k - 0 1', 6, 661072, 'martin-04-2');
  Test('3k4/8/8/8/8/8/8/R3K3 w Q - 0 1', 6, 803711, 'martin-05');
  Test('r3k3/8/8/8/8/8/8/3K4 b q - 0 1', 6, 803711, 'martin-05-2');
  Test('r3k2r/1b4bq/8/8/8/8/7B/R3K2R w KQkq - 0 1', 4, 1274206, 'martin-06');
  Test('r3k2r/7b/8/8/8/8/1B4BQ/R3K2R b KQkq - 0 1', 4, 1274206, 'martin-06-2');
  Test('r3k2r/8/3Q4/8/8/5q2/8/R3K2R b KQkq - 0 1', 4, 1720476, 'martin-07');
  Test('r3k2r/8/5Q2/8/8/3q4/8/R3K2R w KQkq - 0 1', 4, 1720476, 'martin-07-2');
  Test('2K2r2/4P3/8/8/8/8/8/3k4 w - - 0 1', 6, 3821001, 'martin-08');
  Test('3K4/8/8/8/8/8/4p3/2k2R2 b - - 0 1', 6, 3821001, 'martin-08-2');
  Test('8/8/1P2K3/8/2n5/1q6/8/5k2 b - - 0 1', 5, 1004658, 'martin-09');
  Test('5K2/8/1Q6/2N5/8/1p2k3/8/8 w - - 0 1', 5, 1004658, 'martin-09-2');
  Test('4k3/1P6/8/8/8/8/K7/8 w - - 0 1', 6, 217342, 'martin-10');
  Test('8/k7/8/8/8/8/1p6/4K3 b - - 0 1', 6, 217342, 'martin-10-2');
  Test('8/P1k5/K7/8/8/8/8/8 w - - 0 1', 6, 92683, 'martin-11');
  Test('8/8/8/8/8/k7/p1K5/8 b - - 0 1', 6, 92683, 'martin-11-2');
  Test('K1k5/8/P7/8/8/8/8/8 w - - 0 1', 6, 2217, 'martin-12');
  Test('8/8/8/8/8/p7/8/k1K5 b - - 0 1', 6, 2217, 'martin-12-2');
  Test('8/k1P5/8/1K6/8/8/8/8 w - - 0 1', 7, 567584, 'martin-13');
  Test('8/8/8/8/1k6/8/K1p5/8 b - - 0 1', 7, 567584, 'martin-13-2');
  Test('8/8/2k5/5q2/5n2/8/5K2/8 b - - 0 1', 4, 23527, 'martin-14');
  Test('8/5k2/8/5N2/5Q2/2K5/8/8 w - - 0 1', 4, 23527, 'martin-14-2');
end.
