Regelbasierte Systeme am Beispiel Tichu
Transcription
Regelbasierte Systeme am Beispiel Tichu
Regelbasierte Systeme am Beispiel Tichu Maturaarbeit von Simon Rösch, 1MNd Betreut von Tobias Bäumlin Erstellt von Dezember 2007 bis Oktober 2008 Regelbasierte Systeme am Beispiel Tichu Simon Rösch, 1MNd 1 Einleitung Als es vor knapp einem Jahr darum ging, ein Thema für die Maturaarbeit zu wählen, war für mich klar, dass ich etwas im Bereich Informatik machen möchte. Da ich auch ein sehr angefressener Tichu-Spieler bin, kam ich auf die Idee ein Programm zu schreiben, das Tichu spielen kann. Ich war mir aber auch bewusst, dass dies nicht einfach sein würde und habe die Idee deshalb lange nur mit mir herumgetragen. Als mir dann keine bessere Idee kam, habe ich begonnen mit Kollegen, die in der Informatikbranche tätig sind, über mein Projekt zu sprechen. Ich habe nicht nur ermunternde Ratschläge bekommen, aber nach einem längeren Gespräch mit Moritz Kobel, der mein Projekt als durchführbar einstufte und mich dazu ermunterte, es zu versuchen, habe ich mich definitiv für dieses Projekt entschieden. Da ich nun wusste, was ich machen wollte, brauchte ich noch einen Betreuer. Für mich kam eigentlich nur Tobias Bäumlin in Frage, da er mich im Programmieren unterrichtete. Dieser sagte nach etwas zögern auch zu. Zusammen haben wir dann beschlossen, dass es wohl am einfachsten wäre, das Problem mit einem Expertensystem zu lösen. Da es ein viel zu grosser Aufwand gewesen wäre, ein Expertensystem selber zu schreiben, machte ich mich auf die Suche nach einem bereits bestehenden System, das ich für meine Zwecke adaptieren konnte. Gleichzeitig habe ich auch schon eine erste Version des Programms geschrieben, das jedoch noch sehr zufällig spielte. Nach der gefundenen Lösung, das regelbasierte System Drools, konnte es dann definitiv losgehen. Nach der praktischen Arbeit brauchte ich nicht mehr gross nachzudenken, worüber ich schreiben sollte, die Themen waren ziemlich klar. Regelsysteme und Tichu mussten erklärt werden und auch eine Beschreibung meines Projektes durfte nicht fehlen. An dieser Stelle möchte ich es nicht unterlassen, mich bei denjenigen zu bedanken, die mich bei meiner Arbeit unterstützten. Es sind dies namentlich mein Betreuer Tobias Bäumlin, der mir immer mit Ratschlägen zur Seite gestanden ist, sowie Moritz Kobel, der mich zum Projekt motiviert hat. Ein grosser Dank geht auch an Urs Hostettler, der mir per Mail einige tichubezogene Fragen beantwortete und mir die Erlaubnis gab, die Spielkarten von Fata Morgana zu scannen und in meiner Arbeit zu verwenden. Auch den Lektoren AnnaTina, Christoph und Jürg Rösch möchte ich an dieser Stelle herzlich danken, sowie allen anderen, die mir während der Arbeit in irgendeiner Weise geholfen haben. -- Oktober 2008 Regelbasierte Systeme am Beispiel Tichu Simon Rösch, 1MNd 2 Inhaltsverzeichnis 1 Einleitung 3 2 Inhaltsverzeichnis 4 3 Abstract 6 4 Regelbasierte Systeme 4.1 Regelbasierte Logik 4.2 Der Aufbau eines regelbasierten Systems 4.3 Vorteile eines regelbasierten Systems 7 7 9 9 5 Drools 5.1 Der Rete-Algorithmus 5.2 Die Regelsprache 5.3 Der Einbau in ein Java-Programm 5.4 Das Eclipse-Plugin 11 11 12 15 16 6 Tichu 6.1 Geschichte 6.2 Der Autor 6.3 Die Spielvorbereitungen 6.4 Die Spielregeln 6.5 Die Sonderkarten 6.6 Bomben 6.7 Das Ende einer Runde 6.8 Das Ansagen 17 17 17 18 18 19 20 20 20 7 Wahrscheinlichkeitsberechnungen bei Tichu 7.1 Die Annäherungsformel 21 23 8 Das Projekt 25 8.1 Die Vereinfachungen 25 8.2 Die Realisation 25 8.3 Der Spielablauf 25 8.4 Das Mischen der Karten 26 8.5 Das Schupfen 26 8.6 Das Berechnen von möglichen Kombinationen 26 8.7 Das Prüfen von Kombinationen 27 8.8 Wahrscheinlichkeit einer Kombination 27 8.9 Die optimalen Kombinationen 27 8.10 Die History 29 8.11 Das Userinterface 29 8.12 Der Computerplayer 29 8.13 Schwellenwahrscheinlichkeitswert-Bestimmung30 8.14 Die Endphase30 8.15 Spielstrategien30 8.16 Schupfen31 -- Oktober 2008 Regelbasierte Systeme am Beispiel Tichu Simon Rösch, 1MNd 8.17 UML-Diagramm von meinem Programm32 9 Fazit 33 10 Quellenverzeichnis 34 10.1 Literatur34 10.2 Internetadressen34 10.3 Computerprogramme34 10.4 Bildnachweis34 11 Anhang 35 11.1 Resultate der Schwellenwahrscheinlichkeitswert-Bestimmung35 11.2 Resultate Offensiv vs. Defensiv35 11.3 Resultate Offensiv vs. Ultraoffensiv36 11.4 Mail von Urs Hostettler37 11.5 Digitaler Anhang38 -- Oktober 2008 Regelbasierte Systeme am Beispiel Tichu Simon Rösch, 1MNd 3 Abstract Ein Programm, das gut Tichu spielen soll, braucht eine Komponente, die entscheidet, wann welcher Zug gemacht werden soll. Dazu eignen sich Regelbasierte Systeme, da diese einen relativ einfachen Weg bieten, das Spielstrategie-Wissen dem Computer zu übergeben. Ein solches Regelbasiertes System ist Drools. Drools basiert auf Java, hat eine einfache Syntax und ist, obwohl es OpenSource ist, äusserst gut dokumentiert. Mit Hilfe von diesem System habe ich ein Programm erstellt, das eine etwas vereinfachte Version von Tichu spielen kann. Dabei eine gute Strategie zu entwickeln erwies sich als äusserst schwierig. Am Schluss hatte ich drei verschiedene Strategien, aus denen ich im Test ermittelte, welche die beste sei. Gesamthaft gesehen, ist es mir aber nicht gelungen, ein Programm zu schreiben, das wirklich gut Tichu spielen kann, da ich mich auch selber beim Tichu Spielen oft auf meine Intuition verlasse, was der Computer nicht kann. Trotzdem war es aber eine sehr interessante Arbeit und ich habe dabei neue Programmiertechniken kennen gelernt und kann das Spiel Tichu jetzt auch von einer ganz anderen Perspektive aus ansehen. -- Oktober 2008 Regelbasierte Systeme am Beispiel Tichu Simon Rösch, 1MNd 4 Regelbasierte Systeme Die Künstliche Intelligenz (englisch „Artificial Intelligence“) ist das Teilgebiet der Informatik, das sich damit befasst Probleme automatisch und intelligent zu lösen. Eine Art, dem Computer Intelligenz beizubringen, sind Expertensysteme. Wie der Name schon sagt, wird dabei versucht dem Computer das gleiche (oder wenn möglich bessere) Wissen zu geben, das auch ein menschlicher Experte auf dem entsprechenden Gebiet hat. Solche Systeme sind dann notwendig, wenn die zu verarbeitenden Daten nicht in schön strukturierter Form vorliegen. Karl Kurbel hat in seinem Buch „Entwicklung und Einsatz von Expertensystemen“ [L1] ein Expertensystem wie folgt definiert: „Ein Expertensystem ist ein Programm, das in einem eng abgegrenzten Anwendungsbereich die spezifischen Problemlösungsfähigkeiten eines menschlichen Experten zumindest annähernd erreicht oder übertrifft.“ Das wichtigste in einem Expertensystem ist das Wissen, denn darauf basiert das ganze Programm. Dieses Wissen kann aber in verschiedenen Formen vorliegen wie z.B. in Objekten, Constraints oder Regeln. Expertensysteme, die auf Regeln basieren, nennt man regelbasierte Systeme. Da es mir am einfachsten schien, das Wissen für die Strategie eines „künstlichen Tichuphilen“ mit Regeln darzustellen, wählte ich für mein Programm ein Regelsystem. Wie immer in der Informatik wären sicher auch andere Lösungswege möglich gewesen. 4.1 Regelbasierte Logik Eine Regel besteht immer aus einer Prämisse und einer Konklusion und hat den Aufbau Wenn Prämisse, dann Konklusion. Die Prämisse bezieht sich immer auf eine Faktenbasis und beschreibt die Situation, die eintreten muss, damit die Regel feuert, das heisst, die Konklusion ausgeführt wird. Die Prämisse wird oft auch „left-hand side“ genannt, da sie die linke Seite der Regel stellt. Analog dazu nennt man die Konklusion auch „right-hand side“. Die Konklusion kann in einem Regelsystem ganz unterschiedlich aussehen: Sie kann beispielsweise ein direktes Resultat enthalten, die Faktenbasis verändern oder neue Fakten zur Faktenbasis hinzufügen resp. Fakten entfernen. Durch die Veränderung der Faktenbasis werden nun die Prämissen anderer Regeln erfüllt, was zur Folge hat, dass diese gefeuert werden müssen, was wiederum ein Resultat oder eine weitere Veränderung der Faktenbasis zur Folge hat. Auf diese Weise können mit Regeln und dazugehöriger Faktenbasis Probleme gelöst werden. Solche Regeln können jedoch auch zu Widersprüchen führen, die das Regelsystem lösen können muss. Regel 1: Wenn der Kunde eine Kundenkarte hat, dann gibt es Fr. 10.Reduktion. Regel 2: Wenn das Produkt aus der Elektrogeräteabteilung kommt und mehr als Fr. 250.- kostet, dann gibt es 10% Rabatt. Beispiel 4.1 Was muss nun der Kunde bezahlen, der eine Kundenkarte besitzt und ein Produkt aus der Elektrogeräteabteilung kaufen will, das im Originalpreis 255.- kosten würde? Da beide Regeln gleichzeitig zutreffen, sind sie im Konflikt. In diesem Fall muss das Siehe Kapitel 6.1 -- Oktober 2008 Regelbasierte Systeme am Beispiel Tichu Simon Rösch, 1MNd Regelsystem also wissen, welche Regel zuerst ausgeführt werden soll. Dazu gibt es mehrere Möglichkeiten: Den Regeln werden verschiedene Prioritäten zugewiesen, es wird die erste/letzte zutreffende Regel gewählt, es wird die spezifischere/allgemeinere Regel gewählt oder es wird zufällig eine Regel ausgewählt. Weiter stellt sich die Frage, ob überhaupt von beiden Rabatten gleichzeitig profitiert werden kann. Wenn ja, wird dann die Regel 2 noch ausgeführt, nachdem Regel 1 ausgeführt wurde und das Produkt ja eigentlich nur noch Fr. 245.- kosten würde? Das Regelsystem muss also auch genau vorgeben, wann geprüft wird, wie viele und welche Regeln ausgeführt werden. Es bietet sich die Möglichkeit, nur eine bestimmte Anzahl Regeln auszuführen (bspw. nur ein Rabatt, nicht kumulierbar) oder alle Regeln auszuführen, die passen. Auch entscheidend ist, ob nach dem Ausführen einer Regel erneut geprüft wird, welche Regeln zutreffen (also die Faktenbasis aktualisiert wird) oder die Regeln nur für eine Faktenbasis überprüft werden. Wie diese Probleme gelöst werden, hängt vom jeweiligen Regelsystem ab. Oft hat der Anwender aber auch die Möglichkeit, gewisse Teile der Konfliktlösungsstrategien selber zu definieren. Aber auch noch mit Hilfe dieser Konfliktlösungsstrategien sind nicht alle Probleme gelöst, denn was passiert, wenn es 2 Regeln gibt, Regel 1: Wenn A < 5, dann A = A·A Regel 2: Wenn A > 5, dann A = 3 Beispiel 4.2 und die Faktenbasis nach dem ausführen jeder Regel neu geladen wird? – Man befindet sich in einer Endlosschleife und das Regelsystem wird früher oder später abstürzen. Obwohl diese beiden Regeln kaum jemand programmieren würde, muss der Programmierer auch beim Aufstellen von Regeln aufpassen und sich immer ganz im Klaren sein, was er genau macht. Ein weiteres Regelbeispiel: Regel 1: Regel 2: Wenn ein Tier 2 Beine und 2 Flügel hat, dann ist es ein Vogel. Wenn ein Vogel klein ist und eine rote Brust hat, dann ist es ein Rotkehlchen. Beispiel 4.3 Diese beiden Regeln können nun verschieden angewendet werden. Man kann daraus schliessen, dass ein kleines Tier mit 2 Beinen, 2 Flügeln und einer roten Brust ein Rotkehlchen ist. Dabei handelt es sich um die „Vorwärtsverkettung“. Es gibt aber auch die Möglichkeit, die Regeln umzukehren und daraus zu schliessen, dass ein Rotkehlchen ein kleiner Vogel mit roter Brust ist. Diese Methode wird dann „Rückwärtsverkettung“ genannt. Es macht aber nicht immer Sinn, Regeln umzukehren. Regel: Wenn ich ins Dählhölzli gehen will, dann muss ich zuerst nach Bern fahren. Beispiel 4.4 Wenn wir diese Regeln umkehren, erhalten wir als Resultat, dass ich ins Dählhölzli gehen will, wenn ich nach Bern fahre, was nicht immer zutreffen muss. -- Oktober 2008 Regelbasierte Systeme am Beispiel Tichu Simon Rösch, 1MNd 4.2 Der Aufbau eines regelbasierten Systems Grundsätzlich haben alle regelbasierten Systeme den gleichen Aufbau. Im „Working Memory“ sind alle Facts gespeichert, die für die Regelanwendung notwendig sind. Das Regelsystem muss also eine Möglichkeit bieten, dem „Working Memory“ Fakten hinzuzufügen, diese zu aktualisieren oder zu entfernen. Im „Producion Memory“ sind alle Regeln gespeichert. Auch hier braucht es je nach Bedarf die Möglichkeit automatisch Regeln anzupassen, hinzuzufügen oder zu löschen. Zwischen diesen beiden Komponenten steht der Regelinterpreter (die Inferenzmaschine, engl. inference engine). Der Regelinterpreter sucht anhand der Fakten im „Working Memory“ die zutreffenden Regeln und führt diese anhand der Konfliktlösungsstrategie aus. Praktisch, aber nicht zwingend notwendig, ist eine Erklärungskomponente, die erklären kann welche Regeln, auf Grund welcher Fakten, in welcher Reihenfolge gefeuert wurden. Dies ist besonders bei der Entwicklung wichtig, da es sonst schwer ist, herauszufinden, wieso das erhaltene Resultat nicht mit dem erwarteten Resultat übereinstimmt. Meistens treten Regelsysteme auch nicht alleine auf, sondern sind Teil einer Applikation. Dann braucht es auch noch Komponenten, die es der Applikation erlauben, das „Working Memory“ und bei Bedarf auch das „Production Memory“ anzupassen. 4.3 Vorteile eines regelbasierten Systems Ein grosser Vorteil von Regeln ist die sehr übersichtliche Struktur der Regeln selber, durch die man Aussagen fast so formulieren kann, wie man es im alltäglichen Leben auch tut. Auf diese Art können sehr schwierige Probleme gelöst werden, die auf „traditionelle“ Art zu programmieren extrem schwierig wäre. Auch kann es sein, dass die Lösung eines Problems gar nicht vollständig bekannt ist, wodurch es unmöglich wäre, ein „traditionelles“ Programm zu schreiben, durch Regeln das Problem aber (annähernd) gelöst werden kann. Zudem lässt die einfache Struktur der Regeln zu, dass ein Experte auf dem jeweiligen Gebiet (nach einer kurzen Einarbeitungszeit) ohne Programmierkenntnisse Regeln selbstständig aufstellen und verändern kann. Ein Regelsystem bietet auch den Vorteil, dass genau erklärt werden kann, wieso was ausgeführt worden ist. Dies kann gerade in der Entwicklungsphase extrem wichtig sein, nämlich wenn das Programm nicht die Lösung hervorbringt, die es eigentlich sollte. Ein weiterer Vorteil ist die strikte Trennung zwischen Daten und Logik. Da die Regeln separat gespeichert sind, wird die Logik viel übersichtlicher. Auch kann die Logik schnell ausgetauscht werden, sei es in einem Geschäftsprogramm, bei dem die Regeln oft und schnell ändern oder um zwei verschiedene Spielstrategien in einem programmierten Spiel auszuprobieren. Nach dieser Reihe von Vorteilen eines Regelbasierten Systems stellt sich die Frage, wieso man denn nicht immer Regelsysteme verwendet. Die Drools Dokumentation gibt auf die Frage, wann man ein Regelsystem brauchen soll, folgende Antwort: When there is no satisfactory traditional programming approach to solve the problem. (Deutsch: „Wenn es keinen zufriedenstellenden, traditionellen Weg gibt, um das Problem zu lösen.) [I4] -- Oktober 2008 Regelbasierte Systeme am Beispiel Tichu Simon Rösch, 1MNd Diese Aussage braucht aber noch etwas Erklärung, denn wann gibt es keinen traditionellen Lösungsweg? – Genau dort wo Regelsysteme Vorteile bieten: Wenn es keine algorithmische Lösung gibt, die Logik sich oft verändert oder die Experten selber nicht programmieren können. -10- Oktober 2008 Regelbasierte Systeme am Beispiel Tichu Simon Rösch, 1MNd 5 Drools Auf dem Markt gibt es viele Regelsysteme, die alle ihre Vor- und Nachteile haben. Da ich wusste, dass ich meine Maturaarbeit in Java schreiben wollte, habe ich nach einem Regelsystem gesucht, das auf Java basiert. Im Buch „Java Rules Engines“ von Lars Wunderlich bin ich auf Drools gestossen. Da Drools eine Open Source Rules Engine ist, also im Internet gratis heruntergeladen werden kann, waren auch meine finanziellen Erwartungen erfüllt. Das Buch von Lars Wunderlich bot mir einen einfachen Einstieg und die sehr ausführliche Online-Dokumentation von Drools hat mir die restlichen Fragen beantwortet. 5.1 Der Rete-Algorithmus Wie im Kapitel „4.2. Der Aufbau eines regelbasierten Systems“ erklärt, braucht jedes Regelsystem einen Regelinterpreter, der herausfindet, welche Regeln gefeuert werden sollen. Bei Drools erfüllt dies der etwas angepasste Rete-Algorithmus, der von Dr. Charles Forgy entwickelt und 1978-79 in seiner Dissertation dokumentiert wurde. Der Rete-Algorithmus lässt sich in zwei Teile aufteilen: die Regelerfassung und die Ausführung. Bei der Regelerfassung wird aus den Regeln ein Netzwerk (rete lat. = Netz) erzeugt, das danach bei der Ausführung genutzt wird, um Daten zu filtern und so herauszufinden, welche Regeln feuern sollen. Das Netzwerk besteht aus einer Menge von Nodes (engl. Knoten), die von den Daten von oben nach unten passiert werden müssen. Bei jedem Node können nur die Daten passieren, die der Anforderung entsprechen. Das Netz ist aus grundsätzlich 4 verschiedenen Arten von Nodes aufgebaut: RootNodes (WurzelKnoten), 1-Input-Nodes (1-Eingang-Knoten), 2-Input-Nodes (2-Eingang-Knoten) und Endnodes. Jedes Netzwerk beginnt mit dem RootNode. An diesem Punkt werden alle Objekte aus dem „Working Memory“ in das Netzwerk eingefügt. Anschliessend kommt für jedes Objekt, das irgendwo in den Prämissen der Regeln vorkommt, ein ObjectTypNode, der zu den 1-Input-Nodes (1-Eingang-Knoten) gehört. Bei diesen Nodes werden nur die Objekte von einem bestimmten Typ durchgelassen. Nachdem die Objekte nach ihrem Typ sortiert wurden, können für die jeweiligen Objekte Variablen auf bestimmte Werte geprüft werden. Dies geschieht bei Abb. 1: Beispiel eines Rete-Netzwerkes -11- Oktober 2008 Regelbasierte Systeme am Beispiel Tichu Simon Rösch, 1MNd den AlphaNodes, die wiederum zu den 1-Input-Nodes gehören. Nun kann es aber auch sein, dass in einer Regel zwei Werte miteinander verglichen werden. Dazu dienen die beiden 2-Input-Nodes. Die beiden Eingänge werden linker und rechter Eingang genannt. Der linke Eingang übernimmt eine Liste von Objekten, ein sogenanntes Tupel, das durch den 1-InputNode LeftInputNodeAdapter erstellt wird. Der rechte Eingang übernimmt ein normales einzelnes Objekt. Dieses Objekt wird dann mit jedem Objekt aus dem Tupel verglichen und die Paare, die passen, werden weitergeleitet. Es gibt zwei Arten von 2-Input-Nodes: Der JoinNode prüft zwei Werte zweier Objekte und liefert sie weiter, wenn sie übereinstimmen, der NotNode macht genau das Gegenteil, liefert die Objekte also weiter, wenn die geprüften Werte nicht übereinstimmen. Der letzte Node ist der Endnode. Ein solcher wird erreicht, wenn alle Bedingungen einer Regel erfüllt sind. Der Vorteil vom Rete-Algorithmus ist, dass im Vergleich zu einem ganz naiven Regelinterpreter, der jede Regel einzeln prüft, mit einem Rete-Netzwerk schnell und mit nur wenig Aufwand die Regeln gefunden werden, deren Prämissen erfüllt sind. Gerade bei grossen Datenmengen ist dies von grosser Bedeutung. 5.2 Die Regelsprache Drools besitzt eine eigene Regelsprache, die jedoch im Aufbau nicht kompliziert ist und für Java-Programmierer sehr einfach zu erlernen ist. Die Regeln werden in einer (oder mehreren) Datei gespeichert, die typischerweise die Endung .drl hat, was aber nicht zwingend ist. In einer solchen Datei können beliebig viele Regeln und Funktionen abgespeichert werden. Wie bei Java-Klassen können auch die Regeldateien in Packages zusammengefasst werden. Dies wird über den Befehl „package PackageName“ erreicht, welcher am Anfang der Datei stehen muss. Die Reihenfolge der folgenden Elemente einer Regeldatei spielt keine Rolle. Ich werde die einzelnen Elemente anschliessend der Reihe nach erläutern, zuerst aber noch einige allgemeine Bemerkungen zur Regelerstellung in Drools: Kommentare können wie in Java einzeilig mit // und mehrzeilig mit /* ... */ erstellt werden. Zusätzlich können einzeilige Kommentare auch mit # anstelle von // eingeleitet werden. Weiter gibt es auch bei Drools eine Liste von reservierten Wörtern, die nicht benutzt werden dürfen, ausser natürlich in ihrer jeweiligen Funktion: rule, query, when, then, end, null, and, or, not, exists, collect, accumulate, from, forall, true, false und eval. Weiter gibt es eine Liste mit Wörtern die man besser auch nicht benutzt, obwohl es in den meisten Fällen wahrscheinlich funktionieren würde: package, function, global, import, template, attributes, enabled, salience, duration, init, action, reverse, result, contains, axcludes, memberOf, matches, in, date-effective, date-expires, no-loop, auto-focus, activation-group, agenda-group, dialect und rule-flow-group. Die Semikola (`;`) zum abschliessen eines Befehls sind in der Prämisse optional, in der Konklusion jedoch zwingend notwendig. Zeilenumbrüche sind an jeder Stelle optional. Es empfiehlt sich jedoch seine persönliche Darstellung zur Strukturierung des Codes zu entwickeln. import Analog zu Java funktioniert auch der import-Befehl in Drools. Die Klasse java.lang sowie Klassen aus dem selben package werden automatisch importiert, alle restlichen Klassen, die benötigt werden, müssen mit diesem Befehl importiert werden. -12- Oktober 2008 Regelbasierte Systeme am Beispiel Tichu Simon Rösch, 1MNd global Der Vollständigkeit halber sei hier erwähnt, dass es die Möglichkeit gibt, globale Variablen in Drools zu definieren. Diese dürfen aber nicht verändert werden, da dies der Regelinterpreter nicht bemerken würde, weil sie nicht Teil des „Working Memory“ sind. function Mit function bietet Drools die Möglichkeit in der Regeldatei selber Methoden zu definieren. Dies ist praktisch, wenn man mehrere Regeln mit der selben Konklusion hat, die dann einfach nur noch den Methodenaufruf enthält. Der Aufbau der Methode ist gleich wie in Java: function int add(int a, int b){ return a+b; } Beispiel 5.1 Mit function hat man aber auch die Möglichkeit Methoden aus anderen Klassen zu importieren. Dies funktioniert mit folgender Syntax: import function mein.package.Klasse.add; Beispiel 5.2 In beiden Fällen können die Funktionen ganz einfach über ihren Namen aufgerufen werden. System.out.print( add(1, 2) ) //Ausgabe: 3 Beispiel 5.3 rule Der Aufbau einer Regel ist simpel: rule „<Name>“ <Attribute> when <Prämisse> then <Konklusion> end Beispiel 5.4 Der Name ist der Name der Regel, der praktischerweise auch etwas über die Regel aussagt (Namen wie Regel 1, Regel 2 führen bei grösseren Regelmengen schnell zur Unübersichtlichkeit). Es dürfen nicht zwei Regeln mit dem selben Namen existieren, ansonsten gibt es einen Fehler beim Laden der Regeln. Eine Regel kann diverse Attribute haben, ich möchte hier die wichtigsten kurz beschreiben: No-loop übernimmt einen Wert vom Typ Boolean, Standard ist false. Wenn die Konklusion der Regel einen Fakt so verändert, dass die Regel erneut zutreffen würde, wird die Regel nur ausgeführt, wenn no-loop auf false gesetzt ist. No-loop = true verhindert ein erneutes ausführen der Regel. Salience übernimmt einen Wert vom Typ Integer, Standard ist 0. Salience ist eine Art -13- Oktober 2008 Regelbasierte Systeme am Beispiel Tichu Simon Rösch, 1MNd Priorität, das heisst Regeln mit höherem Salience Wert werden zuerst ausgeführt. Die Prämisse setzt sich bei Drools aus null oder mehr Bedingungen zusammen. Ist die Prämisse leer, ist sie immer erfüllt und die Regel wird immer ausgeführt. Die wichtigste Art Bedingungen zu formulieren sind Pattern. Mehrere Pattern werden standardmässig durch UND verknüpft. Das einfachste Pattern ist eines ohne constraints, das nur einen Objekt-Typ prüft. Für die Prämisse Buch( ) Beispiel 5.5 wird die Regel für jedes Objekt vom Typ Buch im „Working Memory“ ausgeführt. Damit man weiss, welches Objekt gepasst hat und dieses weiterverarbeiten kann (in einer zweiten Bedingung der Prämisse oder in der Konklusion), muss es in einer Variable gespeichert werden. Variablen in Drools können das Vorzeichen `$` haben, welches nicht zwingend notwendig ist, aber der Übersichtlichkeit dient. Einer Variable kann man mit `:` ein Objekt zuweisen. $b : Buch() Beispiel 5.6 Ein Pattern kann aber auch Bedingungen, sogenannte Constraints, enthalten. Mehrere Constraints werden mit `&&` (UND), `||` (ODER) oder `,` (UND) verbunden: $b : Buch( autor==“Franz Hohler“, neu=true ) //Buch vom Autor Franz Hohler das neu ist Beispiel 5.7 Die Connectors werden in der Reihenfolge `&&`, `||`, `,` berücksichtigt. Durch Setzen von Klammern, kann dies geändert werden: $b : Buch( autor==“Franz Hohler“ && preis<=20 || neu==true) //Buch, das von Franz Hohler ist und weniger als 20.- kostet oder ein //Buch, das neu ist $b : Buch( autor==“Franz Hohler“ && (preis<=20 || neu==true) ) //Buch, das von Franz Hohler ist und weniger als 20.- kostet oder neu ist Beispiel 5.8 Die Werte der Objektevariablen werden überprüft indem beim Objekt die Funktion getVariablenname aufgerufen wird. Diese Funktion muss natürlich im Objekt als public Funktion ohne Argumente definiert sein und den Variablenwert zurückliefern. Analog dazu braucht Drools zum Setzen von Variablenwerten (in der Konklusion) die Funktion setVariablenname(variablentyp variable). Diese braucht aber zum Setzen eines Wertes nicht aufgerufen zu werden, sondern kann wie üblich mit $objekt.variable = 123; Beispiel 5.9 gesetzt werden; Drools wandelt das dann zu einem Funktionsaufruf um. Drools bietet auch sämtliche Vergleichsoperatoren: `<`, `<=`, `=>`, `>`, `==`, `!=`. Dazu kommen je nach Variablentyp noch weitere spezifische Operatoren, auf die ich hier nicht weiter eingehen möchte. Weiter bietet Drools Operatoren zum Testen von Bedingungen, die für jedes Objekt -14- Oktober 2008 Regelbasierte Systeme am Beispiel Tichu Simon Rösch, 1MNd eines Types im „Working Memory“ gelten müssen (forall), für die Existenz eines Objektes (exists) resp. die Nichtexistenz (not) oder für die Existenz des einen oder des anderen (or). In der Konklusion der Regel kann normaler Java-Code programmiert werden. Auch auf die in der Prämisse in Variablen gespeicherten Objekte kann wie auf ein normales Java-Objekt zugegriffen werden. Drools bietet zudem noch Methoden zum Aktualisieren des „Working Memory“. Mit update(); kann dem „Working Memory“ mitgeteilt werden, dass ein Objekt aktualisiert wurde. Wird dies nicht getan, werden weitere Regeln so ausgeführt, als ob das Objekt nicht verändert worden wäre. Mit retract(); kann ein Objekt aus dem „Working Memory“ entfernt werden und mit insert(); kann analog dazu ein neues Objekt eingefügt werden. 5.3 Der Einbau in ein Java-Programm Bis jetzt habe ich immer nur über „Working Memory“ etc. geschrieben, aber wie das in Java dann wirklich aussieht, habe ich nicht erklärt. Damit Drools läuft, müssen die Drools Librarys verfügbar sein und die entsprechenden Klassen importiert werden. Danach muss zuerst eine RuleBase erzeugt werden. Dazu schreibt man sich am besten eine Funktion, die das Einlesen der Regeln übernimmt. Man muss nämlich zuerst die Regeldatei einlesen, dann daraus ein Package machen und dieses in die RuleBase einfügen. public static RuleBase readRule() throws Exception{ Reader source = new InputStreamReader( DroolsTest.class. getResourceAsStream(„/Regeldatei.drl“)); PackageBuilder builder = new PackageBuilder(); builder.addPackageFromDrl( source ); Package pkg = builder.getPackage(); RuleBase ruleBase = RuleBaseFactory.newRuleBase(); ruleBase.addPackage( pkg ); return ruleBase; } Beispiel 5.10 Das „Working Memory“ selber ist ein Objekt vom Typ StatefulSession, das aus der ruleBase, die wir oben erstellt haben, erstellt werden kann: final StatefulSession workingMemory = ruleBase.newStatefulSession(); Beispiel 5.11 Danach können dem „Working Memory“ beliebig Objekte hinzugefügt werden, was über die Funktion des StatefulSession-Objekts insert(Object) geschieht. workingMemory.insert(buch); Beispiel 5.12 Wenn alle Objekte hinzugefügt wurden, kann das Feuern der Regeln mit fireAllRules() ausgelöst werden. workingMemory.fireAllRules(); -15- Beispiel 5.13 Oktober 2008 Regelbasierte Systeme am Beispiel Tichu Simon Rösch, 1MNd Damit es nach mehrmaligem Ausführen dieses Prozesses nicht zum Speicherüberlauf kommt, muss die Funktion workingMemory.dispose(); aufgerufen werden, welche die Referenz auf das Objekt in der ruleBase löscht, damit die Garbage Collection das Objekt löschen kann. 5.4 Das Eclipse-Plugin Drools bietet ein Plugin für die Java-Entwicklungsumgebung Eclipse, das praktisch, aber nicht zwingend notwendig ist. Das Plugin ermöglicht es, Drools-Projekte zu erstellen, die dann auch schon die benötigten Librarys eingebunden haben und je nach Wunsch auch schon eine Beispiel-Klasse mit zugehöriger Regeldatei beinhaltet. Wenn das Plugin installiert ist, werden Drools-Regeldateien automatisch als solche erkannt und der Umgang wird durch farbige Hervorhebung der Keywords erleichtert. Weiter kann das Plugin auch das Rete-Netzwerk einer Regeldatei anzeigen, es zeigt einem also, wie die Regeln schliesslich umgesetzt werden. Schade am Plugin ist, dass es die Referenzen in Regeldateien auf andere Teile im Javacode nicht erkennt. Dies führt zum Beispiel dazu, dass, wenn eine Klasse oder eine Variable umbenennt wird, dies in den Regeldateien nicht automatisch aktualisiert wird. Da dies in Eclipse ansonsten sehr einfach funktioniert, vergisst man oft, beim Ändern eines Namens dies auch in der Regeldateien zu tun, was aber glücklicherweise meist in einer Fehlerausgabe des Drools-Compiler endet. -16- Oktober 2008 Regelbasierte Systeme am Beispiel Tichu Simon Rösch, 1MNd 6 Tichu Tichu ist ein Kartenspiel für 4 Spieler, welche in zwei Teams aufgeteilt sind, die sich übers Kreuz gegenüber sitzen. Ein Tichuspiel besteht aus mehreren Runden und endet in der Regel sobald ein Team mindestens 1000 Punkte erreicht hat. Gespielt wird mit 56 Karten, nämlich den Karten 2-10, J (Bauer), Q (Dame), K (König) und A (Ass) in je 4 Farben (rot, grün, blau und schwarz) und 4 Sonderkarten. Das Ziel des Spieles ist es, möglichst schnell seine Karten abzulegen, dabei möglichst viele Punkte zu machen und wenn möglich auch noch mit dem Partner zusammen zu spielen. 6.1 Geschichte Tichu ist in Europa seit 1991 bekannt. Die in der Spielanleitung von Fata Morgana beschriebene Geschichte, dass Tichu in China, genauer in der Region Nanjing täglich von Millionen von Chinesen gespielt wird, wurde mir vom offiziellen Schweizer Autor des Spieles, Urs Hostettler bestätigt. Er wies mich jedoch darauf hin, dass er dem Spiel noch die Sonderkarten und das Schupfen hinzugefügt hat. Ebenfalls gilt in China, im Gegensatz zu Europa, meist die 2 als höchste Karte und nicht das Ass. Tichu ist seither auch noch in anderen Verlagen erschienen und wird neben der Schweiz auch in Deutschland oft gespielt. Es finden auch jährlich mehrere Tichumeisterschaften statt. Bei der Deutschen Tichu-Meisterschaft (kurz DTM), die seit 1994 jährlich (bis 1998 in Dortmund, seither in Würzburg) stattfindet, ist es Tradition, dass der Sieger für ein Jahr bestimmen darf, wie ein „Tichuspieler“ genannt werden soll, da diese Frage schon in der Spielanleitung von Fata Morgana aufgeworfen wurde. So kam es dazu, dass man 1998 vom „Tichupathen“, 2001 vom „Tichupotter“ oder 2008 von „Tichuphilen“ sprechen sollte. Seit einigen Jahren kann man Tichu auch online in der sogenannten Brettspielwelt (www.brettspielwelt.de) mit Usern aus der ganzen Welt zusammen spielen. Es finden auch dort immer wieder online Tichu-Turniere statt. Laut Wikipedia soll es bis jetzt noch kein Programm geben, das es ermöglicht offline gegen den Computer Tichu zu spielen. 6.2 Der Autor Urs Hostettler wurde am 14. August 1949 in Bern geboren. Er studierte Mathematik und ist mit einer Psychologin verheiratet. Auch heute lebt er noch in Bern und arbeitet für den Spieleverlag Fata Morgana. Er war 1982 auch Mitgründer des bekannten Berner Spielladens „Drachennest“. Neben Tichu hat er noch andere bekannte und fast ebenso gute Spiele erfunden, wie bspw. „Anno Domini“ oder „Kreml“. Urs Hostettler entwickelt aber nicht nur neue Spiele, sondern spielt auch immer wieder selber mit. So gewann er beispielsweise 1997 die DTM. Er ist aber auch als Schriftsteller sowie als Musiker tätig. Abb. 2: Urs Hostettler im Mai 2007 -17- Oktober 2008 Regelbasierte Systeme am Beispiel Tichu Simon Rösch, 1MNd 6.3 Die Spielvorbereitungen Zu Beginn des Spieles werden die Karten verteilt. Der Sieger der letzten Runde mischt die Karten, lässt abheben, legt den Kartenstapel in die Tischmitte und nimmt sich die oberste Karte. Reihum nehmen sich alle Spieler jeweils die oberste Karte, bis keine mehr vorhanden ist. Diese Verteilmethode ist am Anfang etwas ungewohnt, aber man gewöhnt sich daran. Auch diese Tradition wurde aus China importiert. Vor Spielbeginn muss nun jeder Spieler jedem Mitspieler eine Karte „schupfen“. Das heisst jeder Spieler legt vor jeden Mitspieler eine seiner Handkarten verdeckt auf den Tisch, die er diesem geben will. Da er dadurch auch drei Karten bekommt, hat er schliesslich wieder 14 Karten auf der Hand. Der Spieler, der nun die Karte Mahjong (siehe 6.5. Sonderkarten) auf der Hand hält, beginnt mit ausspielen. Abb. 3: Die Tichu-Karten von Fata Morgana 6.4 Die Spielregeln Viele Regeln gibt es eigentlich nicht. Wenn man am ausspielen ist, hat man 6 Spielmöglichkeiten. Entweder man spielt eine einzelne Karte, ein Paar, ein Trio, ein Fullhouse, das aus einem Paar und einem Trio besteht, eine Strasse, die aus mindestens fünf aufeinanderfolgenden Einzelkarten besteht oder eine Paarfolge, eine so genannte Treppe, die aus beliebig vielen aufeinanderfolgenden Paaren besteht. Es ist auch erlaubt Bomben auszuspielen, dazu siehe Kapitel Bomben. Der in Spielreihenfolge nächster Spieler hat nun 2 Möglichkeiten. Entweder er passt, das heisst er sagt: „Ich passe!“ und gibt somit das Spiel an den nächsten Spieler weiter, oder er spielt die gleiche Kombination wie der Spieler vor ihm, aber mit höherem Wert. Über die Höhe einer Kombination entscheidet grundsätzlich die tiefste Karte, ausser bei einem Full House, bei welchem das Trio massgebend ist. Es ist zu beachten, dass exakt die gleiche Kombination gespielt werden muss. Das heisst eine Strasse mit sechs Karten kann nicht mit einer Strasse mit fünf oder sieben Karten überspielt werden, sondern nur mit einer Strasse mit ebenfalls sechs Karten. Passen nacheinander drei Spieler, gehört der Stich dem Spieler der die letzten Karten gespielt hat. Er kann nun die Karten verdeckt vor sich ablegen und kommt ans Aus -18- Oktober 2008 Regelbasierte Systeme am Beispiel Tichu Simon Rösch, 1MNd spielen. Sollte er keine Karten mehr haben, „erbt“ der in Spielreihenfolge nächste Spieler das Ausspielrecht. Abb. 4: Mögliche Kombinationen: Linke Spalte: Einzelkarte, Paar, Trio, Fullhouse (v.o.n.u.) Rechte Spalte: Strasse, Treppe, Bombe, Strassenbombe (v.o.n.u.) 6.5 Die Sonderkarten Es gibt 4 Sonderkarten: Hund, Mahjong, Phönix und Drache. Hund Der Hund kann nur als einzelne Karte ausgespielt werden. Nach dieser Karte kann der Partner erneut eine beliebige Kartenkombination ausspielen. Ist der Partner nicht mehr im Spiel, erbt der in Spielreihenfolge nächste Spieler. Mahjong Der Mahjong ist die 1. Wer diese Karte besitzt, beginnt das Spiel. Der Mahjong kann als Einzelkarte mit dem Wert 1 gespielt oder in einer Strasse eingebaut werden. Beim Ausspielen des Mahjongs kann sich der Ausspieler einen Kartenwert wünschen (Bsp. 7 – keine Farbe und keine Sonderkarten). Sobald ein Spieler eine Karte mit diesem Wert spielen kann, ohne eine Spielregel zu verletzen, muss er das tun. Abb. 5: Hund Abb. 6: Mahjong Phönix Der Phönix ist eine Art Joker. Er kann als Einzelkarte gespielt werden, wobei er ausgespielt einen Wert von 1,5 hat und ansonsten hat er immer ein halbes mehr Wert als die Karte die zuvor gespielt wurde. Er kann aber auch als Joker in eine Kombination eingebaut werAbb. 7: Phönix -19- Oktober 2008 Regelbasierte Systeme am Beispiel Tichu Simon Rösch, 1MNd den, in der er eine beliebige Karte ersetzt. Der Nachteil der Karte: Sie gibt -25 Punkte. Drache Der Drache ist die absolut höchste Einzelkarte, auch höher als ein auf ein Ass gespielter Phönix. Er gibt zwar 25 Punkte, der Stich darf aber nicht zu sich genommen werden, sondern muss einem der beiden Gegner abgegeben werden. Abb. 8: Drache 6.6 Bomben Es gibt zwei Arten von Bomben: Vier Karten mit dem gleichen Wert oder eine Strasse in derselben Farbe. Bomben können jederzeit gespielt werden, auch wenn man nicht an der Reihe ist, und sind das absolut höchste. Nachdem ein Spieler eine Bombe gespielt hat, kommt der in Spielreihenfolge nächste Spieler nach ihm an die Reihe. Eine Bombe kann nur mit einer höheren Bombe überspielt werden. Strassen-Bomben sind höher als Vierer-Bomben. Strassen-Bomben mit mehr Karten sind höher als StrassenBomben mit weniger Karten. Ansonsten gelten die üblichen Regeln für die Höhe. 6.7 Das Ende einer Runde Hat nur noch ein Spieler Karten, ist die Runde zu Ende. Der Spieler, der noch Karten hat, gibt seine restlichen Handkarten an das Gegnerteam und seine Stiche an den Spieler, der als erster fertig wurde. Im Team werden nun die Punkte der Stiche zusammen gezählt: Die 5er zählen 5 Punkte, die 10er und Könige je 10 Punkte, Phönix -25 Punkte und Drache 25 Punkte, also total 100 Punkte. Werden beide Spieler eines Teams als erstes nacheinander fertig, ist das Spiel ebenfalls zu ende. Dieses Team hat dann einen sogenannten Doppelsieg erreicht und erhält 200 Punkte, während die Gegner leer ausgehen. 6.8 Das Ansagen Das lustigste am ganzen Spiel ist das sogenannte Ansagen. Jeder Spieler hat die Möglichkeit, bevor er seine erste Karte ausspielt, ein Tichu anzusagen. Falls der Spieler dann als erster fertig wird, bekommt sein Team 100 Punkte zusätzlich. Wird jedoch ein anderer Spieler als erster fertig, bekommt das Team -100 Punkte. Es gibt auch das „Grosse Tichu“, welches eigentlich genau gleich funktioniert wie das normale „Tichu“, muss aber bereits vor dem Aufnehmen der 9. Karte angesagt werden und gibt ± 200 Punkte. Das „Grosse Tichu“ wird eigentlich nur relativ selten ausgesprochen, da es mit 8 Karten noch sehr schwierig abzuschätzen ist, ob man als erster fertig wird. Oft gibt es aber die Situation, dass nur mit dem Aussprechen eines „Grossen Tichus“ der Gegner noch eingeholt werden kann. Das normale Tichu (auch „Kleines Tichu“ genannt) ist um einiges häufiger. Bei erfahrenen Spielern wird durchschnittlich etwa in 2 von 3 Runden ein Tichu ausgesprochen. Da mit einem Tichu gleichviele Punkte erreicht werden wie mit den Stichpunkten, sind für das Endresultat des Spieles oft nur die ausgesprochenen Tichus entscheidend. -20- Oktober 2008 Regelbasierte Systeme am Beispiel Tichu Simon Rösch, 1MNd 7 Wahrscheinlichkeitsberechnungen bei Tichu Damit der Computer die Stärke einer Kombination abschätzen kann, muss er berechnen können, wie gross die Wahrscheinlichkeit ist, dass er mit dieser Kombination einen Stich macht. Diese Wahrscheinlichkeit entspricht der Wahrscheinlichkeit, dass die beiden Gegner keine Kombination haben, mit der sie die Kombination des Computers abstechen könnten. (Ein guter Tichu-Partner sticht den Partner nicht ab, wenn dieser die Möglichkeit auf einen Stich hat.) Die Wahrscheinlichkeit, dass die beiden Gegner keine höhere Kombination haben, ist eins minus die Wahrscheinlichkeit, dass sie eine haben. Die Wahrscheinlichkeit, dass sie eine haben, ist die Wahrscheinlichkeit für den Gegner 1 + die Wahrscheinlichkeit für den Gegner 2 - die Wahrscheinlichkeit, dass beide eine haben. Ich möchte nun zeigen, wie die Wahrscheinlichkeit, dass ein Gegner eine höhere Kombination hat, berechnet werden kann. Ich werde es am Beispiel des Trios machen und von einem Spezialfall ausgehend immer allgemeiner werden. Dazu müssen aber zuerst einige Variablen eingeführt werden, die das Wissen des Computers wiedergeben: . Nehmen wir an, in X gebe es nur noch ein Trio, das heisst nur noch von einem Kartenwert sind noch 3 Karten vorhanden, 4 sind an keinem Ort mehr vorhanden. Das noch mögliche Trio habe die Höhe 10. Der Computer soll nun berechnen, wie gross die Wahrscheinlichkeit ist, dass er mit seinem Trio mit der Höhe 3 einen Stich macht. Er muss nun also berechnen, wie gross die Wahrscheinlichkeit ist, dass einer der beiden Gegner dieses Trio hat. In diesem Spezialfall, indem nur noch ein Gegner ein Trio haben kann, darf er die Wahrscheinlichkeit für den Gegner 1 und die Wahrscheinlichkeit für den Gegner 2 addieren. Die Wahrscheinlichkeit für einen Gegner berechnet sich als Anzahl günstige Fälle über Anzahl mögliche Fälle. Die Anzahl günstige Fälle sind alle Fälle in denen er die Kombination hat und die Anzahl mögliche Fälle sind alle seine möglichen Hände. Um die günstigen Fälle zu berechnen, können aus X weitere 3 Karten abgezogen werden und auch von den Handkarten des Gegners, denn die 3 Karten aus dem Trio muss er sicher haben. Für die restlichen Karten können noch beliebig viele aus X ausgewählt werden: . Die möglichen Fälle lassen sich aus -21- Oktober 2008 Regelbasierte Systeme am Beispiel Tichu Simon Rösch, 1MNd berechnen. Daraus kann die Wahrscheinlichkeit, dass ein Gegner das Trio hat, berechnet werden: . Die Berechnung für Gegner 2 erfolgt genau gleich und da in diesem Fall die Wahrscheinlichkeiten addiert werden dürfen, ergibt sich eine Stichwahrscheinlichkeit von . Erweitern wir den sehr einfachen Fall, dass nur ein weiteres Trio möglich ist auf 2. Sagen wir es sei neben dem 10er-Trio auch noch ein 5er-Trio möglich. Die Wahrscheinlichkeit, dass einer der Gegner ein 10er-Trio hat, berechnet sich immer noch gleich. Dazu kommt aber zusätzlich die Wahrscheinlichkeit, dass einer der Gegner ein 5er-Trio hat. Auch diese kann man über die oben hergeleitete Formel berechnen. Nun muss man vom erhaltenen Resultat noch die Wahrscheinlichkeit zweier Sonderfälle abziehen, da diese doppelt gerechnet wurden: Die Wahrscheinlichkeit, dass ein Gegner beide Trios hat und die Wahrscheinlichkeit, dass die beiden Gegner je ein Trio haben. Die Wahrscheinlichkeit, dass ein Gegner beide Trios hat, lässt sich wie oben berechnen, nur dass er von den X Karten nun zwingend 6 bestimmte haben muss, also: . Die Wahrscheinlichkeit, dass die Gegner je ein Trio haben, heisst, dass jeder Gegner nur ein Trio haben darf. Deshalb müssen in seiner Hand 3 Karten fix sein, aber aus X müssen 6 Karten entfernt werden, da es dort ja zwei Trios gibt. Da bei beiden Gegner ein Trio sein muss, muss man die beiden Werte multiplizieren: . Daraus folgt die kleine Formel für die Stichwahrscheinlichkeit eines Trios der Höhe 3, wenn noch 2 weitere, höhere Trios möglich sind: . -22- Oktober 2008 Regelbasierte Systeme am Beispiel Tichu Simon Rösch, 1MNd Nun müsste man eigentlich auch noch weiter rechnen, denn im Tichu kann es bis zu 12 höhere Trios geben und der Computer müsste für jeden Fall die Wahrscheinlichkeit ausrechnen können. Mathematisch ist es aber sehr aufwändig und am Schluss gäbe es eine riesige Formel. Ich möchte darauf aufmerksam machen, dass wir auch den Fall vernachlässigt haben, in dem von einer Kartenhöhe alle vier Karten in X enthalten sind. Dann gibt es auf dieser Höhe 4 verschiedene Trios, die Formel für ein einzelnes Trio müsste dann noch mit vier multipliziert werden und der Fall abgezogen werden, in dem der Spieler alle 4 Karten hat. Ich würde es mir zutrauen, mit genügend zeitlichem Aufwand alle 12 Formeln zur Stichwahrscheinlichkeitsberechnung von Trios herzuleiten. Bei Paaren wird es jedoch schon viel schwieriger, da es dort noch den Fall geben kann, dass beide Gegner je ein Paar von der selben Höhe haben, der dann auch berücksichtigt werden müsste. Spätestens bei Strassen würde es aber definitiv zu kompliziert für mich, da es bereits mehrere Strassen gibt, wenn nur schon eine Karte der möglichen Strassen doppelt vorkommt etc. Da es für mich aussichtslos erschien, für jeden Fall eine Formel zu finden, mit der ich die Stichwahrscheinlichkeit aller Kombinationen berechnen könnte, habe ich mich dazu entschieden, eine Annäherungsformel zu suchen. 7.1 Die Annäherungsformel Bei der Annäherungsformel habe ich die Wahrscheinlichkeit jeweils für die beiden Gegner einzeln berechnet. Dabei habe ich jeweils folgende Grundformel verwendet: . Dies stimmt für eine Kombination einer bestimmten Höhe, wenn es für diese Kombination nur noch eine Möglichkeit gibt. Da es jedoch für eine Kombination von einer bestimmten Höhe (Bsp. Paar Höhe 7) auch noch mehrere Möglichkeiten geben kann (Falls in X noch drei 7 enthalten sind, noch drei), wird diese Formel mit einem Faktor multipliziert, der angibt, wie viele Karten es für jede Karte in der Kombination durchschnittlich noch zur Verfügung hat. Dieser Faktor berechnet sich aus . Danach wird diese Wahrscheinlichkeit für jede Kombination aufsummiert: . Die Stichwahrscheinlichkeit wird dann wie oben aus -23- Oktober 2008 Regelbasierte Systeme am Beispiel Tichu Simon Rösch, 1MNd berechnet. Da die Formel nicht exakt ist, kann es vorkommen, dass die Wahrscheinlichkeit kleiner 0 ist. Da die Abschätzung aber nur bei grösseren Stichwahrscheinlichkeiten entscheidend ist, wird in einem solchen Fall die Wahrscheinlichkeit auf Null gesetzt, da sie klein zu sein scheint. Die einzige Wahrscheinlichkeit, die nicht direkt mit dieser Formel berechnet werden kann, ist die Wahrscheinlichkeit von Fullhouses. Dort wird zuerst die Wahrscheinlichkeit ausgerechnet, dass einer der Gegner ein Trio hat und anschliessend mit der Wahrscheinlichkeit multipliziert, dass einer ein Paar hat, natürlich nur, falls sie noch fünf oder mehr Karten haben. Diese Abschätzungen sind unexakt, wessen ich mir bewusst bin, aber sie dienen dem Computer abzuschätzen, bei welchen Kombinationen er mit einem Stich rechnen kann und bei welchen nicht, was ohne diese Formel nicht möglich wäre. Es wäre auch zu untersuchen, wie sich Verbesserung dieser Formel auf die Spielstärke des Computers auswirken würde. -24- Oktober 2008 Regelbasierte Systeme am Beispiel Tichu Simon Rösch, 1MNd 8 Das Projekt Nach viel Theorie möchte ich nun zeigen, wie ich diese in der Praxis umgesetzt habe. Das Ziel war es, ein Programm zu schreiben, das Tichu (möglichst gut) spielen kann. Es sollte sowohl möglich sein, dass vier Spieler vom Computer gesteuert werden oder nur drei und einer durch den Benutzer. Da Tichu relativ viele Regeln hat, musste ich das Spiel etwas vereinfachen. Ich will nicht sagen, dass es unmöglich wäre, alle Regeln zu beachten, es hätte aber den Rahmen meiner Arbeit gesprengt. 8.1 Die Vereinfachungen Die einzige Sonderkarte, deren Funktion ich vollständig umgesetzt habe, ist der Hund. Er kann nur alleine ausgespielt werden und danach darf der Partner ausspielen. Beim Mahjong habe ich die Funktion des Wünschens ausgelassen. Phönix und Drache sind beide nur als Einzelkarten spielbar und haben bestimmte Werte (Phönix = Ass + 1, Drache = Ass + 2), der Phönix gibt wie im Originalspiel -25 Punkte, der Drache + 25. Bomben werden in meinem Spiel zwar als eigenständige Kombinationen behandelt, sie können jedoch nur tiefere Bomben der selben Art überspielen. Natürlich können sie wie jede andere Kombination ausgespielt werden. Auch das Ansagen habe ich weggelassen, aber nicht primär wegen der schwierigen Entscheidung, wann ein Tichu angesagt werden soll, sondern weil in einem Spiel mit einem angesagten Tichu strategisch ganz anders gespielt werden müsste. Bei der Planung wollte ich das Schupfen auch weglassen, habe es aber später noch hinzugefügt, da das Schupfen der Teil eines Tichuspiels mit den am besten definierten Strategie-Regeln ist. Ansonsten funktioniert alles wie im Kapitel 6. Tichu beschrieben. 8.2 Die Realisation Ich war mir bewusst, dass es nicht einfach sein wird, ein solches Programm zu schreiben. Deshalb habe ich darauf verzichtet, eine grafische Oberfläche zu programmieren. Als ich vor 10 Monaten begonnen habe, eine erste Version des Programmes zu schreiben, hat mich die Taktik des Computers überhaupt nicht interessiert. Es ging mir darum, ein Programm zu schreiben, in dem der Computer nach den Regeln (mit meinen Vereinfachungen) spielt. Der Computer hat also berechnet, welche Spielmöglichkeiten er hat und daraus, mehr oder weniger zufällig, eine ausgewählt. Als dieses Programm schliesslich fehlerfrei lief, habe ich begonnen mit Drools eine Spielstrategie des Computers zu entwickeln, was sich als grosse Herausforderung herausstellte. Bevor ich jedoch darüber berichte, möchte ich den Aufbau des Grundprogramms erklären. 8.3 Der Spielablauf Ein Tichu-Spiel ist ein Objekt vom Typ game. Dieses besitzt eine Funktion void start() und void start(int runden). Diese Funktion startet das Spiel und regelt danach den ganzen Spielablauf und gibt am Ende der Runde den Punktestand aus. Die beiden Funktionen unterscheiden sich nur darin, dass die ohne Argument das Spiel beendet, : Eine Strassenbombe mit 6 Karten kann nicht über eine Strassenbombe mit 5 Karten gespielt werden. -25- Oktober 2008 Regelbasierte Systeme am Beispiel Tichu Simon Rösch, 1MNd sobald ein Team 1000 oder mehr Punkte erreicht hat, während die andere nach der in runden angegebenen Anzahl Runden das Spiel beendet. Für das Verteilen der Karten, das Schupfen und das Spielen werden dann die jeweiligen Funktionen aufgerufen. Falls ein Spieler vom User gesteuert wird, wird dazu die Klasse userinterface.java verwendet, das Spielen des Computers übernimmt die Klasse computerplayer.java. 8.4 Das Mischen der Karten Da die 56 Karten zufällig auf die vier Spieler verteilt werden sollen, müssen sie zuerst gemischt werden. Dies sollte eigentlich zufällig geschehen, was der Computer aber nicht kann. Was der Computer kann, ist Pseudozufallszahlen generieren, was für das Mischen der Karten ausreichend zufällig ist. Mit der Funktion java.lang.Math. random() können Zufallszahlen zwischen 0 und 1 generiert werden. Dieser Zufallsgenerator hat einen Ausgangszustand, der bestimmt, welche Zufallszahl zurückgegeben wird. Gleichzeitig wird bei einem Funktionsaufruf aber auch anschliessend noch der Zustand des Generators verändert, damit beim nächsten Mal eine neue Zahl ausgegeben wird und nicht immer dieselbe. Solche Algorithmen werden rekursive arithmetische Zufallszahlengeneratoren genannt. Um die 56 Karten zu mischen, wird für die 1. Position eine der 56 Karten ausgewählt, für die zweite, wird dann noch eine aus den verbleibenden 55 Karten ausgewählt. Dieser Misch-Algorithmus gewährleistet, dass jede Kartenreihenfolge gleich wahrscheinlich ist. Beim Verteilen spielt es dann also auch keine Rolle, ob der erste Spieler die ersten 14 Karten bekommt oder die erste, die fünfte, die neunte etc. 8.5 Das Schupfen Jeder Spieler wählt 3 Karten und ordnet diese dem Spieler zu, dem er sie schupfen will. Haben dies alle Spieler getan, tauscht der erste Spieler mit jedem anderen Spieler eine Karte aus, der zweite dann noch mit den zwei verbleibenden und der dritte muss noch mit einem Spieler eine Karte austauschen. Danach müssen die Karten von jedem Spieler neu sortiert werden und die möglichen Kombinationen neu berechnet werden. 8.6 Das Berechnen von möglichen Kombinationen Das Suchen von möglichen Kombinationen ist ziemlich kompliziert. Bei Einzelkarten natürlich nicht, bei Strassen, Treppen oder Fullhouses hingegen schon. Deshalb habe ich mir die Mühe gespart, einen Algorithmus zu schreiben, der diese Kombinationen findet, sondern habe die Karten in alle kombinatorisch möglichen Kombinationen aufgeteilt (Bei 14 Handkarten sind das , was 16‘383 ergibt.) und dann geprüft, ob es eine gültige Kombination ist oder nicht, was viel einfacher ist, als das Suchen von Kombinationen. Im gleichen Schritt wird dann auch noch gerade die Kombinationsart ermittelt, die in einem Integer gespeichert wird. (Einzelkarte = 1, Paar = 2, Trio = 3, Quartett = 4, Treppe = 22, 222, ... 2222222, Fullhouse = 23, Strasse = 5-14, Strassenbombe = 99999905 - 99999914) -26- Oktober 2008 Regelbasierte Systeme am Beispiel Tichu Simon Rösch, 1MNd 8.7 Das Prüfen von Kombinationen Als erstes wird geprüft, ob die Sonderkarten richtig eingesetzt wurden, das heisst nur der Mahjong darf in einer Kombination mit mehr als einer Karte sein, da die anderen Sonderkarten nur als Einzelkarte eingesetzt werden können. Danach wird geprüft: Ist die Länge der Kombination (d.h. die Anzahl Karten) eins, ist es eine Einzelkarte. Ist die Länge zwei und beide Karten haben die gleiche Höhe, ist es ein Paar, bei drei gleich hohen Karten ein Trio. Bei einer Kombination mit vier Karten muss unterschieden werden zwischen Doppelpaar und Quartett, haben alle Karten den gleichen Wert ist es ein Quartett, haben die ersten zwei und die zweiten zwei je die gleiche Höhe und unterscheiden sich in der Höhe um eins, ist es ein Doppelpaar. Auf diese Weise werden dann auch noch Strassen, grössere Treppen und Strassenbomben gefunden. Falls keine Kombination zugeordnet werden konnte, ist die Kombination ungültig und als Resultat wird -1 zurückgegeben. Es gibt auch eine Kombination ohne Karte, das Passen, die den Wert 0 hat. 8.8 Wahrscheinlichkeit einer Kombination Mit der unter 7 Wahrscheinlichkeitsrechnung bei Tichu hergeleiteten Formel, kann die Stichwahrscheinlichkeit einer Kombination ungefähr berechnet werden. Da dazu die Binomialkoeffizienten benötigt werden und Java dazu standardmässig keine Methode bietet, musste ich diese selber schreiben. Auch die Funktion der Fakultät bietet Java standardmässig leider nicht. Da mein Programm aber bis 42! (42! = 1.4·1051) rechnen können muss, reichen der Wertebereich der von int (-231 ... 231-1) und long (-263 ... 263-1) bei weitem nicht aus. Für solche Fälle stellt Java die Klasse BigInteger und BigDouble zur Verfügung, die es ermöglicht beliebig grosse Zahlen darzustellen. Das Rechnen mit solch grossen Zahlen ist etwas gewöhnungsbedürftig, da jede Rechenoperation eine Methode des Objektes ist. BigInteger gross = new BigInteger.ValueOf( Math.pow(10, 10) ); gross = gross.multiply( gross.add( BigInteger.ONE ) ); Beispiel 8.1 Über die Methode ValueOf() kann ein BigInteger erzeugt werden, der dann den Wert hat, der im Argument vom Typ long angegeben wird. Für die Werte 0, 1 und 10 gibt es die direkte Möglichkeit ein Objekt zu erzeugen. Um einen BigInteger wieder zurück in einen normalen Integer zu verwandeln (falls das möglich ist), bietet die Klasse die Methode intValue(). BigDouble funktioniert analog zu BigInteger. 8.9 Die optimalen Kombinationen Strategisch hat es sich als praktisch herausgestellt, die „optimalen“ Kombinationen zu berechnen. In allen optimalen Kombinationen darf jede Karte der Hand nur einmal gebraucht werden. Eine Möglichkeit für die optimalen Kombinationen, wären 14 Einzelkarten. Es versteht sich, dass dies strategisch (in den meisten Fällen) sehr ungeschickt wäre. Je grösser eine Kombination, desto kleiner ist die Wahrscheinlichkeit, dass jemand darüber spielen kann. Um die grössten Kombinationen zu finden, teilt das Programm die Karten in Bereiche auf, in denen kein Wert fehlt. -27- Oktober 2008 Regelbasierte Systeme am Beispiel Tichu Simon Rösch, 1MNd 2r, 2g, 3r, 3g, 4b, 7g, 8r, 10r, Jr, Qs, Kr, Ks, Ph, Dr 2r, 2g, 3r, 3g, 4b | 7g | 9g, 10r, Jr, Qs, Kr, Ks | Ph, Dr Beispiel 8.2 Danach wird in jedem Bereich einzeln geklärt, welches die optimale Kombination ist, da nur die Fullhouses Karten aus mehreren Bereichen benötigen können, was später berücksichtigt wird. Die Bereiche werden unterschieden in solche mit weniger als fünf Werten und solche mit fünf oder mehr Werte. Im Beispiel 8.2 haben alle Bereiche ausser der dritte weniger als fünf verschiedene Werte. In diesen Bereichen sind die einzigen möglichen Kombinationen Einzelkarten, Paare, Trios und Quartette. Für jeden Wert wird also geschaut, wie viele Karten mit diesem Wert vorhanden sind und die entsprechende Kombination als optimal gesetzt. Dabei muss noch überprüft werden, ob Treppen bestehen. Für jedes Paar wird solange auf der nächsten Höhe geschaut, ob dort auch ein Paar ist, bis dies nicht mehr der Fall ist. 2r, 2g, 3r, 3g, 4b 2r, 2g, 3r, 3g → optimal 4b → optimal Beispiel 8.3 In den Bereichen mit mehr als fünf Karten ist es etwas komplizierter, da dort Strassen möglich sind. Es ist aber nicht immer der Fall, dass Strassen optimale Kombinationen sind, denn wenn mehr als die Hälfte der Karten doppelt vorkommen, gibt es weniger Einzelkarten, wenn Paare gespielt werden. Es werden also die Einzelkarten gezählt, die entstehen, wenn die Strasse gespielt wird und die Einzelkarten die entstehen, wenn wie in kleinen Bereichen gespielt wird. Wenn es weniger Einzelkarten gibt, wenn die Strasse gespielt wird, wird die Strasse auf optimal gesetzt. Bei jedem Wert wird anschliessend geschaut, wie viele Karten noch nicht gebraucht werden und diese auch als optimale Kombination gesetzt. Wenn es beim Strasse Spielen mehr Einzelkarten gibt, werden die optimalen Kombinationen wie in kleinen Bereichen gesetzt. Sollte der Fall eintreten, dass bei beiden gleich viele Einzelkarten entstehen, wird die durchschnittliche Höhe der Einzelkarten errechnet und es wird so auf optimal gesetzt, dass die durchschnittliche Höhe der entstehenden Einzelkarten möglichst gross ist. 9g, 10r, Jr, Qs, Kr, Ks 9g, 10r, Jr, Qs, Kr Ks → optimal → optimal 8r, 8s, 9r, 10s, 10r, Js, Jr, Qs, Qg 8r, 8s → optimal 9r → optimal 10s, 10r, Js, Jr, Qs, Qg → optimal 3r, 3g, 4r, 5b, 6r, 6b, 7s, 8r, 8g 3r, 4r, 5b, 6r, 7s, 8r → optimal 3g → optimal 6b → optimal 8g → optimal Beispiel 8.4 Diese Aufteilung in optimale und nicht optimale Kombinationen ist zwar nicht schlecht, aber sie könnte noch verbessert werden. Wenn beispielsweise viele tiefe Einzelkarten -28- Oktober 2008 Regelbasierte Systeme am Beispiel Tichu Simon Rösch, 1MNd existieren, die optimal sind und ein hohes Paar, wird das hohe Paar besser einzeln gespielt. Mein Algorithmus ist also ziemlich unflexibel und könnte noch verbessert werden. 8.10 Die History Die History ist eigentlich der Kern des Programms. Dort läuft das ganze Spiel ab, werden alle Spielinformationen gespeichert und auch die Ausgabe für den Benutzer wird von dort aus gesteuert. 8.11 Das Userinterface Falls ein Spieler nicht vom Computer gesteuert werden soll, übernimmt dies die Klasse userinterface. Sie besitzt die gleichen Methoden wie die Klasse computerplayer, braucht aber zum wählen der Kombination nicht Regeln, sondern fragt den User. In der Methode play(int wer, history history) werden alle zurzeit spielbaren Kombinationen ausgerechnet und zusammen mit einer Nummer ausgegeben. Der User braucht dann nur die Nummer zu tippen, die er gerne spielen möchte. Beim Schupfen funktioniert es eigentlich gleich, nur dass dort nicht die Kombinationen ausgegeben werden, sondern die einzelnen Karten. 8.12 Der Computerplayer Der Computerplayer regelt die Strategie des Computerspielers. Falls der Spieler noch Karten hat, werden die optimalen Kombinationen auf optimal gesetzt und alle Kombinationen dem Regelsystem übergeben. Danach regelt das Regelsystem das Spielen. Hat der Spieler keine Karten mehr, wird er automatisch zum Passen gezwungen. Allgemeineregeln.drl In dieser Datei sind die Regeln gespeichert, die für alle Strategien benötigt werden. Die erste Regel ist ganz einfach, aber wichtig. Sie sagt nämlich aus, dass der Spieler passen soll, wenn er nicht spielen kann, das heisst keine Kombination hat, die über die aktuell ausgespielte Kombination gespielt werden könnte. Danach werden die aktuellen, optimalen Kombinationen in gute und schlechte aufgeteilt. Dazu wird ein Schwellenwahrscheinlichkeitswert verwendet, alle Kombinationen die eine grössere Stichwahrscheinlichkeit haben, sind gut, die anderen schlecht. (Wie der Schwellenwert ermittelt wurde, siehe Kapitel 8.13. Schwellenwahrscheinlichkeitswert-Bestimmung.) Bei den schlechten wird auch gleichzeitig geschaut, ob es eine gute Kombination von der gleichen Art gibt, denn dann kann die schlechte ausgespielt werden und mit der guten wieder gestochen werden. Je nach Ausgabe-Modus werden dann auch noch alle Kombinationen zusammen mit ihrem Optimal-Wert, ihrer Wahrscheinlichkeit und der Aufteilung in gut und schlecht ausgegeben. Anschliessend folgt die jeweilige Spiel-Strategie des Computerspielers, welche ich unter 8.15. Die Spielstrategien erklären werde. Am Schluss sind noch einige Regeln, die nie ausgeführt werden sollten, aber notwendig sind, um das mogeln des Computers sicher zu verhindern. Falls in der spezifischen Strategie nicht gespielt wurde, gibt es hier noch je eine Regel, die zufällig etwas ausspielt, spielt oder passt. -29- Oktober 2008 Regelbasierte Systeme am Beispiel Tichu Simon Rösch, 1MNd 8.13 Schwellenwahrscheinlichkeitswert-Bestimmung Zur Ermittlung des Schwellenwahrscheinlichkeitswert liess ich zwei Teams mit verschiedenen Schwellenwahrscheinlichkeitswerten, aber der gleichen Strategie (defensiv) gegeneinander spielen. Da beim Tichu das Kartenglück eine sehr grosse Rolle spielt, musste ich viele Runden spielen, um deutlich zu erkennen, welches Team besser spielt. Dazu habe ich viermal 200 Runden gespielt und geschaut, wer in den 200 Runden durchschnittlich mehr Punkt gemacht hat. Zuerst wählte ich die Werte 0.8 und 0.5, wobei deutlich herauskam, dass 0.5 der bessere Wert ist. In einem weiteren Versuch wählte ich die Werte 0.6 und 0.5. Hier kam kein genaues Resultat heraus, da je zweimal das Team mit 0.6 und zweimal das mit 0.5 besser war. Ich bin schliesslich davon ausgegangen, dass der allgemein optimalste Wert deshalb irgendwo zwischendrin liegen wird und habe den Wert auf 0.55 gesetzt. 8.14 Die Endphase In der Endphase, das heisst, wenn nur noch 2 Spieler im Spiel sind und zusammen weniger als 6 Karten haben, übernimmt eine andere Klasse das Spielen des Computers. Die Klasse durchrechnen rechnet das Spiel mit allen möglichen Spielmöglichkeiten der beiden verbleibenden Spieler durch und spielt danach die Kombination, mit der durchschnittlich am Spielende am meisten Punkte erzielt werden. Damit das Spiel durchgerechnet werden kann, muss der aktuelle Spielstand (d.h. die History und die Spieler) kopiert werden und nach dem Durchrechnen wieder eingesetzt werden. Damit eine Klasse kopiert werden kann, muss sie serialisierbar sein. Durch das Serialisieren einer Klasse, wird sie in ein Format gebracht, in dem sie in eine Datei geschrieben werden oder über ein Netzwerk transportiert werden könnte. Ist die Klasse in dieser Form vorhanden, kann man sie auch deserialisieren, also daraus wieder eine normale Klasse erstellen. Das Durchspielen aller Spielmöglichkeiten wird durch eine rekursive Methode erzielt. 8.15 Spielstrategien Die strategischen Regeldateien haben alle den gleichen Aufbau: Es gibt drei Arten von Regeln, die verschiedene Salience-Werte haben. Die als erstes geprüften Regeln sind die, die entscheiden, ob der Spieler passen soll. Danach gibt es Regeln, die über das Ausspielen entscheiden und solche die das normale Spielen regeln. defensiv.drl Die defensive Strategie war die erste, die ich entwickelt habe. In dieser Strategie werden nur Kombinationen gespielt, die auf optimal gesetzt wurden. Haben sie eine kleinere Stichwahrscheinlichkeit als der Schwellenwahrscheinlichkeitswert, werden sie wann immer möglich gespielt, ansonsten nur, wenn jede schlechte Kombination durch eine gute gedeckt ist. Beim Spielen einer Kombination wird immer darauf geschaut, dass die tiefst mögliche optimale Kombination gespielt wird. Der Spieler spielt seine guten Karten also erst aus, wenn er seine schlechten losgeworden ist. Hat er keine schlechte Kombination ohne Deckung mehr (resp. beim Ausspielen max. eine), spielt er die Kombination aus, die die Deckung mit der besten Stichwahrscheinlichkeit hat. -30- Oktober 2008 Regelbasierte Systeme am Beispiel Tichu Simon Rösch, 1MNd offensiv.drl Auch in der offensiven Strategie werden nur optimale Kombinationen gespielt, es wird jedoch immer gespielt, wenn gespielt werden kann, egal ob die Wahrscheinlichkeit der Kombination grösser oder kleiner als der Schwellenwahrscheinlichkeitswert, wird die tiefste optimale Kombination gespielt. Gepasst wird also nur, wenn keine optimale Kombination gespielt werden könnte. Beim Ausspielen werden die Kombinationen gespielt, die keine Deckung haben. Sobald alle ausser eine Kombination gedeckt sind, wird die Kombination mit der besten Deckung ausgespielt. Offensiv vs. Defensiv Wie bei der Schwellenwahrscheinlichkeitswert-Bestimmung liess ich ein Team mit der defensiven Strategie und eines mit der offensiven gegeneinander spielen. Dabei kam das heraus, was man mit einiger Überlegung auch hätte vorhersagen können: Das offensive Team ist durchschnittlich über 200 Runden um 22.5 Punkte besser als das defensive. Das Problem ist, dass das defensive Team sehr lange wartet bis es wirklich beginnt zu spielen, dadurch macht das offensive Team auch schon mit tiefen Karten Stiche und wird so oft vor dem defensiven fertig. Ultraoffensiv.drl Da ich herausgefunden habe, dass es besser ist, wenn offensiv gespielt wird, habe ich noch eine ultraoffensive Strategie entwickelt. Diese spielt genau gleich wie die offensive, spielt jedoch wenn keine optimale Kombination vorhanden ist, die tiefste mögliche Kombination, auch wenn sie nicht optimal ist. Ultraoffensiv vs. Offensiv Schliesslich liess ich die ultraoffensive Strategie gegen die offensive spielen, um herauszufinden, welche besser ist. Dass die ultraoffensive Strategie so viel besser ist, hat mich erstaunt. Durchschnittlich wurden pro Runde mit der ultraoffensiven Strategie 32.18 Punkte mehr erzeugt, was sogar noch mehr ist als bei Offensiv vs. Defensiv. Das Problem ist jedoch wahrscheinlich, dass meine offensive Strategie immer noch ziemlich defensiv ist, da nur optimale Kombinationen gespielt werden. Wie gut die Ultraoffensive wirklich ist, kann ich nicht genau sagen, da ich kein wirklicher Vergleich habe. Da kein anderes Computerprogramm existiert, gegen das ich mein Programm testen kann und sehr viele Runden gespielt werden müssen, damit der Effekt des Kartenglücks nur noch einen kleinen Einfluss hat, hatte ich keine Möglichkeit, die wirkliche Stärke meines Programms zu testen. 8.16 Schupfen Eigentlich wollte ich das Schupfen nicht implementieren, doch da ich beim Suchen im Internet nach taktischen Regeln, immer anstelle von Tipps zum eigentlichen Spiel auf Tipps zum Schupfen und Tichu ansagen gestossen bin, habe ich es trotzdem gemacht. Wie das Spielen wird mit Regeln geschupft. Die Regeln zum Schupfen an den Gegner sind ziemlich einfach: Man schupft die zwei Karten, die man am schlechtesten brauchen kann. Dies sind im Normalfall die zwei tiefsten Karten, die in keiner Kombination sind. Gibt es keine sehr tiefen einzelnen Karten, kann auch ein tiefes Paar auseinandergerissen werden und je eine Karte den Gegnern geschupft werden. Wenn es auch kein solches Paar gibt, kann von einer langen Strasse die tiefste Karte weggeschupft -31- Oktober 2008 Regelbasierte Systeme am Beispiel Tichu Simon Rösch, 1MNd werden, falls dadurch die Strasse aber nicht kleiner als fünf Karten lang wird. Was dem Partner geschupft werden soll, ist umstritten. Da aber in meinem vereinfachten Spiel keine Tichus angesagt werden können, ist es meist angebracht, dem Partner die höchste einzelne Karte zu schupfen. 8.17 UML-Diagramm von meinem Programm -32- Oktober 2008 Regelbasierte Systeme am Beispiel Tichu Simon Rösch, 1MNd 9 Fazit Dass ich im Rahmen meiner Arbeit, nicht den perfekten künstlichen Tichuphilen programmieren werde, war für mich ganz klar. Schon vor der Arbeit war für mich offensichtlich, dass es nicht möglich ist, so gut zu spielen, dass jedes Spiel gewonnen wird, da das Kartenglück einen viel zu grossen Einfluss hat. Trotzdem wäre es mein Ziel gewesen, dass mein Programm in jeder Situation das spielt, was ich von ihm erwarten würde, also ich (aufgrund des selben Wissens) auch spielen würde. Dadurch hätte der Computerspieler mindestens so gut gespielt wie ich. Während der Arbeit wurde mir aber immer klarer, dass ich auch dieses Ziel nicht erreichen würde. Obwohl ich mit Drools eine einfache Möglichkeit gefunden habe, Strategieregeln aufzustellen, war es mir nicht möglich, meine persönliche Strategie in Regeln zu verwandeln. Oft konnte ich gar nicht begründen, wieso ich diesen Zug machte, ich also intuitiv spielte, was der Computer nicht kann. Ich will aber meine Arbeit nicht als völlig misslungen ansehen, denn ich habe mein Hauptziel, ein Programm zu schreiben, das Tichu spielen kann, erreicht. Das Programm spielt zwar auf dem Niveau eines Anfängers, verstösst jedoch nicht gegen die Spielregeln. Die Arbeit war für mich auch sehr interessant, da ich neue Programmiermethoden kennen lernte. Auch glaube ich, dass ich selber seither besser Tichu spiele, da ich lernte, das Spiel von einer ganz anderen Seite anzusehen und oft nach rationalen Gründen für meine Taktik zu suchen, anstatt auf meine Intuition zu vertrauen. Auf dem Markt gibt es bis heute noch kein Computerprogramm, gegen das man Tichu spielen kann und das wird auch so bleiben. Möchte ich mein Programm verkaufen, müsste ich sämtliche Spielregeln implementieren und auch die Strategie noch deutlich verbessern. Doch was es nun gibt, ist jemand, der sich bereits mit dem Thema beschäftigte und das Problem auch ansatzweise löste. -33- Oktober 2008 Regelbasierte Systeme am Beispiel Tichu Simon Rösch, 1MNd 10 Quellenverzeichnis 10.1 Literatur L1 Karl Kurbel (1989): Entwicklung und Einsatz von Expertensystemen. Eine anwendungsorientierte Einführung in wissensbasierte Systeme, 2. Auflage, ISBN 3-540-55237-5, Springer-Verlag, Heidelberger Platz 3, D-14197 Berlin L2 Guido Krüger (2000), Handbuch der Java-Programmierung, 2. Auflage, ISBN 3-8273-1710-X, Addison Wesley Verlag, Martin-Koller-Strasse 10-12, D-81829 München L3 Christian Ullenboom (2006), Java ist auch eine Insel. Das umfassende Handbuch, 5. Auflage, ISBN 3-89842-747-1, Galileo Press, Rheinwerkallee 4, D-53227 Bonn L4 Lars Wunderlich (2006): Java Rules Engines. Entwicklung von regelbasierten Systemen, ISBN 3-935042-75-2, entwickler.press, Software & Support Verlag GmbH, Geleitstrasse 14, D-60599 Frankfurt L5 Urs Hostettler (1991): Tichu Spielanleitung, Fata Morgana Spiele, Güterstrasse 32, 3008 Bern 10.2 Internetadressen I1 http://de.wikipedia.org/ I2 http://en.wikipedia.org/ I3 http://forum.chip.de/java-delphi-pascal/array-mischen-401401.html Anleitung zum Misch-Algorithmus I4 http://www.jboss.org/drools/documentation.html Drools Documentation, Version 4.0.4 (17.2.08) 10.3 Computerprogramme C1 Drools, Version 4.0.4, http://www.jboss.org/drools/ C2 Eclipse SDK, Version 3.2.2, http://www.eclipse.org/ C3 Fat Jar Eclipse Plug-In, Version 0.0.27 , http://fjep.sourceforge.net/ 10.4 Bildnachweis Bild 1: Drools Documentation, http://www.jboss.org/drools/ (17.2.08) Bild 2: Wikipedia, http://de.wikipedia.org/wiki/Urs_Hostettler (22.10.08) Bild 3 - 8: Tichukarten von Fata Morgana -34- Oktober 2008 Regelbasierte Systeme am Beispiel Tichu Simon Rösch, 1MNd 11 Anhang 11.1 Resultate der Schwellenwahrscheinlichkeitswert-Bestimmung Team 0/2 spielt mit 0.8, Team 1/3 mit 0.5 Jeweils 200 Runden Team 0/2 Team 1/3 Team 0/2 Team 1/3 Team 0/2 Team 1/3 Team 0/2 Team 1/3 Punkte 11945 13255 10930 12370 10905 14895 11910 13190 Punkteschnitt pro Runde 59.725 66.275 54.650 61.850 54.525 74.475 59.550 65.950 Team 0/2 spielt mit 0.6, Team 1/3 mit 0.5 Jeweils 200 Runden Team 0/2 Team 1/3 Team 0/2 Team 1/3 Team 0/2 Team 1/3 Team 0/2 Team 1/3 Punkte 12110 12690 13090 12110 12335 12265 11115 13485 Punkteschnitt pro Runde 60.550 63.450 65.450 60.550 61.675 61.325 55.575 67.425 11.2 Resultate Offensiv vs. Defensiv Team 0/2 spielt offensiv, Team 1/3 defensiv Jeweils 200 Runden Team 0/2 Team 1/3 Team 0/2 Team 1/3 Team 0/2 Team 1/3 Team 0/2 Team 1/3 Punkte 16020 9580 15435 10065 13600 10500 14100 11000 Punkteschnitt pro Runde 80.100 47.900 77.175 50.325 68.000 52.500 70.500 55.000 Durchschnittlicher Vor- 22.513 sprung von Team 0/2 -35- Oktober 2008 Regelbasierte Systeme am Beispiel Tichu Simon Rösch, 1MNd 11.3 Resultate Offensiv vs. Ultraoffensiv Team 0/2 spielt offensiv, Team 1/3 ultraoffensiv Jeweils 200 Runden Team 0/2 Team 1/3 Team 0/2 Team 1/3 Team 0/2 Team 1/3 Team 0/2 Team 1/3 Punkte 9100 15500 11390 14010 8405 16795 8585 16915 Punkteschnitt pro Runde 45.500 77.500 56.950 70.050 42.025 83.975 42.925 84.575 Durchschnittlicher Vor- 32.175 sprung von Team 1/3 -36- Oktober 2008 Regelbasierte Systeme am Beispiel Tichu Simon Rösch, 1MNd 11.4 Mail von Urs Hostettler hallo simon Seit gut einem halben Jahr arbeite ich an meiner Maturaarbeit, da ich im Sommer 2009 im Gymnasium Neufeld in Bern die Matura ablegen werde. Ich habe mir zum Ziel gesetzt, ein Programm zu schreiben, das Tichu spielen können soll. Das Programm funktioniert eigentlich schon ziemlich gut (ich habe das Spiel jedoch etwas vereinfacht), einzig die Spiel-Strategie des Computers lässt noch etwas zu wünschen übrig. schön! 1. Wie ist Tichu wirklich entstanden? Waren Sie wirklich auf einer China-Reise und haben das Spiel in Nanjing so kennen gelernt, wie es heute in der Schweiz und in Deutschland gespielt wird? was in der spielanleitung steht, stimmt. wir haben noch einige extras hinzugefügt: spezialkarten, schupfen. in china wird das spiel je nach gegend in verschiedenen versionen gespielt. mit bridgekarten, wobei die herz 5 die rolle des drachens, der höchsten einzelkarte, übernimmt. 2. Darf ich in meiner Maturaarbeit die Tichu-Karten vom Fata Morgana Verlag abdrucken? ja 3. Haben Sie, wenn Sie Tichu spielen eine bestimmte Strategie, die weder angesagte Tichus, noch Sonderkarten, das Abstechen des Partners oder das Schupfen betrifft? ich begreife die frage nicht ganz. da nimmst du ja fast alles, was eine BESTIMMTE strategie ermöglicht/erfordert, aus. 4. Wissen Sie, seit wann Tichu in der Brettspielwelt.de spielbar ist? nein, weiss ich nicht, sorry. viel erfolg - sag nur, wenn ich was helfen kann urs hostettler -37- Oktober 2008 Regelbasierte Systeme am Beispiel Tichu Simon Rösch, 1MNd 11.5 Digitaler Anhang -38- Oktober 2008