Suche Home Einstellungen Anmelden Hilfe  

Projekt "Game of Life" - Entwurf


1. Wahl der Programmiersprache

Gem. Vorgabe ist das System in der Programmiersprache Java zu entwickeln. Da Alternativen nicht zugelassen sind, entfallen in den folgenden Abschnitten die üblicherweise erforderliche Überlegungen zur Wahl einer Implementierunsgsprache.

2. Gestaltung der Benutzungsoberfläche

Gem. Anforderungsdefinition sind folgende Funktionalitäten auf der Benutzungsoberfläche bereitzustellen:

Eingaben

Ausgaben

Die Wahl der Benutzungsoberfläche fällt auf ein Bildschirmfenster, das alle o.g. Ein- und Ausgaben übersichtlich gegliedert darstellt. Ein- und Ausgaben werden funktional und inhaltlich zu Gruppen zusammengefaßt und auf dem Fenster angezeigt. Das wichtigste Ausgabeelement, die Spielfeldsimulation, wird dabei in das Zentrum gerückt, alle übrigen Bedienelemente werden an der oberen Fensterseite plaziert.
Abb. 2-1 zeigt den Entwurf der Benutzungsoberfläche, links oben befinden sich die Knöpfe, in der Mitte die Radioknöpfe für die Einstellung der Anzeigegröße, rechts die Textfelder für die Eingabe. Unmittelbar über dem Spielfeld ist ein Hilfetext zu sehen, wie er beim Überstreichen des Knopfes "Stop" angezeigt wird.

Abb. 2-1: Entwurf der Benutzungsoberfläche

3. Grobstruktur des Systems

Gem. Anforderungsdefinition ist das System mausgesteuert. Dies legt eine Struktur des Systems nahe, bei dem die für die Berechnung des Game of Life erforderlichen Objekte und Operationen sowie die für die Benutzungsoberfläche, also für Ein- und Ausgabe einschl. zugehöriger Fehlerbehandlung, erforderlichen Objekte und Operationen in getrennten Klassen untergebracht werden. Hinzu kommt eine Klasse für den Start des Programms, in dem die Methode main definiert wird.
Als Bezeichner für die drei Klassen wird gewählt: Das Zusammenspiel der drei Klassen zeigt die Darstellung in Abb. 3-1.

Abb. 3-1: Zusammenspiel der Klassen starteGame, GameFenster, Game

4. Klasse Game

Die Klasse Game stellt Objekte und Methoden für die Verwaltung des Spielfelds bestehend aus lebenden und toten Zellen bereit. Wesentliche Aufgaben sind die Initialisierung des Spielfelds und die Berechnung von Folgekonfigurationen.

4.1. Datenstruktur

Bei dem Spielfeld handelt es sich um eine 2-dimensionale Matrix der Größe nxm Zellen, wobei jede Zelle aus einer lebenden oder einer toten Zelle besteht. Naheliegend ist die Implementierung durch ein 2-dimensionales Array. Da die zu erwartenden bzw. überhaupt durch den Benutzer wählbaren Spielfeldgrößen eine überschaubare Größe nicht überschreiten, kann das gesamte Spielfeld im Hauptspeicher gehalten werden. Überlegungen zur Reduktion des Speicherbedarfs, etwa durch Implementierung des Spielfelds als dünnbesetzte Matrix, können entfallen.

Auf dieser Grundlage ist eine Reihe unterschiedlicher Implementierungsalternativen denkbar, die jeweils spezifische Vor- und Nachteile besitzen:

  1. Abspeicherung einer Generation in einem Array der Größe nxm vom Typ boolean:
  2. Abspeicherung einer Generation in einem Array der Größe (n+2)x(m+2) vom Typ boolean:
  3. Realisierung durch zwei Arrays vom Typ boolean:
  4. Realisierung durch ein Array eines Aufzählungstyps mit vier Elementen (tot, lebendig, wird_tot, wird_lebendig):
Variante 1 und Variante 2 werden hinsichtlich Aufwand und Ersparnis als gleichwertig eingeschätzt. Variante 4 reduziert zwar - obwohl nicht zwingend erforderlich - den Speicherbedarf, erhöht jedoch den Implementierungsaufwand.
Für das geplante System wird daher eine Datenstruktur gem. Variante 1 in Kombination mit Variante 3 gewählt, wobei die booleschen Werte false bzw. true tote bzw. lebendige Zellen markieren.
Als weitere Datenelemente für die Verwaltung des Spielfelds werden verwendet:

