การกำหนดแฮนด์โป๊กเกอร์


19

ฉันได้ทำเกม Texas Hold'Em เป็นส่วนหนึ่งของการประเมินและฉันครุ่นคิดถึงวิธีการตรวจสอบไพ่ที่มีอยู่ทั้ง 7 ใบและตัดสินว่ามือมีอยู่จริงหรือไม่

วิธีเดียวที่เป็นไปได้ที่ฉันคิดได้คือเรียงไพ่เป็นตัวเลขจากนั้นตรวจสอบกลุ่มที่เป็นไปได้ 5 ใบและตรวจสอบว่าตรงกับรายการของมือที่เป็นไปได้ทุกใบหรือไม่ ซึ่งจะใช้เวลานาน snd จะเป็นไปได้สำหรับการหาคู่เท่านั้นเนื่องจากชุดไม่เกี่ยวข้อง

ไพ่แต่ละสายประกอบด้วยตัวเลข / a / j / q / k และชุดสูท(char)3(ที่ทำสัญลักษณ์โพดำเล็กน้อย)

ไม่มีใครมีคำแนะนำสูตรหรือลิงก์ที่ฉันสามารถใช้เพื่อช่วยสร้างระบบการวิเคราะห์ด้วยมือได้หรือไม่?

ไม่ต้องกังวลเกี่ยวกับการจัดอันดับมือซึ่งกันและกันนั่นคือปลากาต้มน้ำที่แตกต่างกัน


1
เพียงแค่ชี้ให้เห็น แต่แท็กเวกเตอร์ในบริบทนั้นเกี่ยวกับพีชคณิตเชิงเส้น ไม่ใช่ภาชนะ
Sidar

@Sidar รู้สึกอิสระที่จะแก้ไขแท็กในอนาคตหากคุณเชื่อว่าพวกเขาไม่เหมาะสม หากคุณโฮเวอร์เหนือแท็กและตัวเลือก "แก้ไขแท็ก" จะปรากฏขึ้น (อย่างน้อยสำหรับฉันหรือไม่) และคุณสามารถแก้ไขได้เฉพาะแท็กโดยไม่ต้องแก้ไขคำถาม
MichaelHouse

@ Byte56 ฉันมีนิสัยแปลก ๆ ในการคิดฉันไม่แน่ใจว่าฉันถูกต้องหรือไม่ดังนั้นฉันจึงต้องทำอย่างจริงจังเพื่อแสดงความคิดเห็น ... นั่นเป็นเหตุผลที่ฉันไม่ได้แก้ไขโพสต์ บางทีฉันอาจพลาดบางสิ่งในโพสต์ดังนั้นฉันจึงรอคำตอบของเขา
Sidar

นอกจากนี้ยังมีบทความดีๆที่ปรากฏใน Game Developer เมื่อไม่กี่ปีที่ผ่านมา: cowboyprogramming.com/2007/01/04/programming-poker-ai
celion

1
ผมดำเนินการใน java เพื่อความสนุกสนานในขณะที่กลับคุณสามารถค้นหาได้ที่นี่: codereview.stackexchange.com/questions/10973/... หากคุณมองใน PokerHand.java คุณจะพบวิธีทดสอบมือแต่ละประเภท (เช่น isFullHouse) มันจะทำงานได้ก็ต่อเมื่อไพ่นั้นถูกจัดเรียงก่อน
bughi

คำตอบ:


20

ฉันคิดว่าคุณสามารถหามือโป๊กเกอร์ส่วนใหญ่ได้โดยทำตารางสองสามใบของไพ่ที่มีอยู่ในมือและแต่ละชุด

กล่าวอีกนัยหนึ่งให้สร้างการ์ดการทำแผนที่อาเรย์ (ตัวเลขและ A / J / Q / K) เพื่อนับจำนวนไพ่ของอันดับนั้นในมือของคุณ หากผู้เล่นมีคู่หรือสามชนิดจะมีองค์ประกอบในอาร์เรย์นี้เท่ากับ 2 หรือ 3 และอื่น ๆ พวกเขามีบ้านเต็มถ้ามีองค์ประกอบหนึ่งคือ 2 และอีก 3 นั่นคือตรง หากมีห้าองค์ประกอบต่อเนื่องเท่ากับ 1 ในอาร์เรย์นี้

