REFERAT-MenüDeutschGeographieGeschichteChemieBiographienElektronik
 EnglischEpochenFranzösischBiologieInformatikItalienisch
 KunstLateinLiteraturMathematikMusikPhilosophie
 PhysikPolitikPsychologieRechtSonstigeSpanisch
 SportTechnikWirtschaftWirtschaftskunde  



ProPra SS95 Endbericht

ProPra SS95 Endbericht


Contents

Einführung

Einsatzbereich



Anwendungsbereich und Zielgruppe

Soft- und Hardwareanforderungen

Geschwindigkeit

Funktionalität

Legende

Start des Programms

Neues Spiel

Spielbeginn

Nochmal Spielen

Hilfe

Spielende

Spielstrategien - Spielregeln

Spielstrategien

Spielregeln

Benutzeroberfläche

Elemente der Programmoberfläche

Spielfeld

Spielsteine

Informationsfenster

Bedienelemente

Menüleiste

Buttons

Kommunikation

Spielmodi

Beginner einer Partie

Realisierung

Kurze Beschreibung der Strategien

Callbacks

Anmerkung

Start des Programms

Fenster--Ereignisse

Fenster--Verdeckung

Fenster--schließen

Fenster--zerstören

Maus--Ereignisse

Mausbewegung

Mausklick

Button--Ereignisse

Button: Neues Spiel

Button: Nochmal Spielen

Button: Zug zurück

Menü--Ereignisse

Menü: Nochmal spielen, Neues Spiel, Zug zurücknehmen

Menü: Spielende

Menü: Tip

Menü: Hilfe

Die Klasse dD4G

Atribute

Methoden

Die Klasse Spieler

Methoden

Die Klasse Mensch

Die Klassen Computer1, Computer2, Computer3

Methoden

Klasse Kommunikation

Attribute

Methoden

Die Klasse Brett

Attribute

Datenstruktur

letzterZug

letzteZugNummer

Anz_Steine

Methoden

Die Klasse Spielbrett

Attribute

private:

Methoden

private:

public:

Kommentare:

About this document

Einführung

Die Aufgabe des Programmierpraktikums SS '95 bestand darin, ein Spiel zu programmieren, daß man allgemein unter dem Namen dreidimensionales 4-Gewinnt kennt.

So machten sich also 16 Studenten unter der Leitung von Manfred Poepping an die Arbeit diese Aufgabe zu lösen. Probleme enstanden, wenn es um die Koordination der Arbeitsabläufe ging und den Kommunikationsteil des Programmes zum Laufen zu bringen.

Nach mehreren Monaten harter Arbeit enstand nun diese lauffähige Version von 3D - 4 Gewinnt.

Mehr ist nicht mehr über dieses Spiel zu sagen, außer sich davor zu setzen und es auszuprobieren.

Einsatzbereich

Das dreidimensionale Strategiespiel Vier--Gewinnt ermöglicht es dem Spieler zum einem gegen den Computer zu spielen, zum anderen besteht die Möglichkeit, gegen ein anderes Vier--Gewinnt--Programm, sofern es die unter ''Kommunikation'' Kapitel kommunikation beschriebenen Voraussetzungen erfüllt, zu spielen.

Anwendungsbereich und Zielgruppe

Das Programm dient dem Vergnügen. Es wendet sich an Anfänger, die dieses Spiel noch nicht kennen, aber auch an Fortgeschrittene, die ihre Spielkenntnisse vertiefen wollen.

Soft- und Hardwareanforderungen

Benötigt wird ein Unix--Rechner mit der Benutzeroberfläche X--Windows und OSF--Motif.

Geschwindigkeit

Das Programm reagiert im allgemeinen in vernachlässigbar kurzer Zeit, außer beim Menüpunkt ,,Hilfe``, da dann der html-Viewer Mosaic gestartet wird.

Funktionalität

Legende

Start des Programms

Neues Spiel

Wird der Menüpunkt ''Neues Spiel'' ausgewählt, so geschieht folgendes:

Läuft bereits ein Spiel, so erscheint eine Abfrage, die sicherstellt, daß das aktuell laufende Spiel nicht versehentlich abgebrochen wird.

Soll kein neues Spiel gestartet werden, so erfolgt der Rücksprung an die Stelle, von der der Aufruf ''Neues Spiel'' kam. Im anderen Fall muß nun der Spielmodus und die Spielstärke gewählt sowie die Namen der Spieler eingegeben werden.

Folgende Spielmodi sind verfügbar: siehe auch Kapitel kommunikation

Mensch---Mensch

Mensch---Programm

Programm---Programm

Es gibt 3 Spielstärken: leicht, mittel und schwer

Falls ein neues Spiel beginnt, wird der, der anfängt, per Zufall bestimmt.

Daraufhin werden die Farben der Spieler entsprechend gesetzt und es folgt der Beginn des Spieles.

Die Funktionen ''Hilfe'' und ''Programmende'' sind hier immer verfügbar.

Spielbeginn

Wird ein neues Spiel begonnen, so gilt:

Fängt der Gegner an, dann erfolgt ein Gegenzug. Falls dies nicht der Fall ist, so kann der Spieler nun einen Zug machen.

Nach jedem Zug erfolgt ein Gegenzug und umgekehrt, sofern nicht die UNDO--Funktion gewählt wurde und das Spiel noch nicht gewonnen ist. Nach jedem Zug wird geprüft, ob das Spiel von einer Partei gewonnen ist bzw. ein Remis besteht.

Ist bereits ein eigener Zug erfolgt, so läßt sich mit der UNDO--Funktion genau dieser Spielzug zurücknehmen. Ist bereits der Zug des Gegners erfolgt, so wird auch dieser zurückgenommen. Bei der Spielvariante ''Programm gegen Programm'' ist diese Funktion nicht ausführbar.

Die Funktionen ''Hilfe'', ''Programmende'' und ''Neues Spiel'' sind jederzeit möglich.

Nochmal Spielen

Bei ''Nochmal Spielen'' gilt folgendes:

Die Abfrage ''Wirklich'' erscheint nur bei bereits laufendem Spiel.

