TicTacToe - Design

Wir wollen ein TicTacToe Programm schreiben - und dabei alles verwenden was wir bisher gelernt haben. Hier kannst du dir den Sourcecode runterladen.

Wir wollen das Programm unabhängig von der Visualisierung schreiben. Sprich wird implementieren das Spiel zwar für die Textkonsole (cout) aber wir schreiben es so, dass man ohne Probleme die Ausgabe zB per OpenGL machen kann.

Um die Visualisierung vom logischen Programmteil zu trennen verwenden wir eine abgespeckte Version des MVC-Modells.

Das Application Objekt ist die Zentrale unserer Anwendung. Hier wird das Menü erstellt, das Game Objekt instanziiert und der Mainloop findet hier statt.

Fangen wir mit dem Menü an:

UML Diagramm der Klassen Menu und MenuEntry

Beide Klassen sind abtrakt - da sie lediglich das Interface definieren - was tatsächlich gemacht wird (Ausgabe in der Konsole, in ein DirectX Fenster,...) wird erst in der abgeleiteten Klasse festgelegt.

Hier wird das 'Template Method' Design Pattern - auch wenn der Nutzen in diesem speziellen Fall nicht allzugroß ist. Wir betreiben hier Overengineering - wir versuchen unsere kleine Anwendung so zu entwickeln, als wäre es eine große und komplexe Anwendung.

Im Sourcecode wirst du 2 Klassen finden, die von MenuEntry erben: MenuEntryMethod und MenuEntryMethodParam2. Diese werden verwendet um Callbacks einzurichten. Wir sagen einfach, wenn der User Option 1 wählt, dann rufe die exit-Methode des Application Objektes auf.

UML Diagramm der Klasse Application

Betrachten wir nun den Konstruktor der Application Klasse - hier legen wir erst ein konkretes Menü an, und fügen dann die passenden Menü-Einträge hinzu.

In Application::run() wird der Mainloop ausgeführt, welcher nur das Menü aufruft - denn sobald der User das Spiel starten will, wird Application::startGame() aufgerufen. Wir müssen uns in Application::run() somit nur um das Menü kümmern.

Application::startGame() instanziiert das Game Objekt und startet den Game-Mainloop.

UML Diagramm der Klasse Game

Game verwendet zur Visualisierung eine VisualEngine. Wie bei Menu wird auch hier wieder makeEngine() aufgerufen um eine konkrete Engine zu konstruieren. Weiters besitzt Game 2 Zeiger auf Player-Typen - Player 1 und Player 2. Ob diese menschliche Spieler oder nur eine KI sind, entscheidet die Funktion makePlayer() - welche ein 'Factory Method' Design Pattern ist.

UML Diagramm der Klassen Player, HumanPlayer und AIPlayer

HumanPlayer und AIPlayer implementieren die abstrakte Klasse Player - je nachdem mit Benutzereingaben oder einer künstlichen Intelligenz. Wir können so recht einfach neue Spieler hinzufügen (zB verschiedene KI Stufen). HumanPlayer verwendet eine VisualEngine um die Benutzereingaben vom User zu bekommen.

UML Diagramm der Klasse VisualEngine

VisualEngine erledigt die Visualisierung während des Spiels. Sie muss für jede Visualisierung implementiert werden.

Das Position Objekt bei VisualEngine::update() dient er Effizienz. Denn manchmal muss man nur das Feld neuzeichnen, dass sich geändert hat - und nicht das ganze Spielfeld.

UML Diagramm der Klasse Field

Field ist sehr simpel - es kapselt eine 3x3 Matrix (das Spielfeld).

UML Diagramm der Klasse Position

Position wird für Positionsangaben verwendet. Dank des Konstruktors können wir foo(Position(1,1)); schreiben um die Koordinaten 1,1 anzusprechen.

top