ในทำนองเดียวกันคุณสามารถสร้างอาร์เรย์ที่คล้ายกันของการนับไพ่ของแต่ละชุดและใช้มันเพื่อตรวจจับการฟลัช

เมื่อคุณตรวจพบว่ามีไพ่ในมือมันเป็นเรื่องง่ายที่จะกลับไปหาไพ่ในมือเพื่อไฮไลท์พวกเขาใน UI หรือสิ่งที่คุณต้องทำ

ใน 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...

17

มันค่อนข้างยุ่งยากเพราะมีหลายอย่างผสมกัน โชคดีที่คุณมีโปรเซสเซอร์ที่สามารถตรวจสอบชุดค่าผสมจำนวนมากได้ในเวลาอันสั้น

คุณจะต้องใช้กลยุทธ์ที่แตกต่างกันเล็กน้อยในการตรวจจับมือประเภทต่างๆ โชคดีที่มีบางประเภทที่แตกต่างกันสามารถทับซ้อนกลยุทธ์ ฉันจะค้นหาโดยเรียงตามลำดับมือ

  1. ล้างตรง
  2. สี่ชนิด
  3. บ้านเต็ม
  4. เปี่ยม
  5. ตรง
  6. สามชนิด
  7. สองคู่
  8. หนึ่งคู่
  9. ไพ่สูง

2, 3, 6, 7, 8มีทั้งหมดนับง่ายๆ การใช้รายการไพ่ Ace ถึง King เพียงใส่หมายเลขของแต่ละค่าในรายการเพิ่มขึ้นสำหรับแต่ละการ์ดที่พบ จากนั้นตรวจสอบรายการสำหรับ 4s หากไม่มี 4s คุณไม่มีประเภท 4 ตรวจสอบ 3s ถ้าไม่มี 3s คุณไม่มี 3 ชนิด หากคุณมี 3 ให้ตรวจสอบ 2 (ระบุบ้านเต็ม) และอื่น ๆ ...

สำหรับ1, 5คุณสามารถใช้รายการเดียวกันและมองหาลำดับที่บัตรทุกคนมีหนึ่งหรือมากกว่าหนึ่งรายการในรายการสำหรับลำดับที่ 5 บัตร หากพวกเขามีชุดเดียวกันก็เป็นตรงเปี่ยม

4สามารถมีการตั้งค่ารายการเดียวกัน แต่คราวนี้คุณกำลังนับสูท มองหาตัวเลข 5 หรือสูงกว่า

ในที่สุด9คุณมีบัตรสูงสุดซึ่งควรเป็นเรื่องง่าย ๆ ในการดูมูลค่าสูงสุดครั้งสุดท้ายจากรายการใดรายการหนึ่งของคุณด้านบน

คุณสามารถแยกย่อยเมื่อคุณพบการแข่งขันถ้าคุณค้นหาตามลำดับ แม้ว่ามันจะไม่สำคัญที่จะค้นหาต่อไปและค้นหารายการที่ตรงกันทั้งหมดหากคุณต้องการให้ข้อมูลทั้งหมดแก่ผู้ใช้


เป็นหลักคุณเติมถัง จากนั้นตรวจสอบถังสำหรับการรวมกัน เพื่อแสดง:

ป้อนคำอธิบายรูปภาพที่นี่

เริ่มต้นด้วยอาร์เรย์ด้วยที่เก็บข้อมูลสำหรับการ์ดแต่ละใบวนซ้ำผ่านการ์ดและนับอินสแตนซ์ของการ์ดแต่ละใบ จากนั้นคุณสามารถวนซ้ำอาร์เรย์และตรวจสอบชุดค่าผสมบางอย่างได้อย่างง่ายดาย ในตัวอย่างนี้เป็นที่ชัดเจนว่ามี 4 ชนิดเนื่องจากหนึ่งในถังมี 4 รายการในนั้น