Soll kein neues Spiel gestartet werden, so erfolgt der Rücksprung an die Stelle, von der der Aufruf ''Nochmal Spielen'' kam. Andernfalls werden die Optionen des letzten Spieles übernommen.

Optionen des letzten Spieles bedeuten hier die Übernahme von Spielmodus, -stärke und Spielernamen; sie können hier nicht mehr verändert werden.

Bei ''Wer beginnt'' wird der Beginner der neuen Partie festgelegt. Es fängt derjenige an, der das vorherige Spiel verloren hat.

Die Funktionen ''Hilfe'', ''Neues Spiel'', ''Nochmal Spielen'' und ''Programmende'' sind jederzeit verfügbar.

Hilfe

Der Aufruf der Hilfe ist jederzeit möglich.

Die ''Spielregeln'' von 3D--Vier--Gewinnt werden erläutert.

Die Funktion ''Tip'' gibt dem Spieler einen möglichen Spielzug an. Sie kann nur bei laufendem Spiel und bei eigenem Zug aufgerufen werden.

Unter ''Bedienung'' wird die Programmbedienung des Spieles erklärt.

Bei ''Info'' wird eine Information über das Programm und seine Autoren ausgegeben.

Spielende

Es wird geprüft, ob einer der Spieler gewonnen hat, oder ob das Spiel mit Remis endet. (siehe auch Kapitel spiel gewonnen)

Spielstrategien - Spielregeln


Spielstrategien

Es existieren 3 Spielstrategien mit unterschiedlicher Spielstärke, von denen die erste Spielstrategie (Random Placement) die schwächste Spielstärke ist, und die zweite Spielstrategie stärker ist als Randomplacement. Die dritte Spielstrategie ist die stärkste Strategie von allen.

Spielregeln

Das Spiel beginnt mit einem leeren Spielfeld, das man sich als einen Würfel vorstellen kann, welcher 4 Felder breit, 4 Felder hoch und 4 Felder tief ist. Abwechselnd wird jeweils von einem Spieler jeweils eine Kugel seiner Farbe auf ein Feld gelegt. Dabei wird die Kugel von oben auf den Würfel gelegt und fällt anschließend auf die oberste darunterliegende Kugel, so daß die Schwerkraft berücksichtigt wird und daher keine Kugel frei schweben kann. Demjenigen, dem es als erstes gelingt, eine gerade Reihe von 4 eigenen Kugeln zu bilden hat gewonnen, und das Spiel wird damit beendet. Eine gültige 4er Reihe ist horizontal, vertikal und diagonal möglich. Wenn alle Felder belegt sind, ohne daß eine 4er Reihe gebildet wurde, so endet das Spiel unentschieden.

Die Ebene 4 soll die höchste Ebene sein.

Horizontal lassen sich pro Ebene 4 Viererreihen (= 16 Möglichkeiten) bilden (Eine Möglichkeit zeigt Beispiel A)

Vertikal lassen sich pro Ebene 4 Viererreihen (= 16 Möglichkeiten) bilden (illustriert Beispiel B)

Diagonal lassen sich pro Ebene 2 Viererreihen (= 8 Möglichkeiten) bilden (die zwei Möglichkeiten zeigen Beispiel C und D)

Die Ebene 4 soll die höchste Ebene sein.
Es ist auch möglich, die Viererreihe durch die Ebenen zu bilden, was durch Beispiel E veranschaulicht wird. Dadurch ergeben sich 16 Möglichkeiten, auf diese Weise eine senkrechte Viererreihe zu bilden.

Die Ebene 4 soll die höchste Ebene sein.
Viererreihen lassen sich außerdem senkrecht diagonal im Raum bilden. Hier sind 8 Möglichkeiten denkbar. Eine Möglichkeit zeigt Beispiel F.

Die Ebene 4 soll die höchste Ebene sein.
Es lassen sich außerdem Diagonalen auch waagerecht im Raum bilden. Hier existieren auch wiederum, ähnlich Beispiel F, 8 mögliche Viererreihen. Eine Möglichkeit illustriert Beispiel G.

Die Ebene 4 soll die höchste Ebene sein.
Noch eine weitere Art der Viererreihe zeigt Beispiel H. Es gibt hier 4 mögliche Viererreihen, die gebildet werden können.

Benutzeroberfläche

Die Benutzeroberfläche ist X--Windows und OSF--Motif unter einem UNIX-Betriebssystem. Die Benutzungsführung erfolgt in Deutsch; die Bedienung erfolgt mittels Maussteuerung.
Der Aufbau sämtlicher Bildschirmdialoge, d.h. Menüs, Dialogboxen und das Hauptfenster (siehe Skizze unten) ist konform mit den Motif Style Guides; dies ergibt sich u.a. durch den Einsatz des Interface Builders.
Das Programm arbeitet vollständig in einem eigenen Fenster, das als Icon verkleinert werden kann.

Elemente der Programmoberfläche

Spielfeld

Das Spielfeld wird durch vier übereinanderliegende, 4 x 4 Felder große Gitter in dreidimensionaler Ansicht ohne Perspektive dargestellt.

Spielsteine

Die Spielsteine werden als Kugeldarstellung realisiert, wobei die Spielsteine zur Unterscheidung der Spieler verschiedenartig gefärbt sind.

Informationsfenster

Hier werden die folgenden Informationen angezeigt:

Spielermodus; z.B. Mensch gegen Programm

Farbe der Spielsteine der Spieler; z.B. Spieler ''Name'' spielt mit den schwarzen Steinen

Wer beginnt

Spielstand, d.h. Spieler 1 oder Spieler 2 hat gewonnen oder Remis

Bedienelemente

Bei der Spielvariante ''Mensch---Programm'' werden die Züge des Menschen mit der Maus realisiert, wobei nur das oberste Gitter des Spielfeldes als Eingabefeld bestimmt ist. Dort ändert sich der Mauscursor, so daß der Spieler erkennt, wo er eine Kugel setzen darf. Die linke Maustaste bewirkt das Setzen der Kugel auf das Spielfeld. Die Kugel landet danach in der untersten Ebene, die noch frei ist. Fehlerhafte Eingaben werden nicht akzeptiert.

