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