6

ฉันชนเข้ากับอัลกอริทึมนี้หนึ่งครั้ง มันทวีคูณตัวเลขเพื่อกำหนดมือและเป็นอ่านที่น่าสนใจมาก มือไพ่โป๊กเกอร์ของผู้ประเมิน


1
อันนั้นน่าสนใจ แต่ฉันไม่แน่ใจว่าคุณอ่านมันทั้งหมด อัลกอริทึมที่มีไว้สำหรับ5 ใบ คุณอาจพบในการค้นหาของ Google ที่เกี่ยวข้องกับการ์ด 7 ใบเนื่องจากผู้เขียนระบุว่าพวกเขามีอัลกอริทึมสำหรับการ์ด 7 ใบ แต่ไม่ได้แชร์ ดูข้อความสีเทาที่ด้านบนของหน้า ดังนั้นฉันไม่แน่ใจว่าอัลกอริทึมนั้นมีประโยชน์สำหรับชุดการ์ด 7 ใบอย่างไร
MichaelHouse

1
เนื่องจากมีไพ่ในมือ 5 ใบที่แตกต่างกันเพียง 21 ใบเท่านั้นที่สามารถทำได้จากมือ 7 ใบหนึ่งทางเลือกหนึ่งคือการใช้ผู้ประเมิน 5 ใบในแต่ละมือและเลือกที่ดีที่สุด
Adam

@ Byte56 ถูกต้องฉันจำได้ว่าฉันเคยใช้กับการ์ด 7 ใบ แต่ต้องพิจารณาไพ่ 5 ใบที่ดีที่สุดก่อนซึ่งชนิดของการทำลายประสิทธิภาพ
petervaz

ลิงก์ในคำตอบนี้ได้รับการเนรเทศและโดเมนที่สแปมเมอร์หยิบขึ้นมา ฉันได้เปลี่ยนเส้นทางลิงก์ไปยังที่เก็บถาวรของหน้าต้นฉบับ แต่เพื่อให้คำตอบนี้มีประสิทธิภาพยิ่งขึ้นมันจะเหมาะอย่างยิ่งที่จะแก้ไขคำตอบเพื่อรวมบทสรุปของอัลกอริทึมที่เสนอมาภายในเนื้อหาของคำตอบนั้นเอง
DMGregory

2

เพื่อเสริมคำตอบที่ยอดเยี่ยมคำถามนี้ได้รับไปแล้วฉันคิดว่ามันจะเป็นประโยชน์ที่จะนำเสนอหนึ่งในวิธีที่ตรงไปตรงมาที่สุดในการเปรียบเทียบมือเมื่อใช้เทคนิคการจำแนกขั้นพื้นฐานในสถานที่ ก่อนอื่นคุณจะต้องติดแท็กมือกับชั้นเรียนของพวกเขาตามที่ได้รับคำตอบมากมาย - การเปรียบเทียบส่วนใหญ่ของคุณคือ 'hand X ดีกว่า hand Y?' สามารถทำได้เพียงแค่เปรียบเทียบชั้นสองมือและดูว่าชั้นไหนดีกว่า สำหรับส่วนที่เหลือคุณจะต้องทำการเปรียบเทียบแบบการ์ดต่อใบและมันกลับกลายเป็นว่าการจำแนกประเภทมากขึ้นจะทำให้เรื่องนี้ง่ายขึ้น

เป็นกรณีพื้นฐานพิจารณาสถานการณ์ที่มือทั้งสองข้างเป็นไพ่ 'ไพ่สูง' ในกรณีนี้คุณจะเปรียบเทียบไพ่สูงสุดสองใบก่อนจากนั้น (ถ้าจับคู่) ไพ่สองใบถัดไปเป็นต้นหากคุณสมมติว่าแต่ละมืออินพุตถูกจัดเรียงจากไพ่สูงสุดถึงต่ำสุดวิธีนี้จะนำไปสู่รหัสที่ดูเหมือน นี้:

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

