
{**
  @abstract(Lecteur de livre compact.)
  Lecteur d'un livre d'ouvertures au format Thompson-Spracklen.
}

unit Extractor;

(* https://www.developpez.net/forums/d2034310/autres-langages/pascal/langage/representation-l-arbre-d-livre-d-ouvertures-aux-echecs/#post11321534 *)

interface

uses
  Classes;

type
  TStringListArray = array of TStringList;

{** Extraction des lignes d'un livre d'ouvertures compact. }
function ExtractLines(const ATree: string): TStringListArray;

implementation

function ExtractLines(const ATree: string): TStringListArray;
const
  CMaxMoves = 200;
var
  LMoves: array[1..CMaxMoves] of string;
  LIndex: integer;
  LDone: boolean;
  
  procedure Store(const AIndex: integer; const AMove: string);
  var
    i: integer;
  begin
    if AIndex > LIndex then
    begin
      LMoves[AIndex] := AMove;
      LDone := FALSE;
    end;
    
    if (AIndex < LIndex) and not LDone then
    begin
      
      SetLength(result, Succ(Length(result)));
      result[High(result)] := TStringList.Create;
      result[High(result)].Delimiter := ' ';
      for i := 1 to Succ(AIndex) do
        result[High(result)].Append(LMoves[i]);
      
      LDone := TRUE;
    end;
    
    LIndex := AIndex;
  end;

var
  LLen, LLevel, LPos: integer;
  LData: string;
  c: char;
begin
  SetLength(result, 0);
  LIndex := 0;
  LDone := FALSE;
  
  LLevel := 0;
  LPos := 1;
  LData := '';
  LLen := Length(ATree);
  
  while LPos <= LLen do
  begin
    c := ATree[LPos];
    if c = '(' then
    begin
      Store(LLevel, LData);
      Inc(LLevel);
      LData := ''
    end else
    if c = ')' then
    begin
      Store(LLevel, LData);
      Dec(LLevel);
      LData := '';
    end else
      LData := LData + c;
    Inc(LPos);
  end;
  
  Store(0, '');
end;

end.
