Menentukan Tangan Poker

19

Saya telah membuat permainan Texas Hold'Em sebagai bagian dari penilaian, dan saya telah mempertimbangkan bagaimana memeriksa 7 kartu yang tersedia dan menentukan apakah ada tangan.

Satu-satunya metode yang mungkin saya pikirkan adalah mengurutkan kartu secara numerik, kemudian memeriksa setiap kelompok yang mungkin terdiri dari 5 kartu dan memeriksa apakah mereka cocok dengan daftar setiap tangan yang mungkin. Itu akan memakan waktu yang lama snd hanya akan layak untuk menentukan pasangan, karena gugatan itu tidak relevan.

Kartu masing-masing string, terdiri dari nomor / a / j / q / k, dan suit (char)3(yang membuat simbol sekop kecil).

Adakah yang punya saran, formula, atau tautan yang bisa saya gunakan untuk membantu membuat sistem analisis tangan?

Jangan khawatir tentang peringkat tangan terhadap satu sama lain, itu adalah ketel ikan yang berbeda.

Magicaxis
sumber
1
Hanya menunjukkannya tetapi tag vektor dalam konteksnya adalah tentang aljabar linier. Bukan wadahnya.
Sidar
@ Sidar Jangan ragu untuk mengedit tag di masa depan jika Anda yakin itu tidak cocok. Jika Anda mengarahkan kursor ke tag dan opsi "Edit tag" muncul (setidaknya untuk saya?), Dan Anda dapat mengedit tag hanya tanpa mengedit pertanyaan.
MichaelHouse
@ Byte56 Saya punya kebiasaan berpikir yang aneh. Saya tidak yakin apakah saya benar, jadi saya melakukannya secara pasif melalui komentar ... Itu sebabnya saya tidak mengedit posting. Mungkin saya melewatkan sesuatu di pos, jadi saya menunggu jawabannya.
Sidar
Ada juga artikel bagus di sini yang muncul di Game Developer beberapa tahun lalu: cowboyprogramming.com/2007/01/04/programming-poker-ai
celion
1
Saya melakukan implementasi di java untuk bersenang-senang beberapa waktu lalu Anda dapat menemukannya di sini: codereview.stackexchange.com/questions/10973/… . Jika Anda melihat di PokerHand.java Anda akan menemukan metode untuk menguji setiap jenis tangan (mis. IsFullHouse). Mereka hanya berfungsi jika kartu disortir terlebih dahulu.
bughi

Jawaban:

20

Saya pikir Anda dapat menemukan mayoritas tangan poker dengan hanya membuat beberapa tabel dari berapa banyak kartu di tangan yang ada di setiap peringkat dan suit.

Dengan kata lain, buat peringkat kartu pemetaan array (angka dan A / J / Q / K) untuk jumlah kartu peringkat itu di tangan Anda. Jika pemain memiliki sepasang atau tiga jenis, akan ada elemen dalam array ini sama dengan 2 atau 3, dll. Mereka memiliki rumah penuh jika ada satu elemen yang 2 dan yang lain 3, dan lurus jika ada lima elemen berturut-turut sama dengan 1 dalam array ini.

Anda juga dapat membuat susunan yang sama dari jumlah kartu masing-masing kartu, dan menggunakannya untuk mendeteksi flush.

Setelah Anda mendeteksi keberadaan tangan tertentu, cukup mudah untuk kembali dan menemukan kartu tertentu di tangan, untuk menyorotnya di UI atau apa pun yang perlu Anda lakukan.

Dalam pseudocode:

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
sumber
17

Agak sulit karena ada begitu banyak kombinasi. Untungnya Anda memiliki prosesor yang dapat memeriksa sejumlah besar kombinasi dalam waktu yang sangat singkat.

Anda memerlukan beberapa strategi berbeda, untuk mendeteksi berbagai jenis tangan. Untungnya, beberapa tipe yang berbeda dapat tumpang tindih strategi. Saya akan mencari, dalam urutan pangkat tangan.

  1. Flush lurus
  2. Empat sejenis
  3. Rumah penuh
  4. Menyiram
  5. Lurus
  6. Tiga sejenis
  7. Dua pasangan
  8. Satu pasang
  9. Kartu tinggi

2, 3, 6, 7, 8Semua penghitungan sederhana. Menggunakan daftar kartu Ace ke King, cukup tempatkan jumlah setiap nilai dalam daftar, bertambah untuk setiap kartu tambahan yang ditemukan. Kemudian periksa daftar untuk 4s, jika tidak ada 4s, Anda tidak memiliki 4 jenis. Periksa 3s, jika tidak ada 3s, Anda tidak memiliki 3 dari jenis. Jika Anda memiliki angka 3, periksa angka 2 (menunjukkan rumah penuh). Dan seterusnya...

Sebab 1, 5Anda dapat menggunakan daftar yang sama dan mencari urutan di mana semua kartu memiliki satu atau lebih entri dalam daftar untuk urutan 5 kartu. Jika mereka juga memiliki setelan yang sama, itu adalah flush lurus.

4dapat memiliki pengaturan daftar yang sama tetapi kali ini Anda menghitung gugatan. Cari nomor 5 atau lebih tinggi.

Akhirnya, 9Anda memiliki kartu tertinggi, yang seharusnya menjadi masalah sederhana dengan melihat nilai tertinggi terakhir dari salah satu daftar Anda di atas.

Anda dapat keluar setelah menemukan kecocokan jika Anda melakukan pencarian secara berurutan. Meskipun akan sepele untuk melanjutkan pencarian dan menemukan semua kecocokan jika Anda ingin memberikan semua informasi itu kepada pengguna.


Intinya, Anda sedang mengisi ember. Lalu, periksa ember untuk kombinasi. Menggambarkan:

masukkan deskripsi gambar di sini

Dimulai dengan larik, dengan ember untuk setiap kartu, beralih melalui kartu dan hitung instance dari setiap kartu. Kemudian Anda dapat dengan mudah mengulangi array dan memeriksa kombinasi tertentu. Dalam contoh ini, jelas ada 4 jenis karena salah satu ember memiliki 4 item di dalamnya.

MichaelHouse
sumber
6

Saya bertemu algoritma ini sekali. Ini mengalikan bilangan prima untuk menentukan tangan dan merupakan bacaan yang sangat menarik. Evaluator Tangan Poker Cactus Kev

petervaz
sumber
1
Yang itu menarik, tapi saya tidak yakin Anda membaca semuanya. Algoritma itu untuk 5 kartu . Anda mungkin menemukan di dalam pencarian Google terkait dengan 7 kartu, karena penulis menyatakan mereka memiliki algoritma untuk 7 kartu, tetapi tidak membagikannya. Lihat teks abu-abu di dekat bagian atas halaman. Jadi saya tidak yakin seberapa berguna algoritma itu untuk 7 set kartu.
MichaelHouse
1
Karena hanya ada 21 kartu berbeda 5 tangan yang dapat dibuat dari kartu 7 tangan satu pilihan adalah menggunakan evaluator 5 kartu pada masing-masing kartu, dan pilih yang terbaik.
Adam
@ Byte56 Anda benar, saya ingat saya menggunakannya untuk 7 kartu tetapi harus menentukan 5 kartu terbaik sebelumnya, yang agak merusak efisiensi.
petervaz
Tautan pada jawaban ini telah membusuk, dan domain tersebut diambil oleh seorang spammer. Saya telah mengarahkan ulang tautan ke arsip halaman asli, tetapi untuk membuat jawaban ini lebih kuat, sebaiknya mengedit jawaban dengan menyertakan ringkasan algoritma yang diusulkan di dalam tubuh jawaban itu sendiri.
DMGregory
2

Untuk melengkapi jawaban yang sangat baik dari pertanyaan ini, saya pikir akan sangat membantu untuk menawarkan salah satu cara paling mudah untuk membandingkan tangan ketika teknik klasifikasi dasar sudah ada. Pertama-tama, Anda ingin memberi label tangan pada kelas mereka , seperti yang disarankan oleh banyak jawaban - sebagian besar perbandingan Anda tentang 'tangan X lebih baik daripada tangan Y?' kemudian dapat dilakukan hanya dengan membandingkan kelas dua tangan dan melihat kelas mana yang lebih baik. Selebihnya, Anda harus membandingkan berdasarkan kartu-demi-kartu, dan ternyata sedikit lebih banyak pekerjaan dalam klasifikasi akan membuat ini lebih mudah.

Sebagai kasus dasar, pertimbangkan situasi di mana kedua tangan adalah kartu 'tinggi'; dalam hal ini, Anda akan membandingkan dua kartu tertinggi terlebih dahulu, kemudian (jika mereka cocok) dua kartu berikutnya, dll. Jika Anda berasumsi bahwa setiap input tangan diurutkan dari kartu tertinggi ke terendah, pendekatan ini mengarah ke kode yang terlihat seperti ini:

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;
}

Sekarang, kabar baik: ternyata ini memesan leksikografis , sesuai tweak, bekerja untuk membandingkan dua tangan di setiapkelas, selama kelas mereka sama. Misalnya, karena cara membandingkan pasangan adalah dengan membandingkan pasangan terlebih dahulu, kemudian tiga kartu lainnya, Anda dapat mengurutkan tangan Anda untuk menempatkan pasangan lebih dulu (atau bahkan satu kartu dari pasangan terlebih dahulu!) Dan menjalankan perbandingan yang sama ini. (Jadi, misalnya, tangan seperti A9772 akan disimpan sebagai 77A92 atau, lebih baik lagi, 7A927; tangan A9972 akan disimpan sebagai 9A729, dan membandingkan dengan kode di atas Anda akan mulai dengan mengadu 7 melawan 9 dan menemukan bahwa A9972 menang). Satu tangan dari dua pasangan akan disimpan dengan yang lebih tinggi dari dua pasangan pertama, kemudian yang lebih rendah, kemudian 'penendang' (jadi, misalnya, A9977 akan disimpan sebagai 97A97); tiga jenis akan disimpan dengan satu kartu dari tiga pertama, kemudian kickers, kemudian kartu lainnya (misalnya, A7772 akan menjadi 7A277); rumah penuh akan disimpan dengan satu dari tiga dan kemudian satu dari dua (mis., 99777 akan disimpan sebagai 79779); dan lurus dan flushes keduanya dapat disimpan dalam urutan 'lexicographical langsung' karena keduanya dibandingkan seperti tangan kartu tinggi. Ini mengarah ke fungsi pembanding luar langsung yang bekerja untuk semua kelas tangan dengan fungsi yang sudah diberikan:

// 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);
  }
}

Semoga ini bisa membantu!

Steven Stadnicki
sumber
1

Ada beberapa parallelisations mungkin menggunakan representasi kartu yang sesuai dan sedikit-twiddling. Sebagai contoh, kode Java ini mengevaluasi kartu 7-kartu mengembalikan integer yang dapat digunakan untuk membandingkan dua tangan. Itu bisa diadaptasi untuk melaporkan jenis tangan dengan cara yang lebih ramah pengguna. Gagasan inti datang dari halaman Cactus Kev yang dirujuk dalam jawaban sebelumnya.

Jika Anda hanya tertarik pada implementasi yang mungkin untuk penamaan tangan dalam berbagai bahasa daripada efisiensi dan kejelasan kode, Anda juga bisa melihat pada Name the hand poker challenge pada codegolf.SE.

Peter Taylor
sumber
1

Pertama, Anda perlu mengetahui peringkat dan setelan semua kartu; sepele tapi perlu.

Kemudian, putar melalui 7 kartu ini dan buat dua histogram; satu demi peringkat (menggunakan array dengan 13 indeks, semua diinisialisasi ke nol dan bertambah 1 jika dan ketika kartu di tangan dengan peringkat itu ditemukan) dan satu demi suit (menggunakan array empat elemen yang dibangun sama seperti untuk peringkat) . Ini adalah operasi linear dan Anda dapat melakukan kedua operasi untuk setiap kartu hanya untuk satu set traversal.

Anda kemudian dapat menentukan apakah ada tangan berikut yang ada hanya dengan memeriksa setiap histogram untuk ember yang cocok dengan kriteria, dan / atau tes tindak lanjut sederhana:

  • Pasangan: Apakah tepat satu ember peringkat memiliki nilai tepat 2, tanpa ember lain yang memiliki nilai di atas 1 dan tidak ada flush?
  • Dua Pasang: Apakah dua atau lebih ember peringkat memiliki nilai tepat 2, tanpa ember yang memiliki lebih dari 2 dan tanpa flush? (Jelas tiga pasangan bukanlah tangan, tetapi kemungkinan diberikan tujuh kartu; dua pasangan terkuat adalah tangan pemain)
  • TOAK: Apakah tepat satu ember memiliki nilai tepat 3, tanpa ember lain yang memiliki nilai lebih dari 1 dan tidak ada flush?
  • Lurus: Apakah lima ember peringkat berturut-turut memiliki nilai 1 atau lebih tanpa flush? (Jangan lupa bahwa Aces keduanya tinggi dan rendah; Anda bisa menggunakan histogram peringkat 14 elemen dan menghitung Aces dalam dua ember jika Anda mau)
  • Flush: Apakah ember yang sesuai memiliki 5 kartu atau lebih? (jika demikian, pindai tangan untuk mendapatkan kartu yang sesuai dan pilih 5 teratas)
  • Full House: Apakah ada satu ember peringkat memiliki nilai 3 dan ember lainnya memiliki nilai 2 (dengan 7 kartu, flush tidak mungkin dengan rumah penuh kecuali jika Anda bermain dengan dek Pinochle)
  • Four of a Kind: Apakah ada satu peringkat yang memiliki nilai 4? (tidak ada kombinasi lain yang memungkinkan)
  • Straight Flush: Apakah ada straight dan flush yang ditunjukkan oleh histogram? Jika demikian, apakah ada setidaknya satu kartu dalam suit flush yang ditunjukkan dengan peringkat yang cocok dengan masing-masing peringkat dari straight yang ditunjukkan? (Ini mungkin yang paling mahal secara komputasi, tetapi harus sederhana untuk menghitung berapa banyak peringkat berturut-turut, dan Anda hanya perlu memindai tangan sekali untuk 5 peringkat berturut-turut, dua kali untuk 6 dan tiga kali untuk 7)

Anda dapat, secara alami, menggabungkan beberapa cek ini:

  • Apakah ada flush?
  • Apakah ada yang lurus?
    • Jika ada keduanya, apakah itu flush lurus?
    • Jika itu adalah straight flush, apakah ia memiliki Ace dan King?
  • Apakah ada empat jenis?
  • Ada berapa tiga jenis? (Dua, ini rumah yang penuh. Satu, periksa pasangan)
  • Ada berapa pasang? (Dengan dua atau lebih, itu adalah dua pasangan. Dengan satu, jika ada juga tiga itu adalah rumah penuh, jika tidak itu adalah sepasang)
  • Tidak ada yang di atas (kartu tinggi).

Pada dasarnya, jika jawaban untuk ini menghasilkan tangan apa pun, tetapkan nilai "kekuatan tangan" yang dihasilkan dengan kekuatan tangan yang ditemukan, jika nilainya belum lebih tinggi. Misalnya, jika Anda memiliki rumah penuh, kekuatan 7 dari 9, maka Anda juga memiliki tiga jenis, kekuatan 4, dan sepasang, kekuatan 2.

Ada beberapa cara pintas beluk cepat, tapi secara keseluruhan itu tidak benar-benar yang mahal untuk hanya menjalankan semua pemeriksaan.

KeithS
sumber
0

Anda dapat melakukan permainan poker dengan relatif mudah dengan pendekatan berulang sederhana.

Untuk setiap kartu, periksa apakah ada satu atau dua atau tiga kartu lain dengan wajah yang sama untuk memeriksa pasangan atau tiga / empat jenis kartu.

Rumah penuh serupa. Atau jika Anda menemukan pasangan dan tiga jenis yang tidak sama wajahnya, beri tanda sebuah rumah penuh seperti yang ditemukan.

Untuk flush, periksa setiap setelan untuk melihat apakah ada lima setelan yang sama.

Mengecek lurus itu mudah, bahkan jika tidak disortir. Untuk setiap kartu, periksa apakah ada yang lebih tinggi, dan ulangi sampai lima kartu berturut-turut ditemukan atau tidak.

Royal flushes dan straight flushes dapat ditemukan mirip dengan lurus. Royal flushes memiliki beberapa kondisi tambahan sehingga kartu yang bernilai lebih rendah dapat diabaikan.

Ya, pendekatan ini tidak efisien, tetapi untuk sebagian besar permainan poker, itu tidak relevan. Anda memeriksa segelintir pemain setiap setengah menit atau lebih, tidak memeriksa ribuan tangan per detik.

Metode yang lebih baik ada tetapi mungkin membutuhkan lebih banyak waktu untuk kode, dan Anda mungkin memiliki hal-hal lebih penting untuk menghabiskan waktu / uang yang akan membuat permainan yang lebih baik dari perspektif pemain selain kepintaran dan efisiensi suatu algoritma.

Sean Middleditch
sumber
0

cara sederhana untuk menemukan pasangan, pasangan ganda, toak, rumah penuh, pokers dll adalah sebagai berikut:

bandingkan setiap kartu dengan satu sama lain dalam lingkaran bertingkat seperti ini:

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++;

pertandingan akan menampung sebagai berikut:
2 untuk pasangan
4 untuk dua pasang
6 untuk toak
8 untuk rumah penuh
12 untuk poker

untuk mempercepat mengoptimalkan ini: itu tidak diperlukan untuk menjalankan j-loop hingga 5, itu dapat dijalankan ke i-1. perbandingan "i! = j" kemudian dapat dihapus, nilai untuk kecocokan kemudian dibagi dua (1 = pasangan, 2 = 2 pasang dll.)

Thomas Schüler
sumber