program Wires;

uses Cables, Judging, Measure;

const
  Test = true; { use built-in tester }
  SingleCable = false; { allow repeated use; break off with M=0 }
  Quiet = true;
  MaxMethod = 16;
  DefaultMethod = MaxMethod;

var
  prog: string;
  Method: integer;
  out: text;

procedure Init;
  var cc: integer; cfg: text; cfgname: string;
  begin
  prog := Copy(ParamStr(0), 1, Length(ParamStr(0))-4) ;
  if Quiet then Assign(out, prog+'.OUT')
  else Assign(out, 'CON') ;
  rewrite(out) ;
  writeln(out, 'Cable measurer') ;
  writeln(out, '  Test = ', Test:1) ;
  writeln(out, '  Quiet = ', Quiet:1) ;
  writeln(out, '  SingleCable = ', SingleCable:1) ;
  if Test then begin
    Mode := LocalAnswer ;
    cfgname := 'N.A.'
    end { then }
  else begin
    Mode := RemoteAsk ;
    if (ParamCount > 0) then begin
      Val(ParamStr(1), Method, cc) ;
      cfgname := 'ParamStr(1)'
      end { then }
    else begin
      cfgname := prog+'.CFG' ;
      Assign(cfg, cfgname) ;
      {$I-} reset(cfg) {$I+} ;
      if IOResult = 0 then readln(cfg, Method)
      else begin
        Method := DefaultMethod ;
        cfgname := 'Default'
        end { else }
      end { else }
    end { else } ;
  write(out, '  Method = ', Method:1, ' [', cfgname, ']') ;
  writeln(out) ;
  OneItemPerLine := false ;
  writeln(out, '  OneItemPerLine = ', OneItemPerLine:1) ;
  Verbose := false ;
  writeln(out, '  Verbose = ', Verbose:1) ;
  InitJudging(Competitor) ;
  writeln(out)
  end { Init } ;

procedure Fini;
  begin
  Close(LogFile) ; Close(out)
  end { Fini } ;

var
  M: Wire;
  N: Switch;
  f: Connectivity;

procedure ReconstructA; { Ask user }
  var ch: char; a: Wire; b: Switch;
  begin
  repeat
    write('The cable has ', M:1, ' wires and ') ;
    if not MequN then write(N:1, ' ') ;
    writeln('switches') ;
    repeat
      write('Give command [', probeChr, ',', changeChr, ',', doneChr, ']: ') ;
      readln(ch) ; ch := UpCase(ch) ;
      until ch in [probeChr, changeChr, doneChr] ;
    case ch of
      probeChr: begin
        write('Probe wire [1..', M:1, ']: ') ;
        readln(a) ;
        writeln('  Result: ', Probe(a):1)
        end ;
      changeChr: begin
        write('Change switch [1..', N:1, ']: ') ;
        readln(b) ;
        Change(b)
        end ;
      doneChr: begin
        writeln('Give wire --> switch connectivity:') ;
        for a := 1 to M do
          read(f[a]) ;
        readln
        end ;
      end { case }
    until ch = doneChr
  end { ReconstructA } ;

procedure ReconstructW1;
  var a: Wire; b: integer; p: boolean;
  begin
  for a := 1 to M do begin
    b := 0 ;
    repeat
      inc(b) ;
      Change(b) ; { switch b conducting }
      p := Probe(a) ;
      Change(b) { switch b non-conducting }
      until p ;
    f[a] := b
    end { for a }
  end { ReconstructW1 } ;

procedure ReconstructW2; { no reset }
  var a: Wire; b: integer; p: boolean;
  begin
  for a := 1 to M do begin
    p := Probe(a) ;
    b := 0 ;
    repeat
      inc(b) ;
      Change(b)
      until Probe(a) <> p ;
    f[a] := b
    end { for a }
  end { ReconstructW2 } ;

