포커 핸즈 결정


19

평가의 일환으로 Texas Hold'Em 게임을 만들고 있으며 사용 가능한 7 장의 카드를 조사하고 손이 있는지 확인하는 방법에 대해 고민하고 있습니다.

내가 생각할 수있는 유일한 방법은 카드를 숫자로 정렬 한 다음 가능한 모든 5 장의 카드 그룹을 검사하여 가능한 모든 손 목록과 일치하는지 확인하는 것입니다. 소송이 관련이 없기 때문에 snd는 쌍을 결정하는 데만 가능할 것입니다.

카드는 숫자 / a / j / q / k와 슈트 (char)3(작은 스페이드 기호로 구성) 로 구성된 각 줄 입니다.

누구나 수동 분석 시스템을 만드는 데 도움이되는 제안, 공식 또는 링크가 있습니까?

아직 서로 손을 랭킹하는 것에 대해 걱정하지 마십시오. 그것은 다른 주전자입니다.


1
그것을 지적하지만 컨텍스트의 벡터 태그는 선형 대수에 관한 것입니다. 컨테이너가 아닙니다.
Sidar

@Sidar 태그가 맞지 않다고 생각되면 언제든지 태그를 편집하십시오. 태그 위로 마우스를 가져 가면 "적어도 나에 대한?"태그가 표시되며 질문을 편집하지 않고 태그 만 편집 할 수 있습니다.
MichaelHouse

@ Byte56 나는이 옳은지 확실하지 않다고 생각하는 이상한 습관을 가지고있어서 수동적으로 주석을 통해 처리합니다 ... 그래서 게시물을 편집하지 않았습니다. 아마도 게시물에 뭔가를 놓쳤으므로 그의 응답을 기다리고있었습니다.
Sidar

몇 년 전에 게임 개발자에게 등장한 좋은 기사도 있습니다 : cowboyprogramming.com/2007/01/04/programming-poker-ai
celion

1
codereview.stackexchange.com/questions/10973/…에서 찾을 수 있습니다 . PokerHand.java를 보면 각 유형의 핸드를 테스트하는 메소드를 찾을 수 있습니다 (예 : isFullHouse). 카드가 먼저 정렬 된 경우에만 작동합니다.
bughi

답변:


20

각 순위와 수트에 몇 장의 카드가 있는지 몇 개의 테이블을 간단히 작성하여 포커 패의 대부분을 찾을 수 있다고 생각합니다.

다시 말해, 당신의 손에있는 그 카드의 수에 대한 배열 매핑 카드 순위 (숫자 및 A / J / Q / K)를 만드십시오. 플레이어가 짝을 이루거나 종류가 3 개인 경우,이 배열에는 2 또는 3과 같은 요소가 있습니다. 2의 요소 하나와 3의 요소가 있으면 풀 하우스가 있습니다. 이 배열에 1과 동일한 5 개의 연속 요소가있는 경우

마찬가지로 각 수트의 카드 수와 비슷한 배열을 만들어 플러시를 감지하는 데 사용할 수 있습니다.

특정 손의 존재를 감지하면 UI에서 또는 필요한 것을 강조하기 위해 손으로 특정 카드를 찾아서 쉽게 찾을 수 있습니다.

의사 코드에서 :

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 to King 카드 목록을 사용하여, 발견 된 각 추가 카드마다 증분하여 목록에 각 값의 번호를 입력하십시오. 그런 다음 4가없는 경우 목록을 확인하십시오 .4가 없으면 종류가 없습니다. 3이 없으면 3을 확인하십시오 .3이 없습니다. 3이 있으면 2를 확인하십시오 (풀 하우스를 나타냄). 등등...

의 경우 1, 5동일한 목록을 사용하고 모든 카드가 목록에서 5 개 이상의 카드에 대해 하나 이상의 항목을 갖는 시퀀스를 찾을 수 있습니다. 그들은 또한 같은 소송을 가지고 있다면, 그것은 곧장 플러시입니다.

