
{**
@abstract(Contrôle des chaînes FEN par les expressions régulières.)
}
unit FenFilter;

interface

uses
  RegExpr;

type
  TFenFilter = class
    private
      function ExpandEmptySquares(AExpr: TRegExpr): string;
    public
      function IsFen(const AStr: string): boolean;
  end;

implementation

uses
  Classes, SysUtils;

function TFenFilter.ExpandEmptySquares(AExpr: TRegExpr): string;
begin
  result := '';
  with AExpr do
    result := StringOfChar('-', StrToInt(Match[0]));
end;

function TFenFilter.IsFen(const AStr: string): boolean;
const
  CWhiteKing = 'K';
  CBlackKing = 'k';
  CPieces    = '^[1-8BKNPQRbknpqr]+$';
  CActive    = '^[wb]$';
  CCastling  = '^[KQkq]+$|^[A-Ha-h]+$|^\-$';
  CEnPassant = '^[a-h][36]$|^\-$';
  CHalfMove  = '^\d+$';
  CFullMove  = '^[1-9]\d*$';
var
  a, b: TStringList;
  i: integer;
  e: TRegExpr;
  s: string;
  
begin
  a := TStringList.Create;
  b := TStringList.Create;
  
  e := TRegExpr.Create;
  e.Expression := '\d';
  
  (*
  ExtractStrings([' '], [], PChar(AStr), a);
  ExtractStrings(['/'], [], PChar(a[0]), b);
  *)
  
  SplitRegExpr(' ', AStr, a);
  
  result := (a.Count = 6);

  if result then
  begin
    SplitRegExpr('/', a[0], b);
    result := (b.Count = 8);
  end;
  
  if result then
  begin
    result := result and ExecRegExpr(CWhiteKing, a[0]);
    result := result and ExecRegExpr(CBlackKing, a[0]);

    for i := 0 to 7 do
    begin
      result := result and ExecRegExpr(CPieces, b[i]);
      if result then
      begin
        s := b[i];
        repeat
          s := e.Replace(s, @ExpandEmptySquares);
        until not ExecRegExpr('\d', s);
        result := result and (Length(s) = 8);
      end;
    end;
    
    result := result and ExecRegExpr(CActive,    a[1]);
    result := result and ExecRegExpr(CCastling,  a[2]);
    result := result and ExecRegExpr(CEnPassant, a[3]);
    result := result and ExecRegExpr(CHalfMove,  a[4]);
    result := result and ExecRegExpr(CFullMove,  a[5]);
  end;

  a.Free;
  b.Free;
  e.Free;
end;

end.