4.2. Methoden

Auf der in 4.1 gewählten Datenstruktur sind folgende Methoden zu implementieren:
Konstruktor:
Initialisierungsmethoden:
Methoden für Generationswechsel:
Die Struktur der Klasse Game zeigt Abb. 4-1. Die vollständige Spezifikation der Klasse befindet sich im Anhang.

Abb. 4-1: Struktur der Klasse Game

5. Klasse GameFenster

Die Klasse verwaltet die Ein- und Ausgabe des Systems und stellt die dazu benötigten Objekte und Methoden bereit. Entsprechend der Anforderungsdefinition nach einer mausorientierten, möglichst einfachen Bedienung des Systems wird die Fenstertechnik eingesetzt. Ein durch die Klasse erzeugtes Fenster enthält Schaltflächen und Eingabefelder für die Steuerung des Programms durch den Benutzer, Textfelder zur Kommentierung, als Bedienungshilfe und für Fehlermeldungen sowie einen Bereich für die Ausgabe der jeweiligen Spielsituation als Matrix von lebenden und toten Zellen.
Ferner startet die Klasse die Simulation durch Aktivierung der Klasse Game.

5.1. Datenstrukturen

Die Aufgaben der Klasse bestehen vorrangig in der Reaktion auf elementare Ereignisse (z.B. Mausklicks, Texteingaben). Die Datenhaltung ist folglich sehr einfach; sie besteht im wesentlichen aus der Speicherung von Eingaben in elementaren Variablen oder Textfeldern, die der Benutzer zu Beginn oder im Verlauf der Spielsimulation vornimmt.
Folgende Eingaben sind zu speichern; die zugehörigen Eingabewerte werden in Variablen passenden Typs abgelegt: Bei Fehleingaben, wie Werten falschen Typs, werden Fehlermeldungen ausgegeben.

5.2. Methoden

Entsprechend der Vorgabe, eine mausorientierte Bedienungsoberfläche zu erstellen, wird zur Realisierung eine Ereignissteuerung gewählt. Sie gestattet es dem Benutzer, zu beliebigen Zeiten in den Simulationslauf eines Spiels einzugreifen und Eingaben vorzunehmen, ohne Eingabeaufforderungen des Systems abwarten zu müssen. Eingaben werden vom System sofort verarbeitet und ggf. für den weiteren Simulationsverlauf verwendet.

Dazu wird eine Reihe von Methoden als Ereignishandler implementiert. Sie werden bei allen Benutzereingaben, seien es Klicken auf Knöpfe oder Eingaben in Textfelder, aufgerufen, analysieren die entsprechenden Ereignisse und aktivieren die dafür vorgesehenen Methoden für die weitere Bearbeitung der Ereignisse.
Folgende Ereignisse sind auf der Benutzungsoberfläche vorgesehen, die jeweils durch eine zugehörige Handler-Methode bearbeitet wird:

5.2.1. Arbeitsweise der Methoden im Detail

Konstruktor:
Initialisierungsmethoden:
Ereignishandler:
Methoden zur Weiterverarbeitung von Ereignissen:
Die Struktur der Klasse GameFenster zeigt Abb. 5-1. Die vollständige Spezifikation der Klasse befindet sich im Anhang.

Abb. 5-1: Struktur der Klasse GameFenster

6. Klasse starteGame

Die einzige Aufgabe dieser Klasse besteht darin, ein neues Fenster zu erzeugen und anzuzeigen. Dazu wird der Konstruktor GameFenster der gleichnamigen Klasse aufgerufen, eine Instanz dieser Klasse erzeugt und mit dem Bezeichner "neu" benannt. Als aktuelle Parameter für GameFenster werden die festen Werte verwendet. Alle Werte können vom Benutzer anschließend im Dialog abgeändert werden. Die vollständige Spezifikation der Klasse befindet sich im Anhang.



 

Anhang

Klasse Game

Funktion: Bereitstellung von einer Methode zur Belegung eines Feldes mit toten und lebenden Zellen sowie Methoden zur Berechnung der neuen Generation

Instanzvariablen:

Verwendet von: class GameFenster

Verwendete Klassen: keine

Autor: Nina Schumer Datum: 04.09.2001


Konstruktor: Game

Funktion: Konstruktor, erstellt eine neue Game-Population (tot)

Parameter:

Aufgerufen von: Konstruktor in class GameFenster