4같은 목록 설정을 할 수 있지만 이번에는 정장을 세고 있습니다. 5 이상의 숫자를 찾으십시오.

마지막으로 9카드가 가장 높습니다. 위의 목록 중 하나에서 마지막으로 가장 높은 값을 보는 것이 간단합니다.

순서대로 검색하면 일치하는 것을 찾은 후에 나눌 수 있습니다. 모든 정보를 사용자에게 제공하려면 검색을 계속하고 모든 일치 항목을 찾는 것이 쉽지 않습니다.


기본적으로 버킷을 채우고 있습니다. 그런 다음 버킷의 조합을 확인하십시오. 설명하기 위해 :

여기에 이미지 설명을 입력하십시오

배열에서 시작하여 각 카드에 대한 버킷을 사용하여 카드를 반복하고 각 카드의 인스턴스를 계산합니다. 그런 다음 배열을 쉽게 반복하고 특정 조합을 확인할 수 있습니다. 이 예제에서는 버킷 중 하나에 4 개의 항목이 있기 때문에 4 가지 유형이 있음이 분명합니다.


6

나는이 알고리즘에 한 번 부딪쳤다. 소수를 곱하여 손을 결정하고 매우 흥미로운 독서입니다. Cactus Kev의 포커 핸드 평가 기


1
그 중 하나는 흥미롭지 만 모든 내용을 잘 모르겠습니다. 이 알고리즘은 5 장의 카드를 위한 것 입니다. 저자는 7 장의 카드에 대한 알고리즘이 있지만 공유하지는 않는다고 말하면서 7 장의 카드와 관련된 Google 검색에서 발견했을 수 있습니다. 페이지 상단 근처의 회색 텍스트를 참조하십시오. 따라서 알고리즘이 7 카드 세트에 얼마나 유용한 지 잘 모르겠습니다.
MichaelHouse

1
7 장의 카드로 만들 수있는 21 장의 5 장의 카드 핸드가 21 개이기 때문에 하나의 옵션은 각각 5 장의 카드 평가기를 사용하여 가장 좋은 것을 선택하는 것입니다.
Adam

@ Byte56 맞아요. 7 장의 카드를 사용했지만 미리 5 장의 카드를 결정해야했기 때문에 효율성을 떨어 뜨 렸습니다.
petervaz

이 답변의 링크는 썩었 고 도메인은 스패머에 의해 선택되었습니다. 링크를 원본 페이지의 아카이브로 리디렉션했지만이 답변을보다 강력하게 만들려면 답변 본문에 제안 된 알고리즘 요약을 포함하도록 답변을 편집하는 것이 이상적입니다.
DMGregory

2

이 질문에서 이미 얻은 훌륭한 답변을 보완하기 위해 기본 분류 기술을 사용하면 손을 비교하는 가장 간단한 방법 중 하나를 제공하는 것이 도움이 될 것이라고 생각했습니다. 우선 , 많은 답변이 제안한 것처럼 클래스에 손을 태그하고 싶을 것 입니다. '손 X보다 손 X가 더 낫습니까?' 두 손의 수업을 비교하고 어떤 수업이 더 나은지 확인하면됩니다. 나머지의 경우 실제로는 카드별로 비교해야하며 분류 작업이 조금 더 쉬워 질 것입니다.

기본 사례로 양손이 '높은 카드'손인 상황을 고려하십시오. 이 경우 가장 높은 두 개의 카드를 먼저 비교 한 후 다음 두 개의 카드 등을 (일치하는 경우) 비교합니다. 각 입력 핸드가 가장 높은 카드에서 가장 낮은 카드로 정렬되어 있다고 가정하면이 접근 방식은 다음과 같은 코드를 생성합니다. 이:

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

