Entwickler-Ecke

Algorithmen, Optimierung und Assembler - Rangposition einer Kartenverteilung berechnen. (Poker)


JoelH - Di 30.10.12 16:52
Titel: Rangposition einer Kartenverteilung berechnen. (Poker)
Sorry, für den Topictitel, wem was besseres einfällt darf sich gerne melden. Es geht um folgendes. Ich möchte die Rangposition einer Hand aus fünf Karten berechnen. Leider komm ich nicht auf die Formel, allerdings bin ich mir sehr sicher, dass es sie gibt, und dass sie nicht mal so kompliziert ist.

Also folgendes, es geht um Razz (Ist eine Pokervariante). Dabei gewinnt der mit der "schlechtesten" Hand. Diese ist

A2345

die nächst "schlechteren" Hände ist dann

A2346
A2356
A2456

usw.



Da die Kartenfarbe (Pik, Herz, Karo, Kreuz) keine Rolle spielt kann man die Rangfolge wie folgt aufzeichnen.

Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
A23456789TJQK
+++++
++++ +
+++ ++
++ +++
+ ++++
 +++++
++++  +
+++ + +
++ ++ +
+ +++ +
 ++++ +
+++  ++
++ + ++
+ ++ ++
 +++ ++
++  +++
+ + +++
 ++ +++
+  ++++
 + ++++
  +++++

usw.


Wie man recht gut erkennen kann handelt es sich um ein Muster, welches man relativ leicht rekursiv herbeiführen kann. Sehr ähnlich zu den Türmen von Hanoi, wenn nicht sogar dergleiche, nur mit fünf Türmen, anstatt dreien ?!?

Was ich nun gerne hätte, wäre idealerweise eine Formel in die ich fünf Karten quasi als Variablen reinstecke und dann die Position als Zahl zurückbekommen.

Jemand eine Idee, oder die Formel zufällig im Kopf?


Hoermi93 - Di 30.10.12 18:03


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
var
  lTeilString : String;
  I, Punkte: Integer;
begin
 Punkte := 0;
 for I := 0 to 4 do
 begin
  lTeilString := copy(Edit1.Text, i + 1,1 );
  case AnsiIndexText(lTeilString, ['A','2','3','4','5','6','7','8','9','T','J','Q','K'])  of
   0: inc(Punkte, 0);
   1: inc(Punkte, 1);
   2: inc(Punkte, 2);
   3: inc(Punkte, 3);
   4: inc(Punkte, 4);
   5: inc(Punkte, 5);
   6: inc(Punkte, 6);
   7: inc(Punkte, 7);
   8: inc(Punkte, 8);
   9: inc(Punkte, 9);
   10: inc(Punkte, 10);
   11: inc(Punkte, 11);
   12: inc(Punkte, 12);
  end;
 end;
 ShowMessage(IntToStr(Punkte));
end;

ich würd das vielleicht so lösen dann bekomms immer den geringsten Wert zurück


jfheins - Di 30.10.12 19:12

Wenn du Punkte vergibst, würde ich das exponentiell machen.

Alternativ lässt sich dein Muster generieren, wenn du einfach alle natürlichen Zahlen hochzählst und dann immer nur genau die nimmst, die 5 einsen im Bitmuster haben.
Musst nur gucken wegen dem least-significant-bit (bei deinem Beispiel ist das nämlich links...)

Wenn du also nur vergleichen möchtest, welche Hand besser ist, kannst du mit Gewichten von 1, 2, 4, 8, 16, 32, ... arbeiten oder das ganze zu einem Integer verwursten und vergleichen.

Hier mal der Beispielcode, mit dem ich das überprüft habe:

PHP-Quelltext
1:
2:
3:
4:
5:
6:
7:
function Result = NextCombination(x)
a = bin2dec(fliplr(x))+1;
while sum(dec2bin(a)-'0') ~= 5 % Einsen zählen
    a = a+1;
end
Result = fliplr(dec2bin(a));
end

Ist jetzt leider in matlab, aber ich hoffe die Funktion geht hervor. fliplr kehrt den String um, damit das LSB rechts zum liegen kommt. Ausgehend von einer gegebenen Kombination wird also immer eine 1 addiert und geguckt ob das Bitmuster genau 5 Einsen enthält. Sobald das der Fall ist, sind wir fertig und der Wert kann für die Darstellung wieder umgewandelt werden.

Um eine Punktefunktion in Delphi zu implementieren würde ich folgendermaßen vorgehen:
Definiere ein konstantes Array mit einem Char als Index. Dieses kannst du nun vorbelegen mit den passenden Werten. ('A'=$01, '2'=$02, '3'=$04, '4'=$08, '5'=$10) usw.
Danach kannst du für jedes Blatt den Score berechnen indem du die Werte der einzelnen Buchstaben mit bitweisem or verknüpfst.