Menüleiste

Eine Menüleiste am oberen Fensterrand enthält die folgenden Menüpunkte.

Datei

Spielende:

In einer Dialogbox wird nach einer Sicherheitsabfrage der Art ''Programm wirklich beenden'', das Programm bei einer positiven Antwort beendet, ansonsten läuft das aktuelle Spiel weiter.

Neues Spiel:

Bei einem laufenden Spiel wird mittels einer Dialogbox nach einer Sicherheitsabfrage der Art ''Eine neue Spielserie starten'' bei einer positiven Antwort eine neue Spielserie gestartet. Bei einer negativen Antwort läuft das aktuelle Spiel weiter. Läuft aktuell kein Spiel, so wird eine neue Spielserie gestartet. Über eine Dialogbox wird der Spielmodus, -stärke und Spielernamen ausgewählt.

Nochmal spielen:

Bei einem laufenden Spiel wird ebenfalls in einer Dialogbox nach einer Sicherheitsabfrage der Art ''Neues Spiel beginnen?'' bei einer positiven Antwort ein neues Spiel gestartet. Bei einer negativen Antwort läuft das aktuelle Spiel weiter. Läuft aktuell kein Spiel, so wird ein neues gestartet. Dabei werden die Optionen (wie Spielmodus etc.) des vorherigen Spieles übernommen.

Zug zurücknehmen:

Nur der jeweils zuletzt gesetzte eigene Zug des Spielers wird rückgängig gemacht.

Hilfe

Bedienung:

Die Bedienung des Programmes wird erklärt.

Spielregeln:

Die Spielregeln von 3D-Vier-Gewinnt werden erläutert. Der Text erscheint in einem seperaten Fenster, dessen Inhalt mit der Maus gescrollt werden kann.

Info:

In einem Textfenster werden Informationen über das Spiel und die Autoren ausgegeben.

Tip:

Dem Spieler wird optisch durch eine Kugel, die sich farblich von den Spielerkugeln unterscheidet, ein möglicher nächster Zug angezeigt. Dieser Button kann nur angewählt werden, wenn man am Zug ist und bereits ein Spiel läuft.

Buttons

Die folgenden Buttons, deren Funktion bereits unter Programmoberfläche zur Verfügung.

Nochmal spielen

Neues Spiel

Zug zurücknehmen

Dabei können -- je nach Spielsituation -- einzelne Buttons nicht angewählt werden. Diese sind in dem Fall von den wählbaren optisch unterscheidbar dargestellt.

Kommunikation


Spielmodi

Es ergeben sich - neben dem Modus , Mensch gegen Programm` - folgende Möglichkeiten:


a)

Ein Programm spielt automatisch gegen ein anderes Programm

Die Spielstärke des Programmes kann vor Beginn des Spieles ausgewählt werden. (Das Programm kann auch zweimal gestartet werden und auf diese Weise gegen sich selbst spielen.)

b)

Zwei menschliche Spieler spielen gegeneinander, wobei jeder Spieler an einem 'eigenen` Programm spielt.
In diesem Fall entfällt die Möglichkeit der Spielstärkenwahl.

Beginner einer Partie