ตอนนี้ข่าวดี: ปรากฎว่าการเรียงลำดับพจนานุกรม , tweaked เหมาะสมทำงานเพื่อเปรียบเทียบสองมือในใด ๆของคลาสตราบใดที่คลาสของพวกเขาเหมือนกัน ตัวอย่างเช่นเนื่องจากวิธีการเปรียบเทียบคู่คือการเปรียบเทียบคู่ก่อนจากนั้นอีกสามใบคุณสามารถจัดเรียงมือของคุณให้วางคู่ก่อน (หรือแม้แต่ไพ่หนึ่งคู่ก่อน!) และทำการเปรียบเทียบแบบเดียวกันนี้ (เช่นเช่นมือ A9772 จะถูกเก็บไว้เป็น 77A92 หรือดีกว่า, 7A927; มือ A9972 จะถูกเก็บไว้เป็น 9A729 และเปรียบเทียบกับรหัสข้างต้นที่คุณเริ่มโดยการกด 7 ต่อ 9 และพบว่า A9972 วอน) มือของทั้งสองคู่จะถูกเก็บไว้กับที่สูงกว่าของสองคู่แรกจากนั้นต่ำกว่าจากนั้น 'เตะ' (ดังนั้นเช่น A9977 จะเก็บเป็น 97A97); ไพ่สามใบจะถูกเก็บไว้ในการ์ดหนึ่งใบจากไพ่สามใบแรกจากนั้นไพ่ที่ถูกเตะจากนั้นไพ่อีกใบหนึ่ง (เช่น A7772 จะเป็น 7A277) บ้านเต็มจะถูกเก็บไว้กับหนึ่งในสามของมันแล้วหนึ่งในสองของมัน (เช่น 99777 จะถูกเก็บไว้เป็น 79779); และ straights and flushes สามารถถูกจัดเก็บไว้ในคำสั่ง 'lexicographical โดยตรง' เนื่องจากทั้งคู่เปรียบเหมือนมือที่มีไพ่สูง สิ่งนี้นำไปสู่ฟังก์ชั่นตัวเปรียบเทียบภายนอกที่ไม่ซับซ้อนซึ่งใช้งานได้กับมือทุกระดับด้วยฟังก์ชั่นที่กำหนดไว้แล้ว:

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

หวังว่านี่จะช่วยได้บ้าง!


1

มีความเป็นไปได้ที่จะใช้การแทนการ์ดที่เหมาะสมและการขนานสองบิต ตัวอย่างเช่นโค้ด Java นี้จะประเมิน hards 7 การ์ดที่คืนค่าจำนวนเต็มซึ่งสามารถใช้สำหรับการเปรียบเทียบสองมือ สามารถปรับให้รายงานประเภทของมือได้ง่ายขึ้น แนวคิดหลักมาจากหน้าของ Cactus Kev อ้างอิงในคำตอบก่อนหน้า

หากคุณสนใจที่จะติดตั้งใช้งานที่เป็นไปได้สำหรับการตั้งชื่อมือในภาษาต่างๆมากกว่าประสิทธิภาพและความชัดเจนของรหัสคุณสามารถดูการตั้งชื่อการแข่งขันโป๊กเกอร์มือ บน codegolf.SE


1

ก่อนอื่นคุณต้องรู้อันดับและความเหมาะสมของไพ่ทั้งหมด เล็กน้อย แต่จำเป็น

จากนั้นหมุนการ์ดทั้ง 7 ใบแล้วสร้างฮิสโตแกรมสองภาพ ทีละอันดับ (ใช้อาเรย์ที่มีดัชนี 13 ตัวเริ่มต้นทั้งหมดให้เป็นศูนย์และเพิ่มขึ้น 1 ถ้าและเมื่อการ์ดในมือที่มีอันดับนั้นพบ) และอีกหนึ่งชุด . เหล่านี้เป็นการดำเนินการเชิงเส้นและคุณสามารถดำเนินการทั้งสองสำหรับแต่ละการ์ดสำหรับการสำรวจเส้นทางเดียวเท่านั้น

