Universität Ulm, Fakultät für Mathematik und Wirtschaftswissenschaften, SAI

SS 99 || Ferienprojekt zu Allgemeine Informatik II || Puzzle Library

MODULE Matches


MODULE Matches;

   IMPORT ChessClocks, Clocks, Cmds, Conclusions, Conditions, ConstStrings,
      Errors, EventConditions, Events, InetTCP, Iterators, Names, Networks,
      Paths, Print, Process, Puzzle, PuzzleGames, PuzzleIO, PuzzlePlayers,
      Read, RelatedEvents, RemoteChessClocks, RemoteEvents, RemoteObjects,
      RemotePGs, RemotePuzzlePlayers, RobustObjects, Services,
      StandardPuzzleGames, Streams, Strings, SysSignals, Tasks, Terminals,
      Times, UnixNames, UnixTerminals, Write;

   CONST
      prompt = ": ";

   CONST
      playerdir = "/etc/puzzle/players";
      gamedir = "/etc/puzzle/games";

   VAR
      errors: RelatedEvents.Object;

   PROCEDURE OpenAllKindsOfPorts;
      VAR
	 network: Networks.Network;
	 it: Iterators.Iterator;
	 port: Networks.Socket;
	 address: Networks.Address;
	 errors: RelatedEvents.Object;
   BEGIN
      NEW(errors); RelatedEvents.QueueEvents(errors);
      Networks.GetNetworks(it);
      WHILE Iterators.Get(it, network) DO
	 IF ~Networks.CreateSomeSocket(port, network, address, errors) OR
	       ~RemoteObjects.AddPort(port, address, errors) THEN
	    Conclusions.Conclude(errors, Errors.error, "open ports");
	 END;
      END;
   END OpenAllKindsOfPorts;

   PROCEDURE MakePath(dir, name: ARRAY OF CHAR; VAR path: ARRAY OF CHAR);
   BEGIN
      COPY(dir, path);
      Strings.Concatenate(path, "/");
      Strings.Concatenate(path, name);
   END MakePath;

   PROCEDURE CheckExistance(path: ARRAY OF CHAR) : BOOLEAN;
      VAR
	 node: Names.Node;
   BEGIN
      IF ~Paths.GetNode(path, NIL, errors, node) THEN
	 Conclusions.Conclude(errors, Errors.error, path);
	 RETURN FALSE
      END;
      RETURN TRUE
   END CheckExistance;

   PROCEDURE ListDir(dir: ARRAY OF CHAR);
      VAR
	 dirnode: Names.Node;
	 members: Iterators.Iterator;
	 member: ConstStrings.String;
   BEGIN
      IF ~Paths.GetNode(dir, NIL, errors, dirnode) THEN
	 Conclusions.Conclude(errors, Errors.error, dir);
      END;
      IF ~Names.GetMembers(dirnode, NIL, members) THEN
	 Conclusions.Conclude(dirnode, Errors.error, dir);
      END;
      WHILE Iterators.Get(members, member) DO
	 ConstStrings.Write(Streams.stdout, member); Write.Ln;
      END;
   END ListDir;

   PROCEDURE GameListing;
      VAR
	 dirnode: Names.Node;
	 gameType: Services.Type;
	 members: Iterators.Iterator;
	 member: ConstStrings.String;
	 match: ARRAY 80 OF CHAR;
	 path: ARRAY 512 OF CHAR;
	 game: PuzzleGames.Game;
	 name: ARRAY 2, 80 OF CHAR;
	 situation: Puzzle.Situation;
	 chessclock: ChessClocks.ChessClock;

      PROCEDURE PrintTimeOfClock(index: SHORTINT);
	 VAR
	    clock: Clocks.Clock;
	    time: Times.Time;
	    timeval: Times.TimeValueRec;
      BEGIN
	 ChessClocks.GetClock(chessclock, index, clock);
	 Clocks.GetTime(clock, time);
	 Times.GetValue(time, timeval);
	 Print.F2(" [%02d:%02d]",
		  timeval.second DIV 60, timeval.second MOD 60);
      END PrintTimeOfClock;

   BEGIN (* GameListing *)
      IF ~Paths.GetNode(gamedir, NIL, errors, dirnode) THEN
	 Conclusions.Conclude(errors, Errors.error, gamedir);
      END;
      IF ~Names.GetMembers(dirnode, NIL, members) THEN
	 Conclusions.Conclude(dirnode, Errors.error, gamedir);
      END;
      WHILE Iterators.Get(members, member) DO
	 ConstStrings.Extract(match, member);
	 MakePath(gamedir, match, path);
	 Services.SeekType("PuzzleGames.Game", gameType);
	 IF ~RobustObjects.GuardedImport(game, gameType, path, NIL, errors) THEN
	    Conclusions.Conclude(errors, Errors.error, path); RETURN
	 END;
	 PuzzleGames.GetNames(game, name[0], name[1]);
	 PuzzleGames.GetCurrentSituation(game, situation);
	 Print.F1("%-16s ", match);
	 IF Puzzle.Finished(situation) THEN
	    Print.F("F");
	 ELSE
	    Print.F("R");
	 END;
	 Print.F2(" %02d:%02d",
	    Puzzle.NumberOfPieces(situation, 0),
	    Puzzle.NumberOfPieces(situation, 1));
	 PuzzleGames.GetChessClock(game, chessclock);
	 IF chessclock # NIL THEN
	    PrintTimeOfClock(0); PrintTimeOfClock(1);
	 ELSE
	    Write.String("        "); Write.String("        ");
	 END;
	 Print.F2(" %s vs %s\n", name[0], name[1]);
      END;
   END GameListing;

   PROCEDURE Replay(match: ARRAY OF CHAR);
      VAR
	 path: ARRAY 512 OF CHAR;
	 gameType: Services.Type;
	 game: PuzzleGames.Game;
	 name: ARRAY 2 OF ARRAY 80 OF CHAR;
	 situation: Puzzle.Situation;
	 it: Iterators.Iterator;
	 move: Puzzle.Move;
	 answer: ARRAY 10 OF CHAR;
   BEGIN
      MakePath(gamedir, match, path);
      IF ~CheckExistance(path) THEN RETURN END;
      Services.SeekType("PuzzleGames.Game", gameType);
      IF ~RobustObjects.GuardedImport(game, gameType, path, NIL, errors) THEN
	 Conclusions.Conclude(errors, Errors.error, path); RETURN
      END;
      PuzzleGames.GetNames(game, name[0], name[1]);
      Write.String(name[0]); Write.String(" vs "); Write.String(name[1]);
      Write.Line(":");

      Puzzle.CreateSituation(situation);
      PuzzleGames.IterateMoves(game, it);
      PuzzleIO.PrintSituation(Terminals.console, situation);
      WHILE Iterators.Get(it, move) &
	    Puzzle.Valid(situation, move, Puzzle.Onturn(situation)) DO
	 Write.String("Continue? "); Read.Line(answer);
	 IF answer[0] = "n" THEN RETURN END;
	 PuzzleIO.PrintMove(Terminals.console, move); Write.Ln;
	 Puzzle.MakeMove(situation, move, Puzzle.Onturn(situation));
	 PuzzleIO.PrintSituation(Terminals.console, situation);
      END;
   END Replay;

   PROCEDURE Kiebitz(match: ARRAY OF CHAR; wait: BOOLEAN);
      VAR
	 path: ARRAY 512 OF CHAR;
	 gameType: Services.Type;
	 game: PuzzleGames.Game;
	 name: ARRAY 2 OF ARRAY 80 OF CHAR;
	 situation: Puzzle.Situation;
	 eventType: Events.EventType; event: Events.Event;
	 eventcond, termcond: Conditions.Condition;
	 conditions: Conditions.ConditionSet;
   BEGIN
      MakePath(gamedir, match, path);
      IF ~wait & ~CheckExistance(path) THEN RETURN END;
      Services.SeekType("PuzzleGames.Game", gameType);
      IF ~RobustObjects.GuardedImport(game, gameType, path, NIL, errors) THEN
	 Conclusions.Conclude(errors, Errors.error, path); RETURN
      END;
      PuzzleGames.GetNames(game, name[0], name[1]);
      Write.String(name[0]); Write.String(" vs "); Write.String(name[1]);
      Write.Line(":");
      PuzzleGames.GetCurrentSituation(game, situation);
      PuzzleIO.PrintSituation(Streams.stdout, situation);
      PuzzleGames.TakeInterest(game, eventType);


      EventConditions.Create(eventcond, eventType);
      EventConditions.Create(termcond, SysSignals.INT);
      Conditions.CreateSet(conditions);
      Conditions.Incl(conditions, eventcond);
      Conditions.Incl(conditions, termcond);

      Write.Line("Press CTRL-c to abort kiebitz mode.");

      LOOP
	 Tasks.WaitForOneOf(conditions);
	 IF Conditions.Test(termcond, NIL) THEN EXIT END;
	 WHILE EventConditions.TestAndGet(eventcond, event) DO
	    IF event IS PuzzleGames.Event THEN
	       WITH event: PuzzleGames.Event DO
		  PuzzleIO.PrintMove(Streams.stdout, event.move); Write.Ln;
		  PuzzleIO.PrintSituation(Streams.stdout, event.situation);
	       END;
	    END;
	 END;
      END;
      EventConditions.Drop(eventcond);
      EventConditions.Drop(termcond);
   END Kiebitz;

   PROCEDURE Match(player1, player2, match: ARRAY OF CHAR;
                   timelimit: Times.Time);

      VAR
	 pl1, pl2: PuzzlePlayers.Player;
	 path1, path2, matchpath: ARRAY 512 OF CHAR;
	 playerType: Services.Type;
	 game: PuzzleGames.Game;

   BEGIN (* Match *)
      MakePath(playerdir, player1, path1);
      MakePath(playerdir, player2, path2);
      IF ~CheckExistance(path1) OR ~CheckExistance(path2) THEN RETURN END;
      Services.SeekType("PuzzlePlayers.Player", playerType);
      IF ~RobustObjects.GuardedImport(pl1, playerType, path1, NIL, errors) THEN
	 Conclusions.Conclude(errors, Errors.error, path1); RETURN
      END;
      IF ~RobustObjects.GuardedImport(pl2, playerType, path2, NIL, errors) THEN
	 Conclusions.Conclude(errors, Errors.error, path2); RETURN
      END;

      StandardPuzzleGames.Create(game, pl1, pl2, player1, player2, timelimit);

      MakePath(gamedir, match, matchpath);
      IF ~RobustObjects.Export(game, NIL, matchpath, NIL, errors) THEN
	 Conclusions.Conclude(errors, Errors.error, matchpath);
      END;
   END Match;

   PROCEDURE DoCmds;
      CONST
	 matchC = 0; quitC = 1; gamesC = 2; playersC = 3; kiebitzC = 4;
	 replayC = 5;
      VAR
	 s: Streams.Stream;
	 nfields: INTEGER;
	 fields: ARRAY 4 OF ARRAY 80 OF CHAR;
	 timelimit: Times.Time; tls: Streams.Stream; tli: INTEGER;
	 wait: BOOLEAN;
   BEGIN
      s := Streams.stdin;
      Cmds.Add(s, gamesC, "games", 0, 1, "[-l]", "list running games");
      Cmds.Add(s, kiebitzC, "kiebitz", 1, 2, "[-w] name",
	 "look at running game");
      Cmds.Add(s, matchC, "match", 3, 4, "name pl1 pl2 [timelimit]",
         "initiate a match (with given name)");
      Cmds.Add(s, playersC, "players", 0, 0, "", "list active players");
      Cmds.Add(s, quitC, "quit", 0, 0, "", "leave this program");
      Cmds.Add(s, replayC, "replay", 1, 1, "name", "replay game");
      LOOP
	 Write.String(": ");
	 CASE Cmds.Read(s, nfields, fields) OF
	 | Cmds.done, Cmds.empty:
	 | Cmds.error: EXIT
	 | Cmds.unknown:
	       Write.Line("Unknown command. Please try ``help''.");
	 | gamesC:
	       IF nfields = 0 THEN
		  ListDir(gamedir);
	       ELSIF fields[0] = "-l" THEN
		  GameListing;
	       ELSE
		  Write.Line("Invalid option.");
	       END;
	 | kiebitzC:
	       IF nfields = 1 THEN
		  Kiebitz(fields[0], FALSE);
	       ELSIF fields[0] = "-w" THEN
		  Kiebitz(fields[1], TRUE);
	       ELSE
		  Write.Line("Invalid option.");
	       END;
	 | matchC:
	       IF nfields = 3 THEN
		  timelimit := NIL;
	       ELSE
		  Strings.Open(tls, fields[3]); Read.IntS(tls, tli);
		  Streams.Release(tls);
		  Times.CreateAndSet(timelimit, Times.relative, 0, tli, 0);
	       END;
	       Match(fields[1], fields[2], fields[0], timelimit);
	 | playersC: ListDir(playerdir);
	 | quitC: EXIT
	 | replayC: Replay(fields[0]);
	 END;
      END;
   END DoCmds;

BEGIN
   OpenAllKindsOfPorts;
   Streams.stdout := Terminals.console;
   NEW(errors); RelatedEvents.QueueEvents(errors);
   DoCmds;
   Process.Exit(0);
END Matches.

SS 99 || Ferienprojekt zu Allgemeine Informatik II || Puzzle Library

Andreas Borchert, 26. Juli 1999