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

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

MODULE StandardPuzzleGames


MODULE StandardPuzzleGames;

   IMPORT ChessClocks, ConstStrings, Events, Iterators, Jobs, Objects,
      Puzzle, PuzzleGames, PuzzlePlayers, Services, Shards,
      StandardChessClocks, Times, VolatileShards;

   TYPE
      ListOfMoves = POINTER TO ListOfMovesRec;
      ListOfMovesRec =
	 RECORD
	    (Objects.ObjectRec)
	    move: Puzzle.Move;
	    next: ListOfMoves;
	 END;

   TYPE
      Game = POINTER TO GameRec;
      GameRec =
	 RECORD
	    (PuzzleGames.GameRec)
	    player1, player2: PuzzlePlayers.Player;
	    name1, name2: ConstStrings.String;
	    currentSituation: Puzzle.Situation;
	    moves, tail: ListOfMoves;
	    eventType: Events.EventType;
	    chessclock: ChessClocks.ChessClock;
	    numberOfMoves: INTEGER;
	    pot: Shards.Pot; lid: Shards.Lid; (* of the chess clock *)
	 END;

   VAR
      if: PuzzleGames.Interface;
      type: Services.Type;

   TYPE
      Job = POINTER TO JobRec;
      JobRec =
	 RECORD
	    (Jobs.JobRec)
	    game: Game;
	 END;

   PROCEDURE GetNames(game: PuzzleGames.Game; VAR name1, name2: ARRAY OF CHAR);
   BEGIN
      WITH game: Game DO
	 ConstStrings.Extract(name1, game.name1);
	 ConstStrings.Extract(name2, game.name2);
      END;
   END GetNames;

   PROCEDURE GetCurrentSituation(game: PuzzleGames.Game;
                                 VAR situation: Puzzle.Situation);
   BEGIN
      WITH game: Game DO
	 Puzzle.CopySituation(situation, game.currentSituation);
      END;
   END GetCurrentSituation;

   PROCEDURE GetChessClock(game: PuzzleGames.Game;
                           VAR chessclock: ChessClocks.ChessClock);
   BEGIN
      WITH game: Game DO
	 chessclock := game.chessclock;
      END;
   END GetChessClock;

   PROCEDURE TakeInterest(game: PuzzleGames.Game;
                          VAR eventType: Events.EventType);
   BEGIN
      WITH game: Game DO
	 IF game.eventType = NIL THEN
	    Events.Define(game.eventType);
	 END;
	 eventType := game.eventType;
      END;
   END TakeInterest;

   PROCEDURE MoveIterator(it: Iterators.Iterator;
                          ref: Iterators.Reference; mode: Iterators.Mode);
      VAR
	 element: ListOfMoves;
   BEGIN
      IF ref # NIL THEN
	 element := ref(ListOfMoves);
	 WHILE element # NIL DO
	    Iterators.Yield(it, element.move);
	    element := element.next;
	 END;
      END;
   END MoveIterator;

   PROCEDURE IterateMoves(game: PuzzleGames.Game;
                          VAR it: Iterators.Iterator);
   BEGIN
      WITH game: Game DO
	 Iterators.Create(it, MoveIterator, game.moves, 0);
      END;
   END IterateMoves;

   PROCEDURE InitModule;
   BEGIN
      Services.CreateType(type, "StandardPuzzleGames.Game", "PuzzleGames.Game");
      NEW(if);
      if.getNames := GetNames;
      if.getCurrentSituation := GetCurrentSituation;
      if.getChessClock := GetChessClock;
      if.takeInterest := TakeInterest;
      if.iterateMoves := IterateMoves;
   END InitModule;

   PROCEDURE RunGame(job: Jobs.Job);
      VAR
	 game: Game;
	 ok: BOOLEAN;
	 onturn: PuzzlePlayers.Player;
	 clockIndex: SHORTINT;
	 element: ListOfMoves;
	 move: Puzzle.Move;
	 event: PuzzleGames.Event;
   BEGIN
      game := job(Job).game;
      IF game.chessclock # NIL THEN
	 ok := ChessClocks.Start(game.chessclock, game.lid); ASSERT(ok);
      END;
      LOOP (* until game is over or one of the participants gives up *)
	 IF Puzzle.Finished(game.currentSituation) THEN EXIT END;
	 CASE Puzzle.Onturn(game.currentSituation) OF
	 | Puzzle.player1: onturn := game.player1; clockIndex := 0;
	 | Puzzle.player2: onturn := game.player2; clockIndex := 1;
	 END;
	 IF game.chessclock # NIL THEN
	    ok := ChessClocks.Switch(game.chessclock, game.lid, clockIndex);
	    ASSERT(ok);
	 END;
	 IF ~PuzzlePlayers.MakeMove(onturn, game.currentSituation,
	                            game.chessclock, game, move) THEN
	    EXIT
	 END;
	 (* add it to the list of moves (even if not valid!) *)
	 NEW(element); element.move := move; element.next := NIL;
	 IF game.moves = NIL THEN
	    game.moves := element;
	 ELSE
	    game.tail.next := element;
	 END;
	 game.tail := element;
	 IF ~Puzzle.Valid(game.currentSituation, move,
	                  Puzzle.Onturn(game.currentSituation)) THEN
	    EXIT
	 END;
	 Puzzle.MakeMove(game.currentSituation, move,
	                 Puzzle.Onturn(game.currentSituation));
	 IF game.eventType # NIL THEN
	    NEW(event);
	    event.type := game.eventType;
	    event.game := game;
	    event.moveNumber := game.numberOfMoves;
	    event.move := move;
	    Puzzle.CopySituation(event.situation, game.currentSituation);
	    Events.Raise(event);
	 END;
	 INC(game.numberOfMoves);
      END;
      IF game.chessclock # NIL THEN
	 ok := ChessClocks.Stop(game.chessclock, game.lid); ASSERT(ok);
      END;
      PuzzlePlayers.GameOver(game.player1, game);
      PuzzlePlayers.GameOver(game.player2, game);
   END RunGame;

   (* === exported constructor ============================================ *)

   PROCEDURE Create(VAR game: PuzzleGames.Game; 
                    player1, player2: PuzzlePlayers.Player;
		    name1, name2: ARRAY OF CHAR;
		    timelimit: Times.Time);
      VAR
	 newgame: Game;
	 job: Job;
   BEGIN
      NEW(newgame); Services.Init(newgame, type);
      PuzzleGames.Init(newgame, if);
      newgame.player1 := player1; newgame.player2 := player2;
      ConstStrings.Create(newgame.name1, name1);
      ConstStrings.Create(newgame.name2, name2);
      Puzzle.CreateSituation(newgame.currentSituation);
      newgame.moves := NIL; newgame.tail := NIL; newgame.numberOfMoves := 0;
      newgame.eventType := NIL;
      VolatileShards.Create(newgame.pot, newgame.lid);
      IF timelimit = NIL THEN
	 newgame.chessclock := NIL;
      ELSE
	 StandardChessClocks.Create(newgame.chessclock,
	    newgame.pot, 2, timelimit);
      END;
      IF ~PuzzlePlayers.Accept(player1, newgame) OR
	 ~PuzzlePlayers.Accept(player1, newgame) THEN RETURN
      END;
      NEW(job); job.game := newgame; Jobs.Submit(job, RunGame);
      game := newgame;
   END Create;

BEGIN
   InitModule;
END StandardPuzzleGames.

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

Andreas Borchert, 26. Juli 1999