procedure ReconstructW3; { no reset, minimized }
  var a: Wire; b: Switch; p: boolean;
  begin
  for a := 1 to M do begin
    if (a = 1) or (N = 1) then p := false
    else p := Probe(a) ;
    b := 1 ; f[a] := N ;
    while f[a] <> b do begin
      Change(b) ;
      if Probe(a) = p then inc(b)
      else f[a] := b
      end { while }
    end { for a }
  end { ReconstructW3 } ;

procedure ReconstructW4; { cyclic }
  var a: Wire; b: Switch; p: boolean;
  begin
  b := N ;
  for a := 1 to M do begin
    p := Probe(a) ;
    repeat
      b := b mod N + 1 ;
      Change(b)
      until Probe(a) <> p ;
    f[a] := b
    end { for a }
  end { ReconstructW4 } ;

procedure ReconstructW5; { cyclic minimized (marginal) }
  var a: Wire; b: Switch; p: boolean;
  begin
  b := N ; p := false ;
  for a := 1 to M do begin
    if a <> 1 then p := Probe(a) ;
    repeat
      b := b mod N + 1 ;
      Change(b)
      until Probe(a) <> p ;
    f[a] := b
    end { for a }
  end { ReconstructW5 } ;

procedure ReconstructW6; { up-down sweeping, minimized }
  var a: Wire; b: Switch; p: boolean;
  begin
  b := 1 ; { sw. 1..b-1 conducting, b..N non-conducting }
  for a := 1 to M do begin
    if b = 1 then p := false
    else p := Probe(a) ;
    if p then begin
      dec(b) ; f[a] := 1 ;
      while f[a] <> b do begin
        Change(b) ;
        if Probe(a) = p then dec(b)
        else f[a] := b
        end { while } ;
      if b = 1 then inc(b)
      end { then }
    else begin
      f[a] := N ;
      while f[a] <> b do begin
        Change(b) ;
        if Probe(a) = p then inc(b)
        else f[a] := b
        end { while } ;
      if b < N then inc(b)
      end { else }
    end { for a }
  end { ReconstructW6 } ;

procedure ReconstructW(i: integer);
  begin
  case i of
    1: ReconstructW1 ;
    2: ReconstructW2 ;
    3: ReconstructW3 ;
    4: ReconstructW4 ;
    5: ReconstructW5 ;
    6: ReconstructW6 ;
    end { case }
  end { ReconstructW } ;

procedure ReconstructS1;
  var a: Wire; b: Switch;
  begin
  for b := 1 to N do begin
    Change(b) ; { switch b conducting }
    for a := 1 to M do
      if Probe(a) then f[a] := b ;
    Change(b) { switch b non-conducting }
    end { for b }
  end { ReconstructS1 } ;

procedure ReconstructS2;
  var a: Wire; b: Switch;
  begin
  for a := 1 to M do f[a] := N ;
  for b := 1 to N-1 do begin
    Change(b) ; { switch b conducting }
    for a := 1 to M do
      if f[a] = N then
        if Probe(a) then f[a] := b
    end { for b }
  end { ReconstructS2 } ;

procedure ReconstructS3;
  var a: Wire; b: Switch; k: integer;
  begin
  for a := 1 to M do f[a] := N ;
  k := M ; { k = # undetermined wires = (# a:: f[a]=N) }
  b := 1 ;
  while (b < N) and (k <> 0) do begin
    Change(b) ; { switch b conducting }
    for a := 1 to M do
      if f[a] = N then
        if Probe(a) then begin f[a] := b ; dec(k) end ;
    inc(b)
    end { while }
  end { ReconstructS3 } ;

procedure ReconstructS(i: integer);
  begin
  case i of
    1: ReconstructS1 ;
    2: ReconstructS2 ;
    3: ReconstructS3 ;
    end { case }
  end { ReconstructS } ;

procedure ReconstructBN(reverse: boolean);
  { uses Binary Notation of switch labels;
    if reverse then LSB first else MSB first }
  var
    s: array [Switch] of boolean; { s[b] == switch b is conducting }
    ph, w: integer; { ph = # phases; w = weight }
    a: Wire; b: Switch;
  begin
  for a := 1 to M do f[a] := 1 ;
  for b := 1 to N do s[b] := false ;
  w := 1 ; ph := 0 ; { w = 2^ph }
  while w < N do begin w := 2*w ; inc(ph) end ;
  if reverse then w := 1 else w := w div 2 ;
  while ph <> 0 do begin
    { adjust switches }
    for b := 1 to N do
      if odd((b-1) div w) <> s[b] then begin
        change(b) ;
        s[b] := not s[b]
        end { if } ;
    { adjust f }
    for a := 1 to M do
      if probe(a) then inc(f[a], w) ;
    if reverse then w := 2*w else w := w div 2 ;
    dec(ph)
    end { while }
  end { ReconstructBN } ;

procedure ReconstructBS(minimize, suppress: boolean);
  { uses Binary Search }
  var g: array [Wire] of record gL, gR: Switch end;

  procedure init_g;
    var a: Wire;
    begin
    for a := 1 to M do
      with g[a] do begin gL := 1 ; gR := N end
    end { init_g } ;

  procedure AllBS(L, R: Switch; p: boolean);
    { switches L..R are p-conducting }
    var a: Wire; b, h: Switch; s, t: integer;
    begin
    if L <> R then begin
      h := (L + R) div 2 ;
      if minimize then for b := h+1 to R do Change(b)
      else begin p := not p ; for b := L to h do Change(b) end ;
      { switches L..h are p-conducting }
      { switches h+1..R are non-p-conducting }
      s := 0 ; t := 0 ;
      for a := 1 to M do with g[a] do
        if (gL <= h) and (h <= gR) then
          if Probe(a) = p then begin
            gR := h ; inc(s) end
          else begin gL := h+1 ; inc(t) end ;
      if not suppress or (s > 0) then AllBS(L, h, p) ;
      if not suppress or (t > 0) then AllBS(h+1, R, not p)
      end { if }
    end { AllBS } ;

  procedure Convert;
    var a: Wire;
    begin
    for a := 1 to M do
      f[a] := g[a].gL
    end { Convert } ;

  begin
  init_g ;
  AllBS(1, N, false) ;
  Convert
  end { ReconstructBS } ;

procedure Reconstruct;
  begin
  case Method of
     1: ReconstructA ;
     2: ReconstructW1 ;
     3: ReconstructW2 ;
     4: ReconstructW3 ;
     5: ReconstructW4 ;
     6: ReconstructW5 ;
     7: ReconstructW6 ;
     8: ReconstructS1 ;
     9: ReconstructS2 ;
    10: ReconstructS3 ;
    11: ReconstructBN(true) ;
    12: ReconstructBN(false) ;
    13: ReconstructBS(false, false) ;
    14: ReconstructBS(false, true) ;
    15: ReconstructBS(true, false) ;
    16: ReconstructBS(true, true) ;
    else writeln(out, 'Unknown Method: ', Method: 1) ;
    end { case }
  end { Reconstruct } ;

procedure DoIt;
  begin
  repeat
    if Test then begin
      repeat
        write('Use method [1..', MaxMethod:1, ', 0 to stop]: ') ;
        readln(Method) ;
        until (0 <= Method) and (Method <= MaxMethod) ;
      end { if } ;
    if Method <> 0 then begin
      writeln(LogFile) ;
      writeln(LogFile, 'Method = ', Method:1) ;
      AskValues(M, N) ;
      if (M > 0) and (N > 0) then begin
        Reconstruct ;
        Done(f)
        end { if } ;
      end { if } ;
    if SingleCable then Method := 0
    until (Method = 0) or (M <= 0) or (N <= 0)
  end { DoIt } ;

begin
Init ;
DoIt ;
Fini
end.