PROGRAM nim;

CONST nmax = 8;
      kmax = 15;

TYPE spieler   = (mensch, computer);
     nimschale = ARRAY [1..nmax] OF 0..kmax;

VAR  n          : 2..nmax;
     schale     : nimschale;
     zug        : RECORD
                    schale : 1..nmax;
                    anzahl : 1..kmax
                  END;
     anderreihe : spieler;
     punkte     : integer;
     janein     : char;

{====================================================================}

PROCEDURE machspiel;

VAR i : 1..nmax;

BEGIN { machspiel }
  randomize;
  n := random (nmax-1)+2;
  FOR i := 1 TO n DO
    schale [i] := random (kmax)+1
END;  { machspiel }

{====================================================================}

PROCEDURE zeichneschale (x : integer);

VAR i, j : integer;

BEGIN { zeichneschale }
  gotoxy ((x-1)*10+1, 14);
  write ('\_____/');
  FOR i := 0 TO (kmax-1) DIV 5 DO
    BEGIN
      gotoxy ((x-1)*10+2, 13-I);
      FOR j := 1 TO 5 DO
        IF schale [x] >= i*5+j
          THEN
            write ('o')
          ELSE
            write (' ')
    END
END;  { zeichneschale }

{====================================================================}

PROCEDURE spielfeld;

VAR i : 1..nmax;
    j : 1..kmax;

BEGIN { spielfeld }
  FOR i := 1 TO n DO
    BEGIN
      zeichneschale (i);
      gotoxy ((i-1)*10+1, 15);
      write ('Schale ', i)
    END
END;  { spielfeld }

{====================================================================}

PROCEDURE menschenzug;

BEGIN { menschenzug }
  REPEAT
    gotoxy (1, 17);
    clreol;
    write ('Ihr Zug : von Schale ');
    read (zug.schale);
    write (' nehmen Sie ');
    read (zug.anzahl);
    write (' Koerner.');
  UNTIL (zug.schale <= n) AND (zug.schale > 0) AND (zug.anzahl > 0)
                          AND (schale [zug.schale]-zug.anzahl >= 0);
  schale [zug.schale] := schale [zug.schale]-zug.anzahl
END;  { menschenzug }

{====================================================================}

PROCEDURE computerzug;

VAR zugzahl : integer;

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

PROCEDURE zufallszug;

BEGIN { zufallszug }
  REPEAT
    zug.schale := random (n)+1
  UNTIL schale [zug.schale] > 0;
  zug.anzahl := random (schale [zug.schale])+1
END;  { zufallszug }

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

FUNCTION gewinnstellung : boolean;

VAR hilfsschale : nimschale;
    nimzahl     : integer;
    i           : 1..nmax;

BEGIN { gewinnstellung }
  hilfsschale := schale;
  hilfsschale [zug.schale] := hilfsschale [zug.schale]-zug.anzahl;
  nimzahl := hilfsschale [1];
  FOR i := 2 TO n DO
    nimzahl := nimzahl XOR hilfsschale [i];
  gewinnstellung := nimzahl = 0
END;  { gewinnstellung }

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

BEGIN { computerzug }
  zugzahl := 0;
  zug.schale := 1;
  zug.anzahl := 0;
  IF gewinnstellung
    THEN
      zufallszug
    ELSE
      REPEAT
        zufallszug;
        zugzahl := zugzahl+1
      UNTIL gewinnstellung OR (zugzahl > punkte);
  schale [zug.schale] := schale [zug.schale]-zug.anzahl;
  gotoxy (1, 18);
  clreol;
  write ('Ich nehme aus der ', zug.schale, '-ten Schale ',
                               zug.anzahl, ' Koerner.')
END;  { computerzug }

{====================================================================}

PROCEDURE abwechseln (VAR x : spieler);

BEGIN { abwechseln }
  IF x = mensch
    THEN
      x := computer
    ELSE
      x := mensch
END;  { abwechseln }

{====================================================================}

FUNCTION spielende : boolean;

VAR summe, i : integer;

BEGIN { spielende }
  summe := 0;
  FOR i := 1 TO n DO
    summe := summe+schale [i];
  spielende := summe = 0
END;  { spielende }

{====================================================================}

BEGIN { nim }
  punkte := 0;
  anderreihe := mensch;
  REPEAT
    clrscr;
    writeln ('*********':40);
    writeln ('*  NIM  *':40);
    writeln ('*********':40);
    machspiel;
    writeln ('Ihre Punktzehl : ':60, punkte);
    writeln ('Vor uns befinden sich ', n, ' Reisschalen.');
    write   ('Bei jedem Zug koennen aus einer Schale beliebig viele ');
    writeln ('Reiskoerner');
    writeln ('entnommen werden, mindestens jedoch eines.');
    write   ('Wer nicht mehr ziehen kannn, weil alle Schalen leer sind,');
    writeln (' hat verloren.');
    spielfeld;
    REPEAT
      IF anderreihe = mensch
        THEN
          menschenzug
        ELSE
          computerzug;
      zeichneschale (zug.schale);
      abwechseln (anderreihe)
    UNTIL spielende;
    gotoxy (1, 20);
    IF anderreihe = computer
      THEN
        BEGIN
          writeln ('Gratuliere, Sie haben gewonnen!');
          punkte := punkte+5
        END
      ELSE
        BEGIN
          writeln ('Sie haben leider verloren!');
          punkte := punkte-3
        END;
    gotoxy (1, 22);
    write ('Noch ein Spiel ? ');
    REPEAT
      read (kbd, janein)
    UNTIL janein IN ['j', 'J', 'n', 'N']
  UNTIL janein IN ['n', 'N']
END.  { nim }