Sollen zwei Programme gegeneinander spielen, so beginnt diejenige Seite, bei der die Spielstärkenwahl zuerst abgeschlossen wird. Genauer: Der Prozeß, in dem zuerst die Pipe `player_1' angelegt worden ist, beginnt. Siehe Datenstrukturen

Realisierung

Kurze Beschreibung der Strategien

Die erste und in psychologischer Sicht auch wichtigste Strategie ist zweifellos die erste (Spielstärke: leicht).

Gemeinhin auch unter dem Pseudonym 'Random Placement' bekannt bietet es allen uns bisher bekannten Vertretern der Klasse DAU zumindest die Hoffnung, einmal im Leben gegen einen Computer irgendetwas reißen zu können. Diese unsere Lieblingsstrategie wählt aus den noch freien Positionen zufällig eine aus und wuchtet ihr Steinchen hinein, ohne auf die Konsequenzen zu achten.

Alle anderen Strategien arbeiten mit einem Bewertungsystem für die jeweils möglichen Positionen. Die zweite Strategie prüft zunächst, ob eine 4er-Reihe des Gegners verhindert werden muß oder ob sie selbst eine bilden, sprich gewinnen kann. Dann wird jede mögliche Position daraufhin geprüft, ob ein Setzen an die jeweilige Stelle eine 3er-Reihe des Gegners verhindern, bzw eine eigene ermöglichen kann; für beide Fälle sind Punkte festgesetzt, die dann addiert bzw subtrahiert werden. Gesetz wird schließlich an die Stelle, die die meisten Punkte im Bewertungsystem hat sammeln können, nachdem noch getestet wurde, ob ein Setzen an der Stelle vielleicht dem Gegner eine Gewinnreihe in der Eben darüber möglich macht.

Die vierte Strategie arbeitet nach genau dem gleichen Prinzip, nur daß hier schon auf 2er-Reihen (eigene und die des Gegners) getestet wird und geprüft wird, ob der Gegner vielleicht eine von diesen niedlich-tödlichen Doppelmühlen im Sinn hat. Weiterhin besitzt diese Strategie eine Prioritätenliste für die einzelnen Positionen; so ist zB ein Eckpunkt in der untersten Ebene strategisch günstiger als in Ebene 2 oder 3, in denen die mittleren Punkte die besseren Chancen bieten. Diese Bewertung ist allerdings im Verhältnis zur obigen Zugbewertung klein gewählt, so daß sie nur zum Tragen kommt, wenn zwei mögliche Züge die gleiche Punktzahl erreicht haben. Die fünfte Strategie arbeitet nach genau demselben Prinzip, allerdings mit leicht veränderten Werten.

Die dritte Strategie bewertet nun die möglichen Positionen nicht nach einem Punktesystem, sondern danach, wieviele Möglichkeiten diese Position noch für Gewinnreihen bildet, d.h. wieviel freie oder nur von eigenen Steinen besetzte Reihen von diesem Punkt ausgehen. Vorher wird, wie bei den obigen Varianten, noch auf 4er-Reihen und Doppelmühlen geprüft.

Callbacks

Anmerkung

Im Gegensatz zu anderen Teilen des Programms, wurden die Callbacks genau nach dem vorher erstellten Dokument (und nicht umgekehrt) implementiert. Dadurch halten sich die Anderungen in Grenzen. Auf Anderungen wird im folgenden explizit hingewiesen.

Start des Programms

Beim Start des Programms wird durch den von Motifation erzeugten Quellcode das Hauptfenster von 3D--Vier--Gewinnt initialisiert und dargestellt. Nachdem das Fenster dargestellt wurde, wird dem Hauptprogramm über einen Event signalisiert, daß mit spielspezifischen graphischen Darstellungen etc. begonnen werden kann. Dies wird über den Callback XmPostInitialize realisiert, der global die Klasse 3D4G initialisiert. Diese erzeugt Brett und Spielbrett und stellt mittels Spielbrett.Neuzeichnen() und Spielbrett.gebe_info_aus() das Spielraster und Infofenster dar. Bei der Initialisierung von 3D4G wird ein globales Flag gesetzt, welches speichert, daß der Neues Spiel--Button noch nicht gedrückt wurde. Solange dieses Flag gesetzt ist werden Mausbewegungen und Mausklicks auf der Stein--setzen--Fläche von den entsprechenden Callbacks ignoriert. Dieses Flag wird beim Erzeugen der Spieler (also dem tatsächlichen Spielbeginn) gekippt.

Ergänzung: Alle global verwalteten Daten werden in globalen structs vom Typ CallbackInfo bzw. SpielModusInfo gespeichert.

Zu diesem Zeitpunkt ist das Spiel komplett initialisiert und bereit fuer weitere Benutzereingaben, allerdings werden die Buttons Nochmal Spielen und Zug zurück für Eingaben gesperrt.

Ergänzung: Dies wird ebenfalls über interne Flags abgefangen.

Fenster--Ereignisse

Fenster--Verdeckung

Nach vollständiger oder teilweiser Verdeckung des Spielfensters wird durch einen entsprechenden Refresh--Callback die Programmoberfläche neu gezeichnet. Dies wird über die Funktionen Spielbrett.Neuzeichnen() und Spielbrett.gebe_info_aus() realisiert.

Fenster--schließen

Wird das Fenster über den WindowClose--Button geschlossen, wird der gleiche Callback wie bei dem Menüpunkt Spiel beenden ausgelöst (d.h. es erscheint ein Requester, welcher erfragt, ob wirklich abgebrochen werden soll. Die weitere Vorgehensweise kann beim Callback für Spielende nachgesehen werden.

Anderung: Die Spiel verlassen? Sicherheitsabfrage fiel einer GUI Überarbeitung zum Opfer

Wird im Kommunikationsmodus gespielt, muß dem gegnerischen Programm über Kommunikation.Abbruch() mitgeteilt werden, daß das Spiel beendet wurde.

Fenster--zerstören

Wird das Programm über destroy verlassen, werden vom Callback Destroy() die entsprechenden Destruktoren der bereits erzeugten Klassen aufgerufen. Danach wird das Programm (ohne Requester--Abfrage) verlassen.
Wird im Kommunikationsmodus gespielt, muß dem gegnerischen Programm über Kommunikation.Abbruch() mitgeteilt werden, daß das Spiel beendet wurde.

Maus--Ereignisse

Mausbewegung

Bei diesem Ereignis wird ein Callback namens Mausbewegt() ausgelöst.

Anderung: Alle Funktionen des Callbacks Mausbewegt sind in die Klasse 3D4G gewandert. Die Mausbewegung wird dieser übergeben und an die Klasse Spielbrett weitergeleitet.

Dieser ermittelt und übergibt die Mauskoordinaten an die Funktion Spielbrett.Feldpositionberechnen(), welche die zurückgibt (bzw. falls der Mauszeiger sich nicht über dem Zug-Eingabefeld befindet). Wurde eine gültige Koordinate zurückgegeben, wird dann Brett.Zuglegal() aufgerufen. Ist der Zug legal, wird der Klasse Spielbrett über die Methode Spielbrett.Markieren( a,b ) mitgeteilt, über welchem Eingabefeld sich der Mauszeiger befindet. Von der Klasse Spielbrett wird die Farbe des entsprechenden Eingabefeldes geändert und gespeichert, welches Feld verändert wurde. Zuvor wird diese Variable ausgelesen um ein evtl. vorher markiertes Feld wieder zu de--markieren. Sollte nach dem Start des Programms noch kein Spielmodus gewählt sein, so werden die Mausbewegungs--Ereignisse nicht bearbeitet, da das Setzen eines Spielsteines noch nicht möglich ist. Gleiches gilt falls die Kommunikation das Spiel übernommen hat.

Mausklick

Bei diesem Event wird der Callback Kugelsetzen() mit den aktuellen Mauskoordinaten aufgerufen.

Anderung: Alle Funktionen dieses Callbacks sind in die Klasse 3D4G gewechselt. Bei einem Mausklick wird nur noch die Methode Zug von 3D4G (mit den aktuellen Mauskoordinaten) aufgerufen.

Dieser testet zunächst, ob ein Mausklick im momentanen Spielmodus überhaupt beachtet werden soll. Im Spielmodus Rechner--Rechner oder vor Auswahl eines Spielmodus sind Mausklicks nicht zugelassen.
Ist ein Mausklick erlaubt, ruft er (wie bereits oben beschrieben) die Funktionen Spielbrett.Feldpositionberechnen() und Brett.Zuglegal() auf, um zu ermitteln, ob es sich um einen gültigen Zug handelt. Ist es ein gültiger Zug, wird die gültige Position über 3D4G der Klasse des menschlichen Spielers über die Methode Zug mitgeteilt. Innerhalb dieser wird dann Brett.Zugsetzen() aufgerufen. Durch Brett.Zugsetzen() wird auch der momentane Spielstatus ermittelt (gewonnen/remis/gültiger Zug). Dieser Rückgabewert wird von der Methode Zug als Rückgabewert an die aufrufende Callback--Funktion zurückgegeben. Mittels Spielbrett.Neuzeichnen() wird dann die Bildschirmausgabe aktualisiert.
Wechselt der Spielstatus in den Zustand ,,gewonnen``, wird die Funktion Spielbrett.Spielbeendet( Spieler, Grund ) aufgerufen, welche einen Requester erzeugt, der diese Tatsache kundtut.

Anderung: Die hier erwähnten Requester sind einer Ausgabe im Statusfenster gewichen.

Nach Bestätigen des Requesters wird das Brett mittels Brett.Brettleeren() neu initialisiert und die Variable für den letzten Zug gelöscht. Desweiteren werden die Spielerklassen über SpielerKlasse.init() neu initialisiert.
Wird im Kommunikationsmodus gespielt, muß die Kommunikation dem gegnerischen Programm mittels der Methode Zug das Spielergebnis mitteilen. Danach kann das Spiel erneut beginnen. Wechselt der Spielstatus in den Zustand ,,remis``, wird ebenso verfahren.

Liegt der Zustand ,,gültiger Zug`` vor, wird über Spielbrett.Neuzeichnen() die Bildschirmausgabe aktualisiert. Danach wird über 3D4G.AntwortZug() ein Gegenzug berechnet und im Brett gesetzt. Dazu ruft 3D4G die Methode Zug der jeweiligen Gegnerklasse auf und gibt deren Rückgabewert an die aufrufende Callback--Funktion zurück. Wechselt dadurch der Spielstatus, werden jeweils die gleichen Funktionen wie nach einem per Mausklick ausgelösten Zug ausgelöst. Ist der Gegenzug getätigt, wird mittels Spielbrett.Neuzeichnen() die Bildschirmausgabe aktualisiert.

Button--Ereignisse

Button: Neues Spiel

Dieser Event ruft den Callback NeuesSpiel() auf, welcher den Requester für die Spieleinstellungen beinhaltet. Die im Spieleinstellungsfenster enthaltenen Bedienelemente rufen jeweils Callbacks auf, die die jeweils betroffene Variable im (zu den Callbacks gehörenden) struct SpielModusInfo verändern.
SpielModusInfo wird bei der Erzeugung der Spieler von der Klasse 3D4G ausgewertet.

Auswahl des Spielmodus

Für jeden wählbaren Spielmodus (Mensch--Mensch, Mensch--Computer, Computer--Computer) existiert ein Callback, der im entsprechenden Feld des SpielModusInfo--structs den gewünschten Spielmodus einträgt.

Auswahl der Spielstärke

Für jede auswählbare Spielstärke existiert ein Callback, der in SpielModusInfo speichert, welche Spielstärke gewählt wurde. Diese Information wird bei der Erzeugung der Spieler von 3D4G berücksichtigt.

Namensvergabe

Eintrag des Namens im Texteingabefeld und Bestätigen mittels Return führt zu einem Callback, der den eingegebenen Text in SpielModusInfo speichert.

Wer fängt an?

Beim Aufruf des Spieleinstellungsrequesters wird der Zufallsgenerator gestartet und ermittelt, wer beginnen soll. Auch diese Information wird in SpielModusInfo gespeichert.

Weiter

Betätigen des Weiter--Buttons führt dazu, daß der struct SpielModusInfo mittels der Methode 3D4G.Spielersetzen() an die Klasse 3D4G übermittelt wird. Mit den so erhaltenen Daten erzeugt 3D4G die entsprechenden Spieler und initialisert die spielbezogenen Daten neu. Danach wird das Neues Spiel--Fenster geschlossen und über Spielbrett.gebe_info_aus() das Info--Fenster aktualisiert.
Wird ein Spielmodus gewählt, welcher Einschränkungen für die Oberfläche beinhaltet, müssen diese vorgenommen werden (z.B. Buttons sperren etc.).

Abbruch

Dieser Button führt dazu, daß ohne eine Veränderung zum Hauptfenster zurückgekehrt wird.

Button: Nochmal Spielen

Dieser Event initialisiert das Brett mittels Brett.Brettleeren() und Spielbrett.Neuzeichnen(), und setzt die Variable für den letzten Zug zurück. Desweiteren werden die Spielerklassen von 3D4G über SpielerKlasse.init() neu initialisiert. Danach kann weitergespielt werden.
Diese Funktion ist nicht verfügbar, falls im Kommunikationsmodus gespielt wird.

Button: Zug zurück

Dieser Event löst einen Callback namens ZZurueck() aus, welcher Brett.Zugzurueck und dann Spielbrett.Neuzeichnen() aufruft.
Diese Funktion ist nicht verfügbar falls im Kommunikationsmodus gespielt wird.

Menü--Ereignisse

Menü: Nochmal spielen, Neues Spiel, Zug zurücknehmen

Diese Menüpunkte rufen die gleichen Callbacks wie die entsprechenden Buttons auf.

Menü: Spielende

Löst einen Callback auf die Funktion Spielbeenden() und einen Requester aus. Wird in diesem Ja (=Ja, es soll abgebrochen werden) gewählt, wird der Destruktor der Klasse 3D4G aufgerufen. Dadurch wird das Spiel beendet.
Wird im Kommunikationsmodus gespielt wird dem gegnerischen Programm von der Klasse 3D4G über die Methode Kommunikation.Abbruch() mitgeteilt, daß das Spiel beendet wurde. Danach wird wie oben bereits beschrieben verfahren.
Wird Nein angewählt, wird ohne eine Aktion auszuführen zum Hauptfenster zurückgekehrt.

Menü: Tip

Bei der Anwahl dieses Menüpunktes wird über 3D4G.AntwortZug() ein Zug von der jeweiligen Gegnerstrategie angefordert (diese berechnet natürlich einen für den Menschen günstigen Zug). Die erhaltene Position wird über Spielbrett.gebe_info_aus() im Infofenster dargestellt.
Diese Funktion ist nicht verfügbar falls im Kommunikationsmodus gespielt wird.

Menü: Hilfe

Die Menüpunkte 1--3 lösen jeweils einen Callback auf eine Funktion aus, die einen externen Textanzeiger (z.B. MOSAIC oder hilfsweise ein XTERM--Fenster) mit dem jeweiligen Text asynchron startet.

Die Klasse dD4G

Diese Klasse ist der Mittler zwischen den Fronten.

Sie weiß im allgemeinen was Sache ist.

Atribute

SpielerxPtr

zeigt auf Spieler x

KommunikationPtr

zeigt auf Kommunikation

BrettPtr

zeigt auf Brett

SpielbrettPtr

zeigt aufs Spielbrett

tFarben

enthält die Farbe des Spielers, der an der Reihe ist

Info

enthält die Informationen zum Spiel

ComputerNamen

Array das die schönen von uns erfundenen Namen für die 3 Strategien enthält

kommdestruct

weiß ob Pipes gelöscht werden müssen

Methoden

Constructor:

Brett und Spielbrett werden erzeugt

Neues Spiel

Spieler1 und -2 werden erzeugt

NochmalSpielen

SetStarter

ZugSetzen

Der Zug wird im Brett gesetzt

AntwortZug

Ein Antwortzug wird angefordert

Tip

Ein Tip wird angefordert

ZugZurueck

Der letzte Zug wird zurückgenommen

Spielersetzen

Spielerklassen initialisieren

Die Klasse Spieler

Die Klasse Spieler ist eine virtuelle Basisklasse für die Klassen Mensch, Computer1, Computer2, Computer3 und Kommunikation. Sie legt die allgemeinen Schnittstellen fest.

Methoden

Zug
Alle Klassen stellen die Methode Zug zur Verfügung. Diese holt oder berechnet einen Zug und setzt diesen im Brett.
Der Rückgabewert dieser Methode gibt an, ob durch diesen Zug das Spiel gewonnen wurde, unentschieden endete oder ob und wie während des Zugs das Spiel abgebrochen wurde.

init(int i)
Beim Aufruf dieser Funktion werden die internen Daten neu initalisiert. Der Parameter i gibt an ob diese Klasse beginnt (1) oder nicht (2).

Die Klasse Mensch

Die Klasse Mensch ist eine Dummy-Klasse.

Die Klassen Computer1, Computer2, Computer3

Methoden

Zug
Ein Zug wird berechnet und im Brett gesetzt. Es wird die Methode ``letzter Zug'' der Klasse Brett benötigt.

Klasse Kommunikation

Die Klasse Kommunikation stellt die Verbindung zu einem anderen entsprechend vorbereiteten 3D--Vier--Gewinnt--Programm zur Verfügung.

(Diese Klasse repräsentiert dann sozusagen den Gegenspieler.)

Attribute

private

tFarben GegnerFarbe:

Die Farbe, mit der die Steine der gegnerischen Seite dargestellt werden.

bool fAbbruchEmpfangen

ist ein Flag als Merker für den Fall, daß die andere Seite das Spiel beendet.

bool angefangen

ist gleich true, genau wenn 'unser' Programm das Spiel beginnt.

public

XtInputId InputId

enthält den Rückgabewert von XtAppAddInput(). Dieses Attribut wird in LegePipesAn() und LoeschePipes() benötigt.
Wegen Streß mit XtAppAddInput und XtAppAddTimeOut ist dieses Attribut public.

XtIntervalId

ist die Id eines Aktiven TimeOut-Timers, der mit XtApp''AddTimeOut() gestartet wurde.
Wegen Streß mit XtApp''AddInput und XtApp''AddTimeOut ist dieses Attribut public.

int PipeHandle:

Handle der Pipe, in die die Daten von Gegenseite geschrieben werden. Muß für Aussen_Lese_Zug() (in comsupport.c) leider public sein.

Methoden

private

void LegePipesAn()

legt zwei Pipes ``player_1'' und ``player_2'' an, über die die Züge zwischen beiden Programmen ausgetauscht werden. Sind die Pipes bereits vorhanden, so fängt die Gegenseite das Spiel an; im anderen Fall beginnt dieses Programm. Diejenige Pipe, aus der Daten des Gegners gelesen werden sollen, wird bei Motif über XtAppAddInput als Eingabemöglichkeit angemeldet.

void LoeschePipes()

meldet ReadPipe bzw. InputId als Eingabemöglichkeit bei Motif ab und löscht die Pipes ``player_1'' und ``player_2''.

void SignalHandler(int)

wird im Konstruktor als Funktion angegeben, die bei Signalen wie SIGSEGV, SIGABRT etc. noch abgearbeitet werden soll.
Es wird die Methode LoeschePipes() aufgerufen, eine Meldung über stderr ausgegeben und das Programm beendet.

public

Kommunikation(tFarben farbe, dD4G *pointer):

Der Konstruktor erhält als Parameter die Farbe, mit der gegnerische Steine in diesem Programm dargestellt werden. Der Wert wird im Attribut GegnerFarbe gespeichert. [Vergleiche auch init(tFarben).]
Der Zeiger dD4G *pointer zeigt auf die Instanz der Klasse dD4G, die den Konstruktor aufgerufen hat. Über diesen Zeiger wird auf Methoden der Klassen dD4G und Brett zugegriffen.
Das Flag fAbbruchEmpfangen wird initialisiert (auf false gesetzt).
Die Methode SignalHandler wird als Handler für Signale wie SIGSEGV etc. angemeldet.
Weiterhin wird LegePipesAn() aufgerufen. Innerhalb dieser Methode wird das Flag angefangen auf den korrekten Wert gesetzt.
Danach wird der Instanz von dD4G mitgeteilt, welche Seite das Spiel beginnt. (Auf die Methode dD4G::SetStarter kann über den von der Klasse Spieler geerbten Zeiger auf dD4G zugegriffen werden.)

Kommunikation():

Im Destruktor wird ein eventuell noch laufender TimeOut-Zähler entfernt.
Wenn dieses Programm gewonnen hat, werden die Pipes durch
LoeschePipes() gelöscht. (Die Gegenseite muß genauso verfahren, damit die Pipes nach einem Spiel auf jeden Fall entfernt werden.)

void Abbruch():

Wird diese Methode aus LeseZug heraus aufgerufen bzw. gilt fAbbruchEmpfangen==true, so wird LoeschePipes() aufgerufen.

Rueckgabewert Zug(tFarben farbe):

Entspricht farbe der Farbe 'unserer' Spielsteine, so wird über Brett::Letzter_Zug() der letzte Zug dieses Programms geholt und an das gegnerische Programm übermittelt.
Ist farbe gleich GegnerFarbe, so wird die Antwort des gegnerischen Programmes aus der entsprechenden Pipe gelesen und ausgewertet. Ein vom Gegner gesendeter Spielzug wird über Brett::''ßug_setzen(tZug) gesetzt.
Sind in der Pipe keine neuen Daten vorhanden, so ist der Rückgabewert 'NixDa'; ansonsten wird der Rückgabewert von
Brett::''ßug_setzen(tZug) oder ein entsprechender Wert für eine Meldung der Gegenseite (wie ``Abbruch'') zurückgegeben.

void init(tFarben farbe)

setzt GegnerFarbe auf farbe, also die Farbe, mit der gegnerische Steine in diesem Programm dargestellt werden.

Funktionen außerhalb der Klasse:
Die folgenden Funktionen werden von der Klasse Kommunikation benötigt und sind in der Datei
comsupport.c implementiert.

void Aussen_Lese_Zug()

wird über XtAppAddInput aufgerufen, wenn neue Daten in der zu ReadPipe gehörenden Pipe anliegen und ruft ihrerseits eine Methode der Klasse dD4G auf. Aus dD4G heraus wird Kommunikation::Zug(tFarben) aufgerufen, um die neuen Daten zu bearbeiten.

void Aussen_DoTimeout()

wird über XtAppAddTimeOut aufgerufen, wenn eine festgelegte Zeitspanne abgelaufen ist und ruft ihrerseits void Kommunikation::DoTimeOut() auf.

Die Klasse Brett

Diese Klasse repräsentiert die Daten des Spielbretts, auf die mit speziellen Methoden zugegriffen werden kann.

Attribute

Datenstruktur

Die Daten werden in einem 4 x 4 x 4 Array (Würfel) mit dem Inhalt schwarz, weiss und frei vom Typ tFarben verwaltet.

letzterZug

Das Attribut letzterZug ist ein eindimensionales Feld vom Typ tZug. In ihm werden die gemachten Züge gespeichert.

letzteZugNummer

Das Attribut letzteZugNummer ist ein Index (vom Typ integer), welcher immer auf den letzten Eintrag in dem Feld letzterZug zeigt.

Anz_Steine

Das Attribut Anz_Steine speichert die Anzahl der schon gesetzten Steine und ist vom Typ integer.

Methoden

Methode Zug-setzen
Parameter: tZug, wobei der z-Wert nicht relevant ist und Null sein kann
Rückgabewert:

0 : ungültiger Zug

1 : gültiger Zug

2 : Spiel gewonnen

3 : Remis

Diese Methode bekommt die 2D-Koordinaten(x,y) und die Farbe des Spielers übergeben, der gerade am Zug ist und liefert oben genannte Rückgabewerte zurück. Dabei wird intern nur dann ein Stein (d.h. 1 oder 2) gesetzt, falls der Zug ein gültiger Zug war (wird mit Hilfe von Zug_legal abgeprüft). In dem Fall wird dann zuerst das Attribut Anz_Steine und das Attribut letzterZug aktualisiert. Dann wird überprüft, ob das Spiel mit diesem Zug gewonnen wurde oder ein Remis vorliegt. Dementsprechend ist der Rückgabewert. Wenn ein Stein gesetzt wurde, wird Neuzeichnen(Ebene) des Spielbretts aufgerufen.

Methode Zug-zurueck
Parameter: tFarben
Rückgabewert: FALSE: Zug wurde nicht zurückgenohmen
TRUE: Zug oder Züge wurden zurückgenohmen

Diese Methode löscht den letzten oder die beiden letzten Züge (falls der Gegner schon am Zug ist) und gibt TRUE als Rückgabewert zurück. Falls der aktuelle Zug schon zurückgenommen oder im bisherigen Spielverlauf noch kein Zug gemacht wurde (Attribut letzteZugNummer = -1), wird FALSE als Rückgabewert zurückgegeben.

Methode Daten-auslesen
Parameter: tPosition
Rückgabewert: tFarben, Farbe des Spielsteins an der Position

Methode Brett-leeren
Parameter: keine
Rückgabewert: keiner

Diese Methode initialisiert (löscht) das komplette Brett. D.h. jedes Feldelement des Attributes wuerfel[ ][ ][ ] wird auf 'frei', das Attribut Anz_Steine auf 0 und das Attribut letzteZugNummer auf -1 gesetzt.

Methode Zug-legal
Parameter: tPosition, wobei der z-wert nicht relevant ist
Rückgabewert: tPosition, wobei der z-Wert angibt, wo der Stein reinfallen würde
Ist der z-Wert gleich -1, dann ist die senkrechte Reihe schon voll

Diese Methode prüft anhand der ihr übergebenen Parameter, an welche z-Position der Stein fallen würde, oder ob der Zug illegal ist. Je nachdem ist der Rückgabewert. Diese Methode prüft nur UND setzt nicht den Zug.

Methode Letzter-Zug
Parameter: keine
Rückgabewert: tZug, d.h. den letzten gemachten Zug
tZug = -1,-1,-1,frei falls noch kein Zug gemacht wurde

Diese Methode liefert den letzten gültigen Zug. Falls im Spielverlauf noch kein Zug gemacht wurde, wird ein dummyZug vom Typ tZug zurückgegeben.

Die Klasse Spielbrett

Attribute

private:

Spielwiese: technisch: struct polygon Spielwiese wobei D.h. die Spielwiese besteht aus 4 Gittern, wobei nur das oberste Gitter Zugeingaben zuläßt.

Ein Gitter besteht aus 16 Polygonen bzw. Parallelogrammen.

wobei die c-te Ebene

Das private Linienarray Gitter beinhaltet die vier Außenlinien des obersten Gitters. Diese werden im Konstruktor berechnet und bei der Methode Feldpositionberechnen bzw. ist_in_Gitter benötigt.

Die Struktur polygon besteht aus den Punkten A,B,C,D und einem Mittelpunkt M; der Schnittpunkt der beiden Diagonalen.

Die Struktur linie besteht aus den zwei Punkten A und B, welche jeweils die globale Struktur tPunkt haben.

Ein Punkt besteht aus einem globalen Tupel der Form tPunkt(int x; int y;).

Integerkonstante anzahl_meldungen legt fest, wieviel Meldungen im Info--Fenster angezeigt werden sollen; sie wird für die Methode gebe_Infos_aus gebraucht.

Integerkonstante anzahl_buchstaben legt fest, wie lang ein Textstring sein soll und wird für die Methode gebe_Infos_aus benötigt.

Sonstige:

Methoden

private:

Konstruktor: Berechnet die Linien des Spielbretts und initialisiert die Attribute.

ccw

Parameter: Tripel von Punkten, welche die globale Struktur tPunkt haben.

Rückgabe:

Teste, ob man für die drei Punkte, wenn man vom ersten zum zweiten und dann zum dritten geht, sich im oder gegen den Uhrzeiger dreht.

schneidet

Parameter: Tupel von Linien, wobei eine Linie die Struktur linie hat.

Rückgabewert:

Prüft, ob sich zwei Linien schneiden.

ist_in_Gitter

Parameter: Koordinate des Mauscursors mit der Struktur tPunkt

Rückgabewert:

Prüft, ob Mauscursor sich innerhalb des obersten Gitters befindet.

public:

Neuzeichnen

Stellt gesamte Spielwiese graphisch dar. Dabei wird auf die Methode Brett.Daten_auslesen(tPosition) zugegriffen. Das Info--Fenster bleibt dabei unverändert.

Parameter: keiner

Rückgabewert: keiner

aktualisiert nur die c-te Ebene von unten und verändert das Info--Fenster nicht. Es erfolgt ein mehrmaliger Aufruf von Brett.Daten_auslesen.

Parameter:

Rückgabewert: keiner

gebe_Info_aus

Parameter: Struktur SpielModusInfo und Integer was_noch mit:

Das Info--Fenster hat den Widgetnamen infoT. Eine Textzeile hat Platz für anzahl_buchstaben. Es ist Platz für anzahl_meldungen vorgesehen.

Rückgabewert: keiner

Die Methode gibt Informationen über den Spielmodus, Spielstärke, wer beginnt und wer gewonnen hat aus.

Feldpositionberechnen

Parameter: Mauskoordinaten (bezogen auf das Programmfenster) in der Struktur tPunkt

Rückgabewert: Koordinate mit der Struktur tPunkt

Versuch, die Mauskoordinate auf Koordinaten des oberen Gitters abzubilden.

FeldMarkieren

Parameter: Mauskoordinaten (bezogen auf das Programmfenster) in der Struktur tPunkt

Rückgabewert: keiner

Die Methode verändert den Mauscursor, falls dieser sich über einem zulässigen Eingabefeld befindet.

Kommentare:

Der von keinem erwartete Abschnitt mit Carstens [Anm.: Carsten Thurau] Kommentar
Mein Kommentar zum Propra:
Wieder einmal eine Pflichtveranstaltung hinter mir

Nein, so schnell und abwertend kann man das Thema nicht abhaken. Entgegen anders lautenden Gerüchten hat es mir Spaß gemacht, und sogar einen Sinn habe ich entdeckt.

Was hat es gebracht:

es war für die meisten wahrscheinlich der erste Versuch, in einer größeren Gruppe zu arbeiten. Sicherlich hätte das Problem auch zu zweit lösen können aber darum ging es nicht. Hier konnte man einfach lernen, was man bei Gruppenarbeit zu beachten hat, welche Fehler auftreten können und wir nutzten die Gelegenheit, aus Fehlern zu lernen, sehr gut aus. Vor allen Dingen dürften wir gelernt haben, dass genaue Absprache selbst der Details, die selbstverständlich erscheinen, selbstverständlich sein sollte.
,,Die Ebene 0 ist bei uns unten.``
,,BEI UNS IST SIE ABER OBENt`

