{
  CEOI 2003 - Münster, Germany

  Task: Pearls
  Desc: Public Library, to be used during the contest
        NOTE: This version of the library always gives the necklace
              to the first dwarf on the applicable list.
  Author: Tobias Thierer <ceoi@tobias-thierer.de>
}

unit pearls_lib;

interface
  function getNext:Integer;
  procedure setNext(d:Integer);
  procedure finish;

implementation

  { ==================================================================== }
  { == private functions that are not published through the interface == }
  { ==================================================================== }

  const inname     = 'pearls.in';
        MAX_PEARLS = 1000;
        MAX_DWARFS = 1000;
        MAX_LIST_LENGTH = 20;
        assertions = true;


  type dwarfsRange = 1..MAX_DWARFS;
       pearlColor = (black, white);

  var numPearls      : Integer; { length of the necklace, 1 <= numPearls <= 1000 }
      numDwarfs      : Integer;
      currDwarf,
      firstDwarf     : Integer;
      necklace       : array[1..MAX_PEARLS] of pearlColor;
      listLength     : array[pearlColor, dwarfsRange] of Integer; { lengths of white and black lists }
      list           : array[pearlColor, dwarfsRange, 1..MAX_LIST_LENGTH] of Integer;
      isGreenDwarf   : array[dwarfsRange] of Boolean;
      pearlNum       : Integer;
      LIBinitialized : Boolean;

  { ----------------------------------------------------------------------- }

  function intToString(i:Integer):String;
  var s : String;
  begin str(i,s); intToString := s; end;

  procedure libReport(doexit:boolean; msg:String);
  begin
    writeln(msg);
    if doexit then halt(0);
  end;

  procedure assert(b:Boolean; msg:String);
  begin
    if assertions and (not b)
       then libReport(true, 'Assertion failed: ' + msg);
  end;


  procedure readData;
  var actPearl, actDwarf, i: Integer;
      ch    : Char;
      color : pearlColor;
      inf   : text;
  begin
    {$i-}
    assign(inf, inname);
    reset(inf);
    {$i+}
    if ioresult <> 0 then LIBreport(true,'could not open input file');
    readln(inf, numPearls, numDwarfs, firstDwarf);
    for actPearl:=1 to numPearls-1 do begin
      read(inf, ch);
      assert((ch = 'B') or (ch='W'), 'pearl neither [B]lack nor [W]hite.');
      if (ch='B') then necklace[actPearl] := black else necklace[actPearl] := white;
    end;
    readln(inf, ch); { 'D', diamond }
    assert(ch='D', 'diamond expected at end of necklace');
    for actDwarf:=1 to numDwarfs do begin
      read(inf, i);
      isGreenDwarf[actDwarf] := (i=0);
      for color:=black to white do begin
        read(inf, listLength[color,actDwarf]);
        assert(listLength[color, actDwarf] <= numDwarfs, 'White or black list of dwarf '+intToString(actDwarf)+' is too long.');
        for i:=1 to listLength[color,actDwarf] do read(inf, list[color,actDwarf,i]);
      end;
      readln(inf);
    end;
    close(inf);
  end;

  procedure init;
  begin
    if LIBinitialized then exit;
    LIBinitialized := true;
    pearlNum := 1;
    readData;
    currDwarf := firstDwarf;
    LIBreport(false, 'init()');
  end;

  { ==================================================================== }
  { ===== public functions that are published through the interface ==== }
  { ==================================================================== }

  function getNext:Integer;
  var currColor:pearlColor;
  begin
    // init;
    if pearlNum >= numPearls then LIBreport(true,
        'too many calls to getNext()/setNext()');
    if isGreenDwarf[currDwarf] then LIBreport(true,
       'called getNext() but ' + intToString(currDwarf)+' is a green dwarf');
    if not isGreenDwarf[currDwarf] then begin
      currColor := necklace[pearlNum];
      currDwarf := list[currColor, currDwarf, 1];
      assert((currDwarf >= 1) and (currDwarf <= numDwarfs),
             ' illegal dwarf number generated.');
    end;
    LIBreport(false,'getNext() -> ' + intToString(currDwarf));
    inc(pearlNum);
    getNext:=currDwarf;
  end;


  procedure setNext(d:Integer);
  var found:Boolean;
      i,len:Integer;
      currColor:pearlColor;
  begin
    // init;
    LIBreport(false,'setNext(' + intToString(d) +')');
    if pearlNum >= numPearls then LIBreport(true,'too many calls to getNext()/setNext()');
    if not isGreenDwarf[currDwarf] then LIBreport(true, 'called setNext() but ' + intToString(currDwarf)+' is a red dwarf');
    currColor := necklace[pearlNum];
    found := false;
    len := listLength[currColor, currDwarf];
    for i:=1 to len do if list[currColor, currDwarf, i] = d then found := true;
    if not found
     then LIBreport(true,
          'no dwarf with number ' + intToString(d) + ' in list of dwarf '+intToString(currDwarf));
    currDwarf := d;
    inc(pearlNum);
  end;

  procedure finish;
  begin
    // init;
    LIBreport(false,'finish()');
    if (pearlNum <> numPearls) then LIBreport(true, 'called finish() but end of game is not reached');
    if isGreenDwarf[currDwarf]
     then LIBreport(true, 'green dwarfs have won')
     else LIBreport(true, 'red dwarfs have won');
  end;

begin
  LIBinitialized := false;
  init;
end.