จากนั้นคุณสามารถกำหนดได้ว่ามีมือใดต่อไปนี้อยู่โดยเพียงแค่ตรวจสอบแต่ละฮิสโตแกรมเพื่อหาที่ตรงกับเกณฑ์และ / หรือการทดสอบติดตามอย่างง่าย:

  • การจับคู่: ที่ฝากข้อมูลอันดับหนึ่งมีค่าเป็น 2 หรือไม่และไม่มีที่เก็บข้อมูลอื่นที่มีค่าสูงกว่า 1 และไม่มีการล้างข้อมูลหรือไม่
  • สองคู่: ถังที่มีอันดับสองหรือมากกว่านั้นมีค่าเท่ากับ 2 โดยที่ที่ฝากข้อมูลไม่มีมากกว่า 2 และไม่มีฟลัชหรือไม่ (เห็นได้ชัดว่าสามคู่ไม่ใช่มือ แต่เป็นไปได้ที่ได้รับไพ่เจ็ดใบสองคู่ที่แข็งแกร่งที่สุดคือมือของผู้เล่น)
  • TOAK: ที่ฝากข้อมูลหนึ่งชุดมีค่าเท่ากับ 3 อย่างแน่นอนโดยที่ที่ฝากข้อมูลอื่น ๆ มีค่ามากกว่า 1 และไม่มีการล้างข้อมูลหรือไม่
  • ตรง: ถังที่อยู่ติดกันห้าลำดับมีค่า 1 หรือมากกว่าโดยไม่มีการฟลัชหรือไม่? (อย่าลืมว่าเอซมีทั้งสูงและต่ำคุณสามารถใช้ฮิสโตแกรมอันดับที่ 14 องค์ประกอบและนับเอซในสองถังถ้าคุณต้องการ)
  • ล้างข้อมูล: ชุดไพ่ใด ๆมีไพ่ 5 ใบหรือมากกว่า? (หากเป็นเช่นนั้นให้สแกนมือเพื่อหาไพ่ชุดนั้นและเลือก 5 อันดับแรก)
  • ฟูลเฮาส์: ที่ใดก็ตามที่บุ๊กกิ้งอันดับหนึ่งมีค่าเป็น 3 และที่เก็บอื่น ๆ มีค่าเป็น 2 (ด้วยไพ่ 7 ใบการล้างเป็นไปไม่ได้กับเฮ้าส์เต็มยกเว้นว่าคุณกำลังเล่นกับดาดฟ้า Pinochle)
  • สี่ชนิด: อันดับใดมีค่า 4 หรือไม่ (ไม่ควรรวมกันอื่น ๆ )
  • Straight Flush: มีทั้งแบบตรงและแบบฟลัชระบุโดยฮิสโทแกรมหรือไม่? ถ้าเป็นเช่นนั้นมีการ์ดอย่างน้อยหนึ่งใบในชุดสูทที่ระบุพร้อมกับอันดับที่ตรงกับลำดับของชุดที่ระบุไว้หรือไม่ (นี่อาจเป็นค่าใช้จ่ายที่คำนวณได้สูงที่สุด แต่ควรนับง่ายๆว่ามีการจัดลำดับติดต่อกันกี่ครั้งและคุณควรสแกนมือครั้งเดียวสำหรับ 5 อันดับที่น่าพอใจสองครั้งสำหรับ 6 และสามครั้งสำหรับ 7)

คุณสามารถรวมเช็คเหล่านี้เข้าด้วยกัน:

  • มีเปี่ยมหรือไม่
  • ตรงหรือไม่
    • หากมีทั้งคู่มันจะเป็นตรงหรือไม่
    • ถ้ามันตรงไปตรงมามันมีทั้งเอซและราชาหรือไม่?
  • มีสี่ชนิดหรือไม่?
  • มีสามแบบมีกี่แบบ? (สองมันเป็นบ้านเต็มหนึ่งตรวจสอบคู่)
  • มีกี่คู่ (ด้วยสองคนขึ้นไปมันเป็นสองคู่กับหนึ่งถ้ามีสามก็เป็นบ้านเต็มมิฉะนั้นจะเป็นคู่)
  • ไม่มีการข้างต้น (การ์ดสูง)

โดยทั่วไปหากคำตอบของสิ่งเหล่านี้ให้มือใด ๆ ให้ตั้งค่า "ความแข็งแกร่งของมือ" ที่ได้เป็นค่าความแข็งแรงของมือที่พบถ้าค่านั้นไม่ได้สูงขึ้น ตัวอย่างเช่นถ้าคุณมีบ้านเต็มกำลัง 7 จาก 9 คุณก็มีสามชนิดคือพลัง 4 และคู่กำลัง 2

มีทางลัดและการออกอย่างรวดเร็วเล็กน้อย แต่โดยรวมแล้วมันไม่แพงเลยที่จะเรียกใช้เช็คทั้งหมด


0

คุณสามารถทำมือโป๊กเกอร์ค่อนข้างง่ายด้วยวิธีการทำซ้ำง่าย ๆ

สำหรับแต่ละการ์ดตรวจสอบว่ามีหนึ่งหรือสองหรือสามคนที่มีใบหน้าเดียวกันเพื่อตรวจสอบคู่หรือสาม / สี่ชนิด

บ้านเต็มคล้ายกัน หรือหากคุณพบทั้งคู่และสามอย่างที่ไม่ใช่ใบหน้าเดียวกันให้ปักธงบ้านแบบเต็มตามที่พบ

สำหรับฟลัชให้ตรวจสอบชุดสูทแต่ละชุดเพื่อดูว่ามีชุดสูทห้าชุดหรือไม่

การตรวจสอบตรงเป็นเรื่องง่ายแม้ว่าจะไม่ได้เรียงลำดับ สำหรับแต่ละการ์ดตรวจสอบว่ามีหนึ่งสูงกว่าและทำซ้ำจนกว่าจะพบไพ่ห้าใบติดต่อกันหรือไม่

รอยัลฟลัชและฟลัชแบบตรงสามารถพบได้ในลักษณะเดียวกันกับ straights Royal flushes มีเงื่อนไขพิเศษบางประการที่สามารถเพิกเฉยต่อบัตรราคาต่ำ

ใช่วิธีนี้ไม่มีประสิทธิภาพ แต่สำหรับเกมโป๊กเกอร์ส่วนใหญ่ที่ไม่เกี่ยวข้อง คุณกำลังตรวจสอบผู้เล่นเพียงไม่กี่คนทุกครึ่งนาทีหรือมากกว่านั้นโดยไม่ตรวจสอบมือนับพันต่อวินาที

มีวิธีการที่ดีกว่า แต่อาจใช้เวลาในการเขียนโค้ดนานกว่าและคุณอาจมีสิ่งที่สำคัญกว่าในการใช้เวลา / เงินในการทำเกมที่ดีขึ้นจากมุมมองของผู้เล่นนอกเหนือจากความฉลาดและประสิทธิภาพของอัลกอริธึม


0

วิธีง่ายๆในการหาคู่, คู่, toaks, บ้านเต็ม, pokers ฯลฯ คือต่อไปนี้:

เปรียบเทียบแต่ละการ์ดกับแต่ละอื่น ๆ ในวงซ้อนกันเช่นนี้

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

การแข่งขันจะมีดังต่อไปนี้:
2 สำหรับคู่
4 สำหรับสองคู่
6 สำหรับ toak
8 สำหรับฟูลเฮาส์
12 สำหรับโป๊กเกอร์

เพื่อเพิ่มประสิทธิภาพความเร็วนี้: ไม่จำเป็นต้องเรียกใช้ j-loop มากถึง 5 ก็สามารถเรียกใช้ i-1 ได้ การเปรียบเทียบ "i! = j" นั้นจะสามารถลบออกได้ค่าสำหรับการแข่งขันจะลดลงครึ่งหนึ่ง (1 = คู่, 2 = 2 คู่เป็นต้น)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.