Kommen wir heute zum dritten Teil der C#-Casino-Reihe. Wer gerade erst in die Serie einsteigt, sollte sich zuvor die ersten beiden Teile durchlesen. In Teil 1 ging es um die Berechnung der Gewinnwahrscheinlichkeit einer Pokerhand in C# und in Teil 2 ging es um das Erkennen von Spielkarten und deren Werten mittels maschinellem Sehen mit Hilfe der AForge-Bibliothek. Wir haben bisher also auf spielerische Art und Weise sowohl das Feld der Statistik, die Verwendung von externen Bibliotheken als auch die Grundlagen der Bildverarbeitung mittels C# bearbeitet.
Im heutigen, dritten Teil, soll es um die Verknüpfung der Ergebnisse der ersten beiden Artikel gehen. Wir wollen also für die analysierten Karten aus Teil 2 direkt die Gewinnwahrscheinlichkeit (wie in Teil 1) berechnen.
Vorbereitungen
Bevor es losgeht, solltet ihr euch das Ergebnis des zweiten Artikels herunterladen. Den Downloadlink für das Visual Studio Projekt findet ihr am Ende des Artikels. Um ein wenig “Kanonenfutter” zu haben, sprich Ausgangsmaterial, braucht ihr noch Screenshots aus einem beliebigen Online-Casino. Zum Testen reicht definitiv auch ein kostenloser Account!
Solltet ihr mit den gleichen Screenshots wie ich arbeiten wollen, damit ihr die Bilderkennung aus Teil 2 nicht anpassen müsst, so müsstet ihr euch einen kostenlosen Account bei Full Tilt Casino oder Mr. Green machen. (Alternativ hilft z.B. ein Blick auf serioeseonlinecasinos.org – dort sind, neben Mr. Green und Full Tilt Poker, noch weitere Alternativen gelistet.)
Habt ihr das Visual Studio Projekt geladen, kann es losgehen. Wir nehmen bewusst das Projekt des zweiten Artikels als Ausgangslage, da sich der Code aus Teil 1 leichter in Teil 2 “verpflanzen” lässt, als es andersrum der Fall wäre.
Using-Direktiven und eine weitere Bibliothek
Zuerst übertragen wir die externen Referenzen und Hilfsklassen aus Teil 1 in unser aktuelles Projekt. Hierzu kopieren wir die HandEvaluator.dll aus dem Projektordner von Teil 1 in den aktuellen Projektordner. Danach klicken wir im Verweis-Bereich des Visual Studios auf “Verweis hinzufügen”, wählen die DLL-Datei aus und schreiben schlussendlich die using-Anweisung (“HoldemHand”) in den Kopf der Form1.cs-Datei.
//... using AForge.Math.Geometry; using System.Drawing.Imaging; using HoldemHand;
Nun haben wir die Grundlage geschaffen, um auch in unserem aktuellen Projekt die Gewinnwahrscheinlichkeit zu berechnen. Um nun auch in der Praxis die Wahrscheinlichkeit zu berechnen, brauchen wir natürlich die ausgeteilten Karten – ohne diese kann eine Berechnung logischerweise nicht stattfinden. Wer Teil 2 noch im Kopf hat, weiß, dass die Erkennung der Karten in der analyzeCards()-Methode stattgefunden hat. Zum Ende der Methode haben wir also die nötigen Informationen, sodass wir uns an dieser Stelle einklinken und die Funktion erweitern.
Arbeiten mit dem HandEvaluator
Nun geht es also darum, mittels des HandEvaluators die Gewinnwahrscheinlichkeit der bereits ermittelten Karten zu bestimmen. Die Aufgabe lautet also die erkannten Kartenwerte in die Form zu bringen, die der Handevaluator als Eingabe benötigt. Unsere Kartenwerte haben wir bisher in der Liste List<Card> cards abgelegt, wobei die Indizes 0-2 die Karten im Deck und die Indizes 3 und 4 die beiden Handkarten enthalten. Jeder Index der cards-Liste besitzt wiederum die Eigenschaften suit (= Kartenfarbe) und value (=Kartenwert).
Da der HandEvaluator jedoch die englischen Kurzformen für die Kartenfarben benötigt, legen wir zuvor noch ein Dictionary an, mit dem wir gleich die deutschen Kartenfarbennamen (aus Teil 2) in die englische Kurzform überführen können.
//Kartenwerte und dazugehörige Bezeichnungen für die Poker-Library private Dictionary<string, string> cardsTranslator = new Dictionary<string, string>() { {"2", "2"}, {"3", "3"}, {"4", "4"}, {"5", "5"}, {"6", "6"}, {"7", "7"}, {"8", "8"}, {"9", "9"}, {"10", "10"}, {"Bube", "J"}, {"Dame", "Q"}, {"König", "K"}, { "Ass", "A" }, {"Pik", "s"}, {"Herz", "h"}, {"Karo", "d"}, {"Kreuz", "c"} };
Nun sind wir bereit, um die Gewinnwahrscheinlichkeit auszurechnen. Hierzu iterieren wir über alle Karten, übersetzen die Kartenfarben und übergeben dann den String, der alle Karten enthält an den HandEvaluator. Wem das jetzt zu schnell ging, der schaut sich am besten die Kommentare im nachfolgenden Code an oder hängt einfach mal einen Breakpoint in den Debugger. Folgenden Code fügen wir, wie eben besprochen, am Ende der analyzeCards()-Methode ein.
//Gewinnwahrscheinlichkeit berechnen - Teil 3 //Fasse alle Hand-Karten als string in der Poker-Library-Syntax zusammen string handCards = ""; //Durchlaufe alle erkannten Karten for (int i = 3; i < 5; i++) { handCards += cardsTranslator[cards[i].value] + cardsTranslator[cards[i].suit] + " "; } handCards = handCards.Trim(); //Fasse alle Deck-Karten als string in der Poker-Library-Syntax zusammen string deckCards = ""; for (int i = 0; i < 3; i++) { deckCards += cardsTranslator[cards[i].value] + cardsTranslator[cards[i].suit] + " "; } deckCards = deckCards.Trim(); //Initialisiere Hilfsvariablen für die Poker-Library double[] self = new double[9]; double[] opponent = new double[9]; double selfWin = 0.0; //Berechne Poker-Hände und Wahrscheinlichkeiten Hand.HandPlayerOpponentOdds(handCards, deckCards, ref self, ref opponent); //Berechne Sieg-/Split-Wahrscheinlichkeit for (int i = 0; i < 9; i++) { selfWin += self[i] * 100.0; } //Gebe Sieg-/Split-Wahrscheinlichkeit aus var siegWahrscheinlichkeit = string.Format("{0:##0.0}%", selfWin);
Nun sind wir auch schon fast fertig. Das Ergebnis unserer Berechnung sollte sich nun in der String-Variable siegWahrscheinlichkeit befinden. Um diese auch an geeigneter Stelle anzuzeigen, fügen wir im WinForms-Designer noch ein Label ein. (Ich habe es labelWahrscheinlichkeit genannt und neben dem “nächster Screenshot”-Button platziert.)
Um die Wahrscheinlichkeit auszugeben, fügen wir nun noch eine letzte Zeile in unsere analyzeCards()-Methode ein.
labelWahrscheinlichkeit.Text = "Wahrscheinlichkeit für\r\nSieg oder Split:\r\n\r\n" + siegWahrscheinlichkeit;
Nun sind die Arbeiten abgeschlossen und wir neigen uns dem Ende des dritten Teils unserer Serie.
Fazit & Download
Das fertige Projekt könnt ihr natürlich wie immer herunterladen:
Download: KartenDetektor V2 – Visual Studio Project
Mit wenigen “Handgriffen” lassen sich die Ergebnisse der ersten beiden Artikel miteinander verschmelzen und somit ein Mehrwert kreieren. Solltet ihr Fragen oder Probleme haben, schreibt mir einen Kommentar. Selbiges gilt natürlich auch für Ideen, Wünsche oder Vorschläge für weitere Teile in der Serie! Was wollt ihr als nächstes sehen/lernen? Ich freue mich auf euer Feedback.
The Zune concentrates on being a Portable Media Player. Not a web browser. Not a game machine. Maybe in the future it’ll do even better in those areas, but for now it’s a fantastic way to organize and listen to your music and videos, and is without peer in that regard. The iPod’s strengths are its web browsing and apps. If those sound more compelling, perhaps it is your best choice.