Verwendung folgender globaler Variablen: feld[][][], n, m, anzahl

Benutzte Methoden: initializeMatrix(), initializeGeneration()


Methode: initializeMatrix

Funktion: Initialisiert die Populationsmatrix mit toten Zellen

Parameter: keine

Aufgerufen von: Game-Konstruktor in class GameFenster: actionPerformed(ActionEvent) bei Betätigung des "Löschen"-Buttons

Verwendung folgender globaler Variablen: feld[][][], n, m

Benutzte Methoden: keine


Methode: randomMatrix

Funktion: Belebung von "anzahl" zufällig ausgewählten Zellen in der Populationsmatrix

Parameter: keine

Aufgerufen von: in class GameFenster: actionPerformed(ActionEvent) bei Betätigung des "Zufall"-Buttons

Verwendung folgender globaler Variablen: feld[][][], n, m

Benutzte Methoden: keine


Methode: nextGeneration

Funktion: Berechnet die nächste Generation der Population nach den vorgegebenen Regeln

Parameter: keine

Aufgerufen von: in class GameFenster: run() (wenn die Simulation läuft)

Verwendung folgender globaler Variablen: feld[][][], n, m

Benutzte Methoden: countNeighbours(int, int), incGeneration()


Methode: isSet

Funktion: Liefert true zurück, wenn die angegebene Zelle lebt, andernfalls (oder falls die Koordinaten außerhalb der Arraygrenzen liegen) false

Parameter: x, y / Koordinaten der Zelle, welche nach Lebendigkeit geprüft wird

Aufgerufen von:
in class GameFenster: mousePressed(MouseEvent) bei MouseClick auf die grafische Darstellung des Feldes, um eine Zelle zu beleben bzw zu töten

Verwendung folgender globaler Variablen: feld[][][]

Benutzte Methoden: keine


Methode: setXY

Funktion: Belebt eine Zelle

Parameter: x, y / Koordinaten der Zelle, welche belebt wird

Aufgerufen von:
in class GameFenster: mousePressed(MouseEvent),mouseDragged(MouseEvent) bei MouseClick und Ziehen auf der grafischen Darstellung des Feldes, um Zellen zu beleben

Verwendung folgender globaler Variablen: feld[][][]

Benutzte Methoden: keine


Methode: deleteXY

Funktion: Tötet eine Zelle

Parameter: x, y / Koordinaten der Zelle, welche getötet wird

Aufgerufen von:
in class GameFenster: mousePressed(MouseEvent),
mouseDragged(MouseEvent)
bei MouseClick und Ziehen auf der grafischen Darstellung des Feldes, um Zellen zu töten

Verwendung folgender globaler Variablen: feld[][][]

Benutzte Methoden: keine


Methode: countNeighbours

Funktion: Zählt die Nachbarzellen einer Zelle

Parameter: x, y / Koordinaten dieser Zelle

Aufgerufen von: nextGeneration()

Verwendung folgender globaler Variablen: feld[][][]

Benutzte Methoden: keine


Methode: initializeGeneration

Funktion: Initialisiert generation mit 1

Parameter: keine

Aufgerufen von: Game-Konstruktor
in class GameFenster: actionPerformed(ActionEvent)
Betätigung des "Zufall"- oder "Löschen"-Buttons

Verwendung folgender globaler Variablen: generation

Benutzte Methoden: keine


Methode: incGeneration

Funktion: Inkrementiert generation um 1

Parameter: keine

Aufgerufen von: nextGeneration()

Verwendung folgender globaler Variablen: generation

Benutzte Methoden: keine


Methode: getGeneration

Funktion: Liefert den aktuellen Inhalt von generation zurück

Parameter: keine

Aufgerufen von:
in class GameFenster: actionPerformed(ActionEvent), run()

Verwendung folgender globaler Variablen: generation

Benutzte Methoden: keine


Klasse GameFenster

Funktion: Bereitstellung eines Fensters mit Schaltflächen und Textfeldern zur Bedienung sowie einer Fläche zur grafischen Darstellung der Bewegungssimulation

Instanzvariablen:

Verwendet von: class starteGame

Verwendete Klassen: Game

Autor: Nina Schumer Datum: 04.09.2001


Konstruktor: GameFenster

Funktion: Konstruktor, erstellt ein neues Fenster mit Bedienungselementen

Parameter:

Aufgerufen von: class starteGame

