unit Cables;

interface

const
  MequN = true; { # wires = # switches }
  MaxN = 90;
  MaxM = 90;

type
  Wire = 0..MaxM ; { actually Wire = 1..M, for some M }
  Switch = 0..MaxN ; { actually Switch = 1..N, for some N }
  SwitchSet = set of Switch ;
  Connectivity = array [Wire] of Switch ;
  { For f: Connectivity, wire a is connected to switch b == f[a]=b }

  Cable = record
    M: Wire; { M = # wires }
    N: Switch; { N = # switches }
    f: Connectivity;
    end { Cable } ;

  Command = (probeCmd, changeCmd, doneCmd);

const
  probeChr  = 'T';
  changeChr = 'C';
  doneChr   = 'D';
  noChr     = 'N';
  yesChr    = 'Y';

function Log2(n: word): integer;
function Card(const s: SwitchSet; n: integer): word;
function Mu(const s: SwitchSet): Switch ;
function RandomSwitch(const s: SwitchSet; n: integer): Switch;
procedure WriteSwitches(var out: text; const s: SwitchSet; n: integer;
                        newline: boolean);
procedure ShowCable(var out: text; const C: Cable; long: boolean);

implementation

function Log2(n: word): integer;
  { ret: base-two logarithm of n rounded up, or -1 if n = 0 }
  var k: integer;
  begin
  if n = 0 then Log2 := -1
  else begin
    k := 0 ;
    while n <> 1 do begin n := (n+1) div 2 ; inc(k) end ;
    Log2 := k
    end { else }
  end { Log2 } ;

function Card(const s: SwitchSet; n: integer): word;
  { pre: s is subset of [1..n] }
  { ret: #s (cardinality of s) }
  var b: Switch; k: word;
  begin
  k := 0 ;
  for b := 1 to n do inc(k, ord(b in s)) ;
  Card := k
  end { Card } ;

function Mu(const s: SwitchSet): Switch;
  { pre: Card(s) = 1 }
  { ret: the element in s }
  var b: Switch;
  begin
  b := 1 ;
  while not (b in s) do inc(b) ;
  Mu := b
  end { Mu } ;

function RandomSwitch(const s: SwitchSet; n: integer): Switch;
  { pre: s <> [ ] }
  { ret: any element in s }
  var b: Switch; k: integer;
  begin
  k := Random(Card(s, n))+1 ;
  b := 1 ;
  repeat
    while not (b in s) do inc(b) ;
    dec(k)
    until k = 0 ;
  RandomSwitch := b
  end { RandomSwitch } ;

procedure WriteSwitches(var out: text; const s: SwitchSet; n: integer;
                        newline: boolean);
  { pre: s is subset of [1..n] }

  var b: Switch; sep: string;
  begin
  write(out, '[') ; sep := '' ;
  for b := 1 to n do
    if b in s then begin
      write(out, sep, b:1) ;
      sep := ', '
      end { if } ;
  write(out, ']') ;
  if newline then writeln(out)
  end { WriteSwitches } ;

procedure ShowCable(var out: text; const C: Cable; long: boolean);
  { show histogram of multiplicities }
  var
    a: Wire; b: Switch; i: 0..MaxN;
    t: array [Switch] of integer; { t[b] = # a:Wire | C.f[a]=b }
    tt: array [0..MaxN] of integer; { tt[i] = # b:Switch | t[b]=i }
  begin
  with C do begin
    writeln(out, 'Cable with ', M:1, ' wires and ', N:1, ' switches') ;
    for b := 1 to N do t[b] := 0 ;
    for a := 1 to M do inc(t[f[a]]) ;
    for i := 0 to N do tt[i] := 0 ;
    for b := 1 to N do inc(tt[t[b]]) ;
    if long then begin
      writeln(out, '  Wire --> Switch Connectivity:') ;
      for a := 1 to M do begin
        if a mod 10 = 1 then write(out, '   ') ;
        write(out, f[a]:4) ;
        if a mod 10 = 0 then writeln(out)
        else if a mod 5 = 0 then write(out, '   ')
        end { for a } ;
      if M mod 10 <> 0 then writeln(out) ;
      writeln(out, '  Switch Multiplicity:') ;
      for b := 1 to N do begin
        if b mod 10 = 1 then write(out, '   ') ;
        write(out, t[b]:4) ;
        if b mod 10 = 0 then writeln(out)
        else if b mod 5 = 0 then write(out, '   ')
        end { for b } ;
      if N mod 10 <> 0 then writeln(out)
      end { if long } ;
    writeln(out, '  Multiplicity Multiplicity:') ;
    { # nonzero tt[i] is at most MAX k | k*(k+1)/2 <= N @ k }
    { for N=100 this yields 13, viz. 13*14/2 = 91, 14*15/2=105 }
    write(out, '    Sw.Mult.:') ;
    for i := 0 to N do
      if tt[i] <> 0 then write(out, i:4) ;
    writeln(out) ;
    write(out, '        #   :') ;
    for i := 0 to N do
      if tt[i] <> 0 then write(out, tt[i]:4) ;
    writeln(out)
    end { with C }
  end { ShowCable } ;

begin
end.