이제 좋은 소식 :이 사전 순서 는 적절하게 조정되어 어느 한 손에서 두 손을 비교하는 데 효과적 이라는 것이 밝혀졌습니다수업이 동일하다면 수업 중 예를 들어, 페어를 비교하는 방법은 페어를 먼저 비교 한 다음 다른 3 장의 카드를 비교하는 것이므로, 페어를 먼저 (또는 페어의 한 카드까지 먼저) 배치하기 위해 손을 정렬하고 동일한 비교를 실행할 수 있습니다. (예를 들어, A9772와 같은 손은 77A92 또는 더 나은 7A927로 저장됩니다. 손 A9972는 9A729로 저장되며 위의 코드와 비교하여 7을 9에 대입하여 시작합니다. A9972 원). 두 쌍의 손은 두 쌍 중 높은 쪽이 먼저, 그 다음 낮은 쪽이 '키커'로 저장됩니다 (예 : A9977은 97A97로 저장됩니다). 종류 중 3 개는 3 개 중 하나의 카드에 먼저 저장 한 다음 키커, 다른 카드에 저장합니다 (예 : A7772는 7A277입니다). 풀 하우스는 3 개 중 1 개와 2 개 중 하나가 저장됩니다 (예 : 99777은 79779로 저장 됨). 스트레이트와 플러시는 모두 높은 카드 핸드처럼 비교되기 때문에 '직접 렉시 그래픽'순서로 저장할 수 있습니다. 이것은 이미 주어진 기능으로 모든 클래스의 손에서 작동하는 간단한 외부 비교기 기능으로 이어집니다.

// 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 코드 두 손을 비교하는 데 사용할 수있는 정수를 반환하는 7 카드 하드를 평가 합니다. 손의 유형을보다 사용자 친화적 인 방식으로보고하도록 조정할 수 있습니다. 핵심 아이디어는 이전 답변에서 언급 한 Cactus Kev의 페이지에서 나옵니다.

효율성과 코드 명확성이 아니라 다양한 언어로 손의 이름을 지정할 수있는 구현에만 관심이있는 경우 codegolf.SE 에서 포커 핸드 챌린지 이름 지정 을 참조하십시오.


1

먼저 모든 카드의 순위와 수트를 알아야합니다. 사소하지만 필요합니다.

그런 다음이 7 장의 카드를 돌려 두 개의 히스토그램을 만듭니다. 순위 별 1 개 (13 개의 인덱스가있는 배열 사용, 해당 순위의 카드를 찾은 경우에는 0으로 초기화되고 1 씩 증가) 및 순위 별 (순위와 유사하게 구성된 4 개의 요소 배열 사용) . 이는 선형 작업이며 한 세트의 순회에 대해서만 각 카드에 대해 두 작업을 모두 수행 할 수 있습니다.

그런 다음 기준과 일치하는 버킷 및 / 또는 간단한 후속 테스트를 통해 각 히스토그램을 간단히 검사하여 다음 손이 있는지 확인할 수 있습니다.

  • 쌍 : 정확히 하나의 순위 버킷의 값이 정확히 2이고 다른 버킷의 값이 1보다 높고 플러시가 없습니까?
  • 두 쌍 : 둘 이상의 순위 버킷의 값이 정확히 2이고 버킷이 2보다 크거나 플러시가 없습니까? (분명히 3 쌍은 핸드가 아니지만 7 장의 카드가 주어질 가능성이 있습니다. 가장 강한 2 페어는 플레이어의 핸드입니다)
  • TOAK : 하나의 버킷에 정확히 3의 값이 있고 다른 버킷에 1보다 큰 값이 있고 플러시가 없습니까?
  • 스트레이트 : 연속 순위 버킷 5 개가 플러시없이 1 이상의 값을 가지고 있습니까? (에이스가 높고 낮다는 것을 잊지 마십시오. 원하는 경우 14 요소의 랭크 히스토그램을 사용하고 두 버킷에서 에이스를 계산할 수 있습니다)
  • 세척 : 어떤 있습니까 정장 버킷 5 개 이상의 카드를 가지고? (그렇다면 손에 해당 카드가 있는지 스캔하고 상단 5를 선택하십시오)
  • 풀 하우스 : 한 랭크 버킷의 가치가 3이고 다른 버킷의 가치가 2입니다 (7 장의 카드로 피노 클 데크로 플레이하지 않으면 풀 하우스로 플러시가 불가능합니다)
  • 4 가지 종류 : 한 등급의 가치가 4입니까? (다른 조합은 불가능합니다)
  • 스트레이트 플러시 : 히스토그램으로 표시된 스트레이트 플러시 가 모두 있습니까? 그렇다면, 지정된 플러시 슈트에 표시된 스트레이트의 각 등급과 일치하는 등급을 가진 카드가 하나 이상 있습니까? (이것은 아마도 계산 비용이 가장 비싸지 만 연속 순위가 몇 개인 지 계산하는 것이 간단해야하며 5 개의 계급 계급에 대해 한 번, 6 회에 대해 두 번, 7 회에 대해 세 번만 스캔해야합니다)