Verwendung folgender globaler Variablen: population, start, stop, zufall, loeschen, klein, mittel, gross, xField, yField, anzahlField, geschwField

Benutzte Methoden:
in class Game: Konstruktor


Methode: actionPerformed

Funktion: Fängt Action-Ereignisse ab, erfragt deren Herkunft und agiert entsprechend

Parameter: event/ enthält wichtige Daten über das Ereignis

Aufgerufen: wenn ein ActionEvent auftritt

Verwendung folgender globaler Variablen: population, xField, yField, anzahlField, geschwField, warteZeit, anzeigeText, abbruch

Benutzte Methoden: setzeFensterGroesse(), startAnimation()
in class Game: Konstruktor, getGeneration(), randomMatrix(), initializeGeneration()


Methode: mousePressed

Funktion: Belebt oder löscht bei Mausclick eine Zelle

Parameter: event/ enthält wichtige Daten über das Maus-Ereignis

Aufgerufen: wenn ein MouseClick auftritt

Verwendung folgender globaler Variablen: setzen, groesse, population

Benutzte Methoden:
in class Game: isSet(int, int), setXY(int, int), deleteXY(int,
int)


Methode: mouseMoved

Funktion: Zeigt bei MouseMove über ein Bedienungselement einen
erlklärenden Kommentar an

Parameter: event/ enthält wichtige Daten über das Maus-Ereignis

Aufgerufen: wenn ein MouseMove auftritt

Verwendung folgender globaler Variablen: xField, yField, anzahlField, geschwField, start, stop, zufall, loeschen, klein, mittel, gross, anzeigeText

Benutzte Methoden: keine


Methode: mouseDragged

Funktion: Belebt oder löscht bei Ziehen der Maus Zellen

Parameter: event/ enthält wichtige Daten über das Maus-Ereignis

Aufgerufen: wenn die Maus bei gedrückter Taste bewegt wird

Verwendung folgender globaler Variablen: setzen, groesse, population

Benutzte Methoden:
in class Game: setXY(int, int), deleteXY(int, int)


Methode: itemStateChanged

Funktion: Fängt Item-Ereignisse ab, erfragt deren Herkunft und agiert entsprechend

Parameter: event/ enthält wichtige Daten über das Ereignis

Aufgerufen: wenn ein ItemEvent auftritt (Click auf Checkbox)

Verwendung folgender globaler Variablen: groesse

Benutzte Methoden: setzeFensterGroesse()


Methode: startAnimation

Funktion: Startet den Thread, welcher für die Simulation verantwortlich ist

Parameter: keine

Aufgerufen von: actionPerformed(ActionEvent) bei Start-Button-Betätigung

Verwendung folgender globaler Variablen: t

Benutzte Methoden: keine (automatischer Aufruf von run())


Methode: run

Funktion: Startet den Thread, welcher für die Simulation verantwortlich ist

Parameter: keine

Aufgerufen von: automatisch aufgerufen bei Start des Threads

Verwendung folgender globaler Variablen: population, t, abbruch, warteZeit

Benutzte Methoden:
in class Game: nextGeneration(), getGeneration()


Methode: setzeFensterGroesse

Funktion: Setzt die Fenstergroesse in Abbhängigkeit von Feldgroesse und der Darstellungsgroesse

Parameter: keine

Aufgerufen von:

Verwendung folgender globaler Variablen: population, groesse

Benutzte Methoden: keine
 


Methode: paint

Funktion: Funktion für die grafische Darstellung

Parameter: g/ stellt die grafischen Methoden zur Verfügung

Aufgerufen:

Verwendung folgender globaler Variablen: population, groesse, anzeige, anzeigeText

Benutzte Methoden: keine


Methode: update

Funktion: Diese Methode wird überlagert, damit repaint() ohne flackern erfolgt. Es wird nur der Teil auf dem Bildschirm gelöscht, der wirklich gelöscht werden muß

Parameter: g/ stellt die grafischen Methoden zur Verfügung

Aufgerufen: durch repaint() in

Verwendung folgender globaler Variablen: population, groesse, anzeige,

Benutzte Methoden: keine


Klasse starteGame

Funktion: Startet die Applikation, indem ein neues GameFenster erstellt wird; enthält die main-Methode

Instanzvariablen: keine

Verwendet von: -

Verwendete Klassen: GameFenster

Autor: Nina Schumer Datum: 04.09.2001

Benutzer: Gast • Besitzer: schwill • Zuletzt geändert am: