Gå til innhold

[Python] Poker: Hvordan gå frem får å finne "hender"


Anbefalte innlegg

Heisann. Har nå lenge vudrdert å starte et prosjekt, for å lage en "pokerbot" til Texas Hold'em, i første fase ønsker jeg å lage noe enkelt. Ingen AI. Bare den grunleggende mattematikken, og "slik".. for å få boten til å "spille".

 

Jeg ble litt blank på hvordan jeg skulle gå frem får å finne mulige hender, basert på de 2 kortene på hånden, og de ~5 kortene på bordet. Jeg er mye klar over at en slik bot vil ha bedre utbytte av å programmeres i raskere språk, som C,Cpp,delphi etc.. Men har for lite erfaring i disse språkene. Kan hende jeg må ta meg til å gjøre noe i C/Cpp, men håper ikke det.

 

Jeg har alt laget et rammeverk som tar seg av macro-delen, med OCR (google tesseract), bildegjenkjenning, mus, tastatur, og mye annet som kan komme til nytte. Dette er for å lese av verdiene og slik, det uten å måtte "hacke" selve programmet :)

 

Nå trenger jeg bare et kraftig dytt i riktig retning, da jeg må vite om det er noen smart måte å gå frem for å lese hånden ved..

Flop -> 2 kort på hånden, 3 kort på bordet
Turn -> 2 kort på hånden, 4 kort på bordet
River -> 2 kort på hånden, 5 kort på bordet

 

Nå må jeg ut i fra kortne jeg har fått tildelt (pluss de på bordet) finne alle mulige hender.

52 kort = 4 typer (Clubs,Hearts,Spade,Dimond), 13(14) rangeringer (A,2,3,4..Q,K,A)

 

Så har vi alle hender:

1 > Royal Flush
2 > Straight Flush
3 > Four-of-a-Kind
4 > Full House
5 > Flush
6 > Straight
7 > Three-of-a-Kind
8 > Two Pair
9 > Pair
10> High Card

#Ikke kjenskap til disse/dette? Følg denne lenken.

 

Det å søke etter alle disse forskjellige kombinasjonene ser jeg ikke helt hvordan jeg burde/kan gjøre.. Hadde ikke tenkt meg at det skulle bli så vanskelig, men det blir bare "yalla-kode" om jeg ikke får litt hjelp fra dere :-)

Er flott selv med hjelp til å "bare" lese enkelte kombinasjoner, en start er en start!

 

Slik løste jeg ett par, og to par.. Halvfungerende "yallekode" Må være en bedre måte å gjøre dette på? Blir forferdelige greir dette! :(

 

'''~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|| FindPokerHand
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'''  
def Find_Pair(cards):
   result = False

   #Loop for one pair
   for x in xrange(0,len(cards)):  
       for y in xrange(0,len(cards)):  
           if(cards[x][:-1] == cards[y][:-1]) and (x!=y):
               result=(cards[x],cards[y])
               break
   return result

def Find_TwoPair(cards):
   result = False

   #Loop for one more pair (two pairs)
   for x in xrange(0,len(cards)):  
       for y in xrange(0,len(cards)):  
           if(cards[x][:-1] == cards[y][:-1]) and (x!=y):
             if(cards[y][:-1]!=pair[0][:-1]) and (cards[y][:-1]!=pair[1][:-1]):
               if(cards[x][:-1]!=pair[0][:-1]) and (cards[x][:-1]!=pair[1][:-1]):
                   result=(pair[0],pair[1],cards[x],cards[y])
                   break 
   return result


'''~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|| Look for hands
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'''    
hand = ["Qd","7c","5d", "2d", "As", "8d", "Qc"]

pair = Find_Pair(hand)  
two_pair = Find_TwoPair(hand)

print pair
print two_pair

 

Endret av warpie
Lenke til kommentar
Videoannonse
Annonse

Heisann. Har nå lenge vudrdert å starte et prosjekt, for å lage en "pokerbot" til Texas Hold'em, i første fase ønsker jeg å lage noe enkelt. Ingen AI. Bare den grunleggende mattematikken, og "slik".. for å få boten til å "spille".

 

Ta en titt for generell inspirasjon.

 

Jeg ble litt blank på hvordan jeg skulle gå frem får å finne mulige hender, basert på de 2 kortene på hånden, og de ~5 kortene på bordet.

 

Aller først tror jeg det er lurt å spørre seg "Hva ønsker jeg å få ut av de opptil 7 kort totalt?". Hvis man ønsker en eller annen form for handling (f.eks. vedde eller stoppe), så er det rimelig å tilordne en eller annen verdi til dette utvalget, hvor verdien bestemmes av spillets regler.

 

Jeg er mye klar over at en slik bot vil ha bedre utbytte av å programmeres i raskere språk, som C,Cpp,delphi etc.

 

1) Det er meningsløst å snakke om raskere språk. Viktig å få med seg det.

2) På det stadiet som du beskriver er hastigheten komplett uinteressant.

 

(Hastigheten _kan_ bli interessant når man har et veldig stort søkerom. Og da kan det lønne seg å velge en implementasjon (ikke et språk) som har høy ytelse. Foreløpig er fleksibilitet veldig mye mer interessant. I så måte er Python, Perl, Ruby, CL uendelig mye bedre enn C eller C++, uansett implementasjon).

 

Nå må jeg ut i fra kortne jeg har fått tildelt (pluss de på bordet) finne alle mulige hender.

 

Hvorfor må du det? Hvis du har royal flush, hva pokker skal du med å finne ut noe som helst annet? (Hvis du derimot ønsker å finne ut hvilke utfall er mulige og sannsynligheten for det, gitt det ikke-komplette utvalget du har, så blir det en annen sak).

 

Det å søke etter alle disse forskjellige kombinasjonene ser jeg ikke helt hvordan jeg burde/kan gjøre

 

For å sjekke hvilke kombinasjoner du _har_, kjører du en test for hvert av rankingpunktene, fra de mest verdifulle til de minst verdifulle. Så kan man stoppe såsnart man har et svar, evt. kjøre alle kombinasjoner som ikke er gjensidig utelukkende og samle alle svar ("royal flush" - "ace high", f.eks, mens "full-house" og "four-of-a-kind" trenger man ikke å teste for engang, når man har "royal flush").

 

Slik løste jeg ett par, og to par.. Halvfungerende "yallekode" Må være en bedre måte å gjøre dette på? Blir forferdelige greir dette! :(

 

Koden din slår meg som for komplisert og for lite generisk (selv om det aldri (?) er behov for mer enn 2 par, burde ikke denne kunnskapen hardkodes i kodestrukturen).

 

Det aller første steget er å finne en saklig representasjon for kort internt i koden (der "saklig" bestemmes av operasjonene på kortene i dette tilfellet), samt konvertering fra menneskevennlig format til denne representasjonen og tilbake. Jeg valgte par (rank, suit), siden deloppgaven er så enkel som å generere alle par gitt en sekvens av kort:

 

def generate_pairs(seq_of_cards):
   return combinations(seq_of_cards, 2)
# end generate_pairs

def all_pairs(sequence):
   normalised = [str2card(c) for c in sequence]
   # rank -> all cards of that rank
   tmp = defaultdict(list)
   for card in normalised:
       tmp[card[0]].append(card)

   return chain.from_iterable(generate_pairs(same_rank)
                              for same_rank in tmp.itervalues())
# end all_pairs

 

Så til kjøringen:

 

$ python poker-pairs.py QD 7C 5D 2D 7S 8D QC
[(('Q', 'D'), ('Q', 'C')), ((7, 'C'), (7, 'S'))]

 

2 par, QD+QC og 7C+7S

 

(Blir litt vel mange tupler i resultatet, så det kan tenkes at en liten klasse for kort som kan opptre som et tuppel ikke er så dumt).

 

Hvis man bare er interessert i _antall_ par, så er oppgaven enklere, da man kan droppe generate_pairs() over og erstatte den med å summere \choose{2}{P} over tmp, der P er antall kort av samme rank.

 

Tilsvarende kode kan skrives for hver av de poenggivene håndtypene.

 

Så må man "bare" lage en rangeringsfunksjon som vektlegger hånd. Det er nok en mye mer komplisert oppgave, siden man ikke vil jo ha komplett informasjon og vil måtte vektlegge hender basert på sannsynlighet.

 

edit: dammit. Velge dumme variabelnavn kan virke mot sin hensikt.

Endret av zotbar1234
  • Liker 1
Lenke til kommentar

Her var det gode svar å få :) Det er sant at eksempelet mitt var hardkodet, og ikke mye optimalt.. Men, det var vel det jeg mente med "Yallakode" => "Det kan gjøres MYE bedre", jeg viste bare ikke hvordan.

 

Det virker som en mye bedre måte å gå frem på, det du viser til av kode. Jeg har problemer med å forstå hva som faktisk skjer der, da jeg ikke kjenner til mangen av disse funksjonene du bruker.

   normalised = [str2card(c) for c in sequence]
   # Aldri hørt om defaultdict(list), hvordan fungerer dette? 
   tmp = defaultdict(list)
   for card in normalised:
   (...)
   chain.from_iterable() #Chain, og from_iterable har jeg ikke kjenskap til.. Noen kloke ord?

 

Det kansje ikke dumt å kjekke om ett eller to av kortne er i egen hånd eller ikke. Dermed vite om dette er "globalt" (alle har paret/parene), eller gjelder dette sansynligvis bare meg. Dette blir selvføgleig gjort etterpå, ved å se om ett, eller to av kortene i paret/parene finnes i egen hånd.

 

Ellers, om du eller noen andre har et tips eller to å komme med, så spytt ut! :)

Endret av warpie
Lenke til kommentar

# Aldri hørt om defaultdict(list), hvordan fungerer dette?

http://docs.python.org/library/collections.html#defaultdict-objects

 

Den bruker argumentet (i dette tilfellet list) på verdien du prøver å assigne til en ikke-eksisterende key.

 

d = defaultdict(list)

d["Liste1"].append("element")

 

 

Dette bruker .append() på listen som er verdien til key "Liste1" dersom key "Liste1" finnes.

 

Dersom key "Liste1" ikke finnes, ville den lagt til key "Liste1" med verdi som ["element"]

 

 

===

Jeg vet dog ikke helt hvorfor dette blir ["element"] og ikke ["e", "l", "e", "m", "e", "n", "t"]

Endret av Yumekui
Lenke til kommentar

Det virker som en mye bedre måte å gå frem på, det du viser til av kode. Jeg har problemer med å forstå hva som faktisk skjer der, da jeg ikke kjenner til mangen av disse funksjonene du bruker.

   chain.from_iterable() #Chain, og from_iterable har jeg ikke kjenskap til.. Noen kloke ord?

 

Prøvd den offisielle dokumentasjonen? (str2card og slikt er noe jeg lagde, men som er overhodet ikke relevant for budskapet mitt).

 

Det kansje ikke dumt å kjekke om ett eller to av kortne er på hånden eller ikke.

 

Jeg aner ikke hva du etterspør.

 

Den bruker argumentet (i dette tilfellet list) på verdien du prøver å assigne til en ikke-eksisterende key.

 

Nei, det gjør den alldeles ikke, noe dokumentasjonen er veldig tydelig på -- "The first argument provides the initial value for the default_factory attribute".

 

Jeg vet dog ikke helt hvorfor dette blir ["element"] og ikke ["e", "l", "e", "m", "e", "n", "t"]

 

Fordi det er slik list.append() virker. lst.append(T) => [T,] for en tom liste lst. Hvorfor mener du at det skulle være noe annet enn ["element",] ? (Den defaultdict'en bruker list() når en ikke-eksisterende nøkkel blir nevnt og _det_ i sin tur setter inn en list() (jfr det 1. argumentet) inn for den aktuelle nøkkelen. Derfor virker d[k].append(), for en ikke-eksisterende k i d).

Endret av zotbar1234
Lenke til kommentar

Da tror jeg jeg har misforstått veldig hvordan den fungerer. ;_;

 

Beklager.

 

Det gir for øvrig mening at det blir ["element"] dersom en tom liste legges til først for ikke-eksisterende keys, før den forsøker hva enn en spurte om, om jeg har skjønt det riktig nå, ja?

Endret av Yumekui
Lenke til kommentar
  • 2 måneder senere...

Opprett en konto eller logg inn for å kommentere

Du må være et medlem for å kunne skrive en kommentar

Opprett konto

Det er enkelt å melde seg inn for å starte en ny konto!

Start en konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
×
×
  • Opprett ny...