당연히 이러한 검사 중 몇 가지를 결합 할 수 있습니다.

  • 플러시가 있습니까?
  • 스트레이트가 있습니까?
    • 둘 다 있으면 스트레이트 플러시입니까?
    • 스트레이트 플러시라면 에이스와 킹이 있습니까?
  • 네 종류가 있습니까?
  • 3 가지 종류가 있습니까? (둘, 그것은 풀 하우스입니다. 하나, 쌍을 확인하십시오)
  • 몇 쌍이 있습니까? (두 개 이상이면 두 켤레입니다. 하나면 세 개가 있으면 풀 하우스입니다. 그렇지 않으면 페어입니다)
  • 위의 어느 것도 (높은 카드) 없습니다.

기본적으로 이러한 답변에 손이 나오면 결과 "손 강도"값을 찾은 손의 강도로 설정 하십시오 (값이 아직 높지 않은 경우). 예를 들어, 집 전체, 힘 7/9를 가지고 있다면, 힘 3, 힘 2, 힘 2의 3도 있습니다.

몇 가지 지름길과 단식이 있지만 전반적으로 모든 검사를 실행 하는 것이 그렇게 비싸지는 않습니다 .


0

간단한 반복 접근 방식으로 포커 패를 비교적 쉽게 수행 할 수 있습니다.

각 카드마다 같은 얼굴을 가진 한두 사람의 다른 사람이 있는지 확인하십시오.

풀 하우스는 비슷합니다. 또는 같은 얼굴이 아닌 한 종류와 세 종류를 모두 찾으면 찾은 집 전체를 신고하십시오.

플러시의 경우, 각 슈트를 점검하여 동일한 슈트 중 5 개가 있는지 확인하십시오.

정렬되지 않은 경우에도 똑바로 점검하는 것은 쉽습니다. 각 카드마다 하나 더 높은 카드가 있는지 확인하고 5 개의 연속 카드가 발견 될 때까지 반복하십시오.

로얄 플러시 및 스트레이트 플러시는 스트레이트와 유사하게 찾을 수 있습니다. 왕실 플러시에는 가치가 낮은 카드를 무시할 수있는 추가 조건이 있습니다.

예,이 방법은 비효율적이지만 대부분의 포커 게임에서는 관련이 없습니다. 당신은 초당 약 수천의 손을 확인하지 않고 30 분마다 작은 소수의 플레이어를 확인하고 있습니다.

더 나은 방법이 존재하지만 코딩하는 데 시간이 더 걸릴 수 있으며, 알고리즘의 영리함과 효율성 외에도 플레이어의 관점에서 더 나은 게임을 만들기 위해 시간 / 돈을 소비하는 데 더 중요한 것들이있을 것입니다.


0

페어, 더블 페어, 톡, 풀 하우스, 포커 등을 찾는 간단한 방법은 다음과 같습니다.

다음과 같이 중첩 루프에서 각 카드를 서로 비교하십시오.

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 쌍 2 개
6 toak
8 풀 하우스
12 포커

j-loop를 최대 5 개까지 실행할 필요가 없으며 i-1까지 실행할 수 있습니다. 그런 다음 비교 "i! = j"를 제거하고 일치 값을 절반으로 줄입니다 (1 = pair, 2 = 2pair 등).

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.