Określanie układów pokerowych

19

W ramach oceny robiłem grę Texas Hold'Em i zastanawiałem się, jak sprawdzić 7 dostępnych kart i ustalić, czy istnieją ręce.

Jedyną możliwą metodą, jaką mogę wymyślić, jest sortowanie kart numerycznie, a następnie sprawdzenie każdej możliwej grupy 5 kart i sprawdzenie, czy pasują one do listy każdej możliwej ręki. Zajmie to dużo czasu, a określenie pary byłoby możliwe, ponieważ kolor jest nieistotny.

Każda z kart to struny złożone z liczby / a / j / q / k i koloru (char)3(co tworzy mały symbol pik).

Czy ktoś ma jakieś sugestie, formuły lub linki, których mógłbym użyć, aby pomóc w stworzeniu systemu do analizy ręcznej?

Nie martw się jeszcze o zestawianie ze sobą rąk, to inny kociołek z rybami.

Magicaxis
źródło
1
Po prostu wskazując, ale znacznik wektorowy w swoim kontekście dotyczy algebry liniowej. Nie pojemnik.
Sidar
@ Sidar Możesz edytować tagi w przyszłości, jeśli uważasz, że nie pasują. Jeśli najedziesz myszką na tagi i pojawi się opcja „Edytuj tagi” (przynajmniej dla mnie?), I możesz edytować tylko tagi bez edycji pytania.
MichaelHouse
@ Byte56 Mam ten dziwny zwyczaj myślenia, że ​​nie jestem pewien, czy mam rację, więc robię to pasywnie poprzez komentarz ... Dlatego nie edytowałem postu. Być może coś przeoczyłem, więc czekałem na jego odpowiedź.
Sidar
Jest też fajny artykuł, który pojawił się w Game Developer kilka lat temu: cowboyprogramming.com/2007/01/04/programming-poker-ai
celion
1
Zrobiłem wdrożenia w Java do zabawy jakiś czas temu można go znaleźć tutaj: codereview.stackexchange.com/questions/10973/... . Jeśli spojrzysz na PokerHand.java, znajdziesz metody testowania każdego rodzaju rozdania (np. IsFullHouse). Działają tylko wtedy, gdy karty zostaną najpierw posortowane.
bughi

Odpowiedzi:

20

Myślę, że większość kart pokerowych można znaleźć, po prostu tworząc kilka tabel z liczbą kart w ręce, które mają każdą rangę i kolor.

Innymi słowy, utwórz szeregi kart mapujących tablice (liczby i A / J / Q / K) do liczby kart o tej wartości w twojej ręce. Jeśli gracz ma parę lub trójkę, w tej tablicy będzie element równy 2 lub 3 itd. Mają fula, jeśli jest jeden element, który ma 2, a drugi to 3, i strita jeśli w tej tablicy jest pięć kolejnych elementów równych 1.

Podobnie możesz stworzyć podobną tablicę liczby kart każdego koloru i użyć jej do wykrycia kolorów.

Po wykryciu obecności określonej ręki dość łatwo jest wrócić i znaleźć określone karty w ręce, aby wyróżnić je w interfejsie użytkownika lub cokolwiek innego, co trzeba zrobić.

W pseudokodzie:

int countByRank[13] = { 0 };        // Initialize counter to zero for each rank
for (cards in hand)
    countByRank[card.rank] += 1;    // Increment counter for this card's rank
if (countByRank.find(2))
    // There's a pair
else if (countByRank.find(3))
    // There's a three-of-a-kind
// etc...
Nathan Reed
źródło
17

Jest to trochę trudne, ponieważ jest tak wiele kombinacji. Na szczęście masz procesor, który może sprawdzić dużą liczbę kombinacji w bardzo krótkim czasie.

Będziesz potrzebował kilku różnych strategii do wykrywania różnych rodzajów rąk. Na szczęście kilka różnych typów może pokrywać się ze strategiami. Przeszukiwałbym według rangi ręki.

  1. Poker
  2. Czterech z gatunku
  3. Pełen dom
  4. Spłukać
  5. Prosto
  6. Trzy z rodzaju
  7. Dwie pary
  8. Jedna para
  9. Wysoka karta

2, 3, 6, 7, 8Są proste liczenie. Korzystając z listy kart As do króla, po prostu umieść liczbę każdej wartości na liście, zwiększając każdą znalezioną dodatkową kartę. Następnie sprawdź listę 4s, jeśli nie ma 4s, nie masz 4. Sprawdź to na 3s, jeśli nie ma 3, nie masz 3. Jeśli masz 3, sprawdź 2 (wskazując full house). I tak dalej...

Dla 1, 5można użyć tej samej listy i poszukać sekwencji, gdzie wszystkie karty mają jeden lub więcej wpisów w wykazie sekwencji 5 kart. Jeśli mają również ten sam kolor, to jest to kolor.

4może mieć taką samą konfigurację listy, ale tym razem liczysz kolor. Poszukaj liczb 5 lub więcej.

Wreszcie 9masz najwyższą kartę, co powinno polegać na sprawdzeniu ostatniej najwyższej wartości z jednej z powyższych list.

Możesz się wyrwać, gdy znajdziesz dopasowanie, jeśli szukasz w kolejności. Chociaż kontynuowanie wyszukiwania i znalezienie wszystkich dopasowań byłoby trywialne, jeśli chcesz podać wszystkie te informacje użytkownikowi.


Zasadniczo napełniacie wiadra. Następnie sprawdzanie wiader pod kątem kombinacji. Ilustrować:

wprowadź opis zdjęcia tutaj

Zaczynając od tablicy, z wiadrem dla każdej karty, iteruj karty i licz wystąpienie każdej karty. Następnie możesz łatwo iterować tablicę i sprawdzać pewne kombinacje. W tym przykładzie jasne jest, że istnieje 4, ponieważ jeden z wiader zawiera 4 przedmioty.

MichaelHouse
źródło
6

Raz wpadłem na ten algorytm. Mnoży liczby pierwsze w celu ustalenia rąk i jest bardzo interesującą lekturą. Cactus Kev's Poker Hand Evaluator

petervaz
źródło
1
Ten jest interesujący, ale nie jestem pewien, czy przeczytałeś to wszystko. Ten algorytm dotyczy 5 kart . Być może znalazłeś w wyszukiwarce Google związanej z 7 kartami, ponieważ autor twierdzi, że ma algorytm dla 7 kart, ale go nie udostępnia. Zobacz szary tekst u góry strony. Nie jestem więc pewien, jak użyteczny jest ten algorytm dla zestawu 7 kart.
MichaelHouse
1
Ponieważ istnieje tylko 21 różnych układów 5 kart, które można wykonać z układu 7 kart, jedną z opcji jest użycie oceny 5 kart na każdym z nich i wybranie najlepszego.
Adam
@ Byte56 Masz rację, pamiętam, że użyłem 7 kart, ale musiałem wcześniej ustalić najlepszą 5 kart, co w pewnym sensie podważyło skuteczność.
petervaz
Link do tej odpowiedzi zgnił, a domenę przejął spamer. Przekierowałem link do archiwum oryginalnej strony, ale aby uczynić tę odpowiedź bardziej wiarygodną, ​​idealnie byłoby edytować odpowiedź, aby zawierała podsumowanie algorytmu zaproponowanego w samej treści odpowiedzi.
DMGregory
2

Aby uzupełnić doskonałe odpowiedzi na to pytanie, które już otrzymałem, pomyślałem, że pomocne byłoby zaoferowanie jednego z najprostszych sposobów porównywania rąk po zastosowaniu podstawowej techniki klasyfikacji. Przede wszystkim będziesz chciał oznaczyć ręce klasą , jak sugeruje wiele odpowiedzi - większość twoich porównań „czy ręka X jest lepsza niż ręka Y?” można to zrobić po prostu porównując klasy obu rąk i sprawdzając, która klasa jest lepsza. Co do reszty, będziesz musiał porównać karty po karcie, i okazuje się, że nieco więcej pracy w klasyfikacji ułatwi to.

Jako podstawowy przypadek rozważ sytuację, w której obie ręce są rękami „z wysoką kartą”; w takim przypadku najpierw porównujesz dwie najwyższe karty, a następnie (jeśli pasują do siebie) kolejne dwie karty itp. Jeśli założymy, że każda ręka wejściowa jest posortowana od najwyższej do najniższej karty, takie podejście prowadzi do kodu, który wygląda jak to:

int CompareHandsOfSameClass(Hand h1, Hand h2) {
  for ( int i = 0; i < 5; i++ ) {
    if ( h1[i].rank > h2[i].rank ) {
      return -1;
    } else if ( h1[i].rank < h2[i].rank ) {
      return 1;
    }
  }
  return 0;
}

Dobra wiadomość: okazuje się, że to uporządkowanie leksykograficzne , odpowiednio poprawione, służy do porównania dwóch rąk w dowolnymklas, o ile ich klasa jest taka sama. Na przykład, ponieważ sposobem porównywania par jest najpierw porównanie par, a następnie pozostałych trzech kart, możesz posortować rękę, aby najpierw umieścić parę (lub nawet jedną kartę pary!) I przeprowadzić to samo porównanie. (Na przykład, ręka taka jak A9772 byłaby przechowywana jako 77A92 lub, jeszcze lepiej, 7A927; ręka A9972 byłaby przechowywana jako 9A729, i porównując z powyższym kodem zacząłbyś od umieszczenia 7 na 9 i okazało się, że A9972 wygrał). Ręka dwóch par byłaby przechowywana najpierw z wyższą z dwóch par, potem niższą, a następnie „kickerem” (tak więc np. A9977 zapisałby jako 97A97); trójka byłaby przechowywana z jedną kartą trzech, najpierw kopaczy, a następnie innych kart (np. A7772 to 7A277); pełny dom byłby przechowywany z jednym z trzech, a następnie z jednym z dwóch (np. 99777 byłby przechowywany jako 79779); zarówno strity, jak i kolory mogą być przechowywane w „bezpośrednim porządku leksykograficznym”, ponieważ oba są porównywane tak jak ręce z wysoką kartą. Prowadzi to do prostej zewnętrznej funkcji komparatora, która działa dla wszystkich klas rąk z już podaną funkcją:

// Compare two hands, returning -1/0/+1 as hand 1 is less than, equal to,
// or greater than hand 2. Note that this function assumes the hands have
// already been classified and sorted!
int CompareHands(Hand h1, Hand h2) {
  if ( h1.handClass > h2.handClass ) {
    return -1;
  } else if ( h1.handClass < h2.handClass ) {
    return 1;
  } else {
    return CompareHandsOfSameClass(h1, h2);
  }
}

Mam nadzieję, że będzie to pomocne!

Steven Stadnicki
źródło
1

Możliwe są pewne paralelizacje przy użyciu odpowiednich reprezentacji kart i kręcenia bitów. Na przykład ten kod Java ocenia trudności z 7 kartami, zwracając liczbę całkowitą, której można użyć do porównania dwóch rąk. Można go dostosować do zgłaszania rodzaju ręki w bardziej przyjazny dla użytkownika sposób. Główne pomysły pochodzą ze strony Cactus Kev, do której odwołuje się wcześniejsza odpowiedź.

Jeśli interesują Cię tylko możliwe implementacje nazywania rozdania w różnych językach, a nie wydajność i przejrzystość kodu, możesz również spojrzeć na wyzwanie Nazwa rozdania pokerowego na codegolf.SE.

Peter Taylor
źródło
1

Najpierw musisz znać stopień i kolor wszystkich kart; banalne, ale konieczne.

Następnie przekręć te 7 kart i utwórz dwa histogramy; jeden według rangi (przy użyciu tablicy z 13 indeksami, wszystkie zainicjowane do zera i zwiększane o 1, jeśli i kiedy zostanie znaleziona karta w ręce o tej randze) i jeden według koloru (przy użyciu tablicy czterech elementów zbudowanych podobnie jak dla rangi) . Są to operacje liniowe i możesz wykonać obie operacje dla każdej karty tylko dla jednego zestawu przejść.

Następnie możesz ustalić, czy istnieje którykolwiek z poniższych układów, po prostu badając każdy histogram pod kątem segmentów spełniających kryteria i / lub prosty test kontrolny:

  • Para: Czy dokładnie jeden segment rangi ma wartość dokładnie 2, a żaden inny segment nie ma wartości powyżej 1 i nie ma koloru?
  • Dwie pary: Czy dwa lub więcej segmentów ma wartość dokładnie 2, przy czym żaden segment nie ma więcej niż 2 i nie ma koloru? (oczywiście trzy pary to nie ręka, ale jest to możliwe, biorąc pod uwagę siedem kart; najsilniejszą dwiema parami jest ręka gracza)
  • TOAK: Czy dokładnie jedno wiadro ma wartość dokładnie 3, a żadne inne wiadro nie ma wartości większej niż 1 i nie ma koloru?
  • Prosto: Czy pięć kolejnych zestawów rang ma wartość 1 lub więcej bez koloru? (Nie zapominaj, że asy są wysokie i niskie; możesz użyć histogramu rangi 14 elementów i policzyć asy w dwóch wiadrach, jeśli chcesz)
  • Flush: Czy któryś wiadro koloru ma 5 lub więcej kart? (jeśli tak, zeskanuj rękę w poszukiwaniu kart tego koloru i wybierz 5 najlepszych)
  • Full House: Czy którykolwiek z segmentów ma wartość 3, a jakikolwiek inny wiadro ma wartość 2 (przy 7 kartach kolor nie jest możliwy z fulem, chyba że grasz talią Pinochle)
  • Four of a Kind: Czy jedna ranga ma wartość 4? (żadna inna kombinacja nie powinna być możliwa)
  • Straight Flush: Czy na histogramach jest zarówno strit, jak i kolor? Jeśli tak, to czy we wskazanym kolorze jest co najmniej jedna karta o randze pasującej do każdej rangi wskazanego strita? (jest to prawdopodobnie najdroższy pod względem obliczeniowym, ale powinno być łatwo policzyć, ile jest kolejnych rang, i powinieneś skanować rękę tylko raz dla 5 kolejnych rang, dwa razy dla 6 i trzy razy dla 7)

Możesz oczywiście połączyć kilka z tych kontroli:

  • Czy jest kolor?
  • Czy jest prosta?
    • Jeśli są oba, czy jest to strit?
    • Jeśli jest to strit, czy ma zarówno asa, jak i króla?
  • Czy istnieje czwórka?
  • Ile jest trójek? (Dwa, to full house. Jeden, sprawdź pary)
  • Ile tam jest par? (Z dwoma lub więcej, to dwie pary. Z jednym, jeśli są też trzy, to jest fula, w przeciwnym razie to para)
  • Żadne z powyższych (wysoka karta).

Zasadniczo, jeśli odpowiedzi na te pytania dadzą jakąkolwiek rękę, ustaw wynikową wartość „siły ręki” na siłę znalezionej ręki, jeśli wartość nie jest już wyższa. Na przykład, jeśli masz fula, siła 7 z 9, to masz także trójkę, siłę 4 i parę, siłę 2.

Istnieje kilka skrótów i szybkich outów, ale ogólnie rzecz biorąc, uruchomienie wszystkich kontroli nie jest tak drogie.

KeithS
źródło
0

Możesz grać w pokera stosunkowo łatwo, stosując proste podejście iteracyjne.

Dla każdej karty sprawdź, czy jest jedna, dwie lub trzy inne o tej samej twarzy, aby sprawdzić parę lub trzy / cztery tego samego rodzaju.

Pełne domy są podobne. Lub jeśli znajdziesz zarówno parę, jak i trójkę, które nie są tą samą twarzą, oflaguj pełny dom jako znaleziony.

Aby uzyskać kolor, sprawdź każdy kolor, aby sprawdzić, czy jest ich pięć.

Sprawdzanie proste jest łatwe, nawet jeśli nie jest posortowane. Dla każdej karty sprawdź, czy jest jedna wyższa, i powtarzaj, aż pięć kolejnych kart zostanie znalezionych, czy nie.

Poker królewski i poker prosty można znaleźć podobnie jak strity. Poker królewski ma kilka dodatkowych warunków, w których karty o niższej wartości można zignorować.

Tak, to podejście jest nieefektywne, ale w przypadku większości gier pokerowych jest to nieistotne. Co pół minuty sprawdzasz niewielką garstkę graczy, nie sprawdzając tysięcy rozdań na sekundę.

Istnieją lepsze metody, ale kodowanie może zająć więcej czasu. Prawdopodobnie masz ważniejsze rzeczy, na które możesz poświęcić czas / pieniądze, dzięki czemu gra będzie lepsza z punktu widzenia graczy, oprócz sprytności i wydajności algorytmu.

Sean Middleditch
źródło
0

prosty sposób na znalezienie par, podwójnych par, toaków, pełnych domów, pokerów itp. to:

porównaj każdą kartę ze sobą w zagnieżdżonej pętli, takiej jak ta:

int matches=0;
for (int i=0;i<5;i++)
   for (int j=0;j<5;j++)
      if (i!=j && cardvalue(card[j])==cardvalue(card[i])) matches++;

mecze będą zawierać:
2 dla pary
4 dla dwóch par
6 dla toak
8 dla fullhouse
12 dla pokera

aby zoptymalizować prędkość: nie trzeba uruchamiać pętli j do 5, można ją uruchomić na i-1. porównanie „i! = j” można następnie usunąć, wartości dopasowania są następnie zmniejszone o połowę (1 = para, 2 = 2 para itd.)

Thomas Schüler
źródło