Während in INFO A nur einige lückenhafte Grundlagen der Sprache C++ vermittelt wurden, in B diese ignoriert wurde, kam INFO C. Meine Hoffnungen, dort etwas mehr über C++ zu erfahren waren genauso groß wie falsch. Durchaus konnte man etwas dazulernen - jedoch nur auf wenig vernünftige Weise: es kamen neue Elemente in den Programmen der Vorlesung vor, die man dann zu Hause verstehen sollte.
Im Propra lernte ich zwangsläufig mehr über mir vorher verborgen gebliebene Elemente wie virtuelle Funktionen und abstrakte Basisklassen, auch einiges über Konzepte, die hinter C++ stehen - jedoch nur in Eigenarbeit.
Vielleicht sollte man mal darüber nachdenken, eine Vorlesung zum Thema C++ nicht erst im Hauptstudium anzubieten, wenn sich fast jeder schon selbst die Kenntnisse angeeignet hat
Aber immerhin: nun ist mir C++ kein Fremdwort mehr, nur ein Reizwort

Gut, dass man sich Kenntnisse mit diversen Hilfsprogrammen selbst aneignen musste; dass wird den Informatiker auch später noch belasten. Interessant die Argernisse mit diesen ,,Hilfen`` - manchmal scheinen sie Eigenleben zu entwickeln.

,,Manfred hat Humor -- man sieht es an Motifation.``

Das wichtigste jedoch war der Bericht über Computer-Psychologen in Norwegen

Stephan I.:
Es waere ,,günstig`` gewesen, wenn alle nicht nur Dokumente produziert hätten, sondern diese auch zur Impelementation nochmal gelesen (!!!) hätten
Ansonsten fand ich, daß wir
Eine starke Truppe waren!! :-)
Brain over --- Insert coin







Haupt | Fügen Sie Referat | Kontakt | Impressum | Nutzungsbedingungen