鱼C论坛

 找回密码
 立即注册
查看: 2964|回复: 6

题目54:在扑克游戏中玩家1能赢多少局?

[复制链接]
发表于 2015-6-12 22:55:45 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x

Poker hands

In the card game poker, a hand consists of five cards and are ranked, from lowest to highest, in the following way:

  • High Card: Highest value card.
  • One Pair: Two cards of the same value.
  • Two Pairs: Two different pairs.
  • Three of a Kind: Three cards of the same value.
  • Straight: All cards are consecutive values.
  • Flush: All cards of the same suit.
  • Full House: Three of a kind and a pair.
  • Four of a Kind: Four cards of the same value.
  • Straight Flush: All cards are consecutive values of same suit.
  • Royal Flush: Ten, Jack, Queen, King, Ace, in same suit.

The cards are valued in the order:
2, 3, 4, 5, 6, 7, 8, 9, 10, Jack, Queen, King, Ace.

If two players have the same ranked hands then the rank made up of the highest value wins; for example, a pair of eights beats a pair of fives (see example 1 below). But if two ranks tie, for example, both players have a pair of queens, then highest cards in each hand are compared (see example 4 below); if the highest cards tie then the next highest cards are compared, and so on.

Consider the following five hands dealt to two players:

QQ20150612-5@2x.png

The file, poker.txt, contains one-thousand random hands dealt to two players. Each line of the file contains ten cards (separated by a single space): the first five are Player 1's cards and the last five are Player 2's cards. You can assume that all hands are valid (no invalid characters or repeated cards), each player's hand is in no specific order, and in each hand there is a clear winner.

How many hands does Player 1 win?

题目:

在扑克游戏中,一局牌由五张牌组成,组成的牌的大小由低向高如下:

  • High Card: 最高值的牌.
  • One Pair: 两张面值一样的牌.
  • Two Pairs: 两个值不同的One Pair.
  • Three of a Kind: 三张面值一样的牌.
  • Straight: 所有的牌面值为连续数值.
  • Flush: 所有的牌花色相同.
  • Full House: Three of a Kind 加一个One Pair.
  • Four of a Kind: 四张牌面值相同.
  • Straight Flush: 所有的牌花色相同并且为连续数值.
  • Royal Flush: 10,J,Q,K和A,并且为相同花色。

牌的面值大小排序如下:
2, 3, 4, 5, 6, 7, 8, 9, 10, Jack, Queen, King, Ace.

如果两个玩家的牌具有同样的排序(上面介绍的几种),那么他们牌的大小由手中最大的牌决定。例如,一对 8 比一对 5 大(见下面例一);但是如果两个玩家都用一对 Q,那么他们手中最大的牌就用来比较大小(见下面例四);如果他们最高面值的牌也相等,那么就用次高面值的牌比较,以此类推。

考虑下面的几个例子:

QQ20150612-6@2x.png

文件 p054_poker.txt (29.3 KB, 下载次数: 35) 包含一千局随机牌。每一行包含十张牌(用空格分隔);前五张是玩家 1 的牌,后五张是玩家 2 的牌。 所有的牌都是合理的(没有非法字符或者重复的牌)。每个玩家的牌没有顺序,并且每一局都有明确的输赢。

其中玩家 1 能赢多少局?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2016-10-14 16:32:33 | 显示全部楼层
这题不是难,是很烦,要考虑很多种情况,写不同条件.
帖子长度关系,省略牌组数据,可以自行粘贴。
376
[Finished in 0.2s]
pokerdata = ['8C','TS','KC','9H','4S','7D','2S','5D','3S','AC','5C','AD','5D','AC','9C','7C','5H','8D','TD','KS','3H','7H','6S','KC','JS','QH','TD','JC','2D','8S','TH','8H',
######################
######################
###~~~省略牌组数据~~~###
######################
######################
'2D','JS','QD','AC','9C','JD','7C','6D','TC','6H','6C','JC','3D','3S','QC','KC','3S','JC','KD','2C','8D','AH','QS','TS','AS','KD','3D','JD','8H','7C','8C','5C','QD','6C']

def evalHand(hand):
    values = ['2','3','4','5','6','7','8','9','T','J','Q','K','A']

    flush = 1
    suit = hand[0][1]
    for card in hand:
        if card[1] <> suit:
            flush = 0
            break

    indices = []
    royal = 1
    straight = 1
    for card in hand:
        indices.append(values.index(card[0]))
    indices.sort()
    if indices[4] - indices[0] <> 4 \
       or indices.count(indices[0]) > 1 \
       or indices.count(indices[1]) > 1 \
       or indices.count(indices[2]) > 1 \
       or indices.count(indices[3]) > 1 \
       or indices.count(indices[4]) > 1:
        straight = 0
    if indices[0] <> 8:
        royal = 0

    kinds = []
    for value in indices:
        count = indices.count(value)
        if count > 1:
            kind = [value, count]
            if kind not in kinds:
                kinds.append(kind)

    if royal and flush:
#        return "royal flush"
        return [9, 0]
    if straight and flush:
#        return "straight flush"
        return [8, indices[4]]
    if len(kinds) == 1 and kinds[0][1] == 4:
#        return "four of a kind"
        return [7, kinds[0][0]]
    if len(kinds) == 2 and (kinds[0][1] + kinds[1][1] == 5):
#        return "full house"
        return [6, kinds[0][0]]
    if flush:
#        return "flush"
        return [5, indices[4]]
    if straight:
#        return "straight"
        return [4, indices[4]]
    if len(kinds) == 1 and kinds[0][1] == 3:
#        return "three of a kind"
        return [3, kinds[0][0]]
    if len(kinds) == 2 and (kinds[0][1] + kinds[1][1] == 4):
#        return "two pair"
        return [2, max(kinds[0][0], kinds[1][0])]
    if len(kinds) == 1 and kinds[0][1] == 2:
#        return "one pair"
        return [1, kinds[0][0]]
#    return "high card"
    return [0, max(indices)]

rounds = []
for rd in range(1000):
    rounds.append(pokerdata[rd*10:rd*10+10])

count = 0
for r in rounds:
    p1 = evalHand(r[0:5])
    p2 = evalHand(r[5:10])
    if p1[0] > p2[0] or (p1[0] == p2[0] and p1[1] > p2[1]):
        count = count + 1

print count
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-6-25 13:19:15 | 显示全部楼层
本帖最后由 王小召 于 2019-6-25 13:25 编辑

总共进行了: 1000 次比赛
P1赢了: 379 次!
P2赢了: 621 次!
用时:0.156001 秒
import re
import time

# 计算手牌属于哪种组合以及特征值
def cal_max(cards):
    color = [_ for _ in filter(None, re.split('[\dTJQKA ]', cards)[1:])]
    value = [_ for _ in filter(None, re.split('[CDHS ]', cards)[:-1])]

    for i in range(5):
        if value[i] == 'T':
            value[i] = 10
        elif value[i] == 'J':
            value[i] = 11
        elif value[i] == 'Q':
            value[i] = 12
        elif value[i] == 'K':
            value[i] = 13
        elif value[i] == 'A':
            value[i] = 14
        else:
            value[i] = int(value[i])
    value.sort()
    if len(set(color)) == 1:
        # # Case 9: 同花顺
        if len(set([int(value[i]) - int(value[i-1]) for i in range(1, 5)])) == 1:
            return [9, value]
        else:
            # Case 6: 同花
            return [6, value]
    else:
        single_values = []
        single_counts = []
        for each_value in set(value):
            single_values.append(each_value)
            single_counts.append(value.count(each_value))

        # Case 8: 炸弹
        if 4 in single_counts:
            return [8, single_values[single_counts.index(4)]]

        # Case 7: 三条加一对
        elif 3 in single_counts and 2 in single_counts:
            return [7, single_values[single_counts.index(3)]]

        # Case 4: 三条
        elif 3 in single_counts:
            return [4, single_values[single_counts.index(3)]]

        # Case 3: 两个对子
        elif 2 in single_counts and single_counts.count(2) == 2:
            tmp = []
            for i in range(len(single_counts)):
                if single_counts[i] == 2:
                    tmp.append(single_values[i])
            tmp.sort()
            return [3, tmp, single_values[single_counts.index(1)]]

        # Case 2: 单个对子
        elif 2 in single_counts:
            max_value = single_values[single_counts.index(2)]
            single_values.remove(max_value)
            single_values.sort()
            return [2, max_value, single_values]

        # Case 5: 顺子
        elif len(set([int(value[i]) - int(value[i-1]) for i in range(1, 5)])) == 1:
            return [5, max(value)]

        # Case 1: 单牌
        else:
            return [1, value]


with open(r'C:\Users\wangyongzhao\Desktop\p054_poker.txt') as f:
    cases = f.readlines()
    total_games = len(cases)  # 总胜场计数
    count1 = 0  # p1 胜场计数
    count2 = 0  # p2 胜场计数
    for each in cases:
            p1 = cal_max(each.strip()[:14])
            p2 = cal_max(each.strip()[15:])
            if p1[0] > p2[0]:
                count1 += 1
            elif p1[0] < p2[0]:
                count2 += 1
            else:
                # 都是对子或者都是顺子,从第一结果看平局了, 分情况讨论
                # 第一种情况,都是单牌(从大到小逆序挨个作比较,有不同值就产生结果)
                if p1[0] == 1:
                    for i in range(4, -1, -1):
                        if p1[1][i] < p2[1][i]:
                            count2 += 1
                            break
                        elif p1[1][i] > p2[1][i]:
                            count1 += 1
                            break
                # 第二种情况,都有对子(实际9个case都要分类讨论,但是file里只涉及这两种!)
                elif p1[0] == 2:
                    if p1[1] > p2[1]:
                        count1 += 1
                    elif p1[1] < p2[1]:
                        count2 += 1
                    else:
                        for i in range(2, -1, -1):
                            if p1[2][i] < p2[2][i]:
                                count2 += 1
                                break
                            elif p1[2][i] > p2[2][i]:
                                count1 += 1
                                break
                else:
                    print("未分类平局对决", p1, "《--》", p2)
print("总共进行了: {} 次比赛\nP1赢了: {} 次!\nP2赢了: {} 次!\n用时:{} 秒".format(total_games, count1, count2, time.process_time()))
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-11-21 09:33:37 | 显示全部楼层
vm = {'T' : 10, 'J' : 11, 'Q' : 12, 'K' : 13, 'A' : 14}
for i in range(2, 10):
  vm[str(i)] = i
sm = {'C' : 0, 'D' : 1, 'S' : 2, 'H' : 3}
def fun(x):
  v = [0] * 15
  s = [0] * 4
  for i in x:
    v[vm[i[0]]] += 1
    s[sm[i[1]]] += 1
  r = [0] * 9
  r[8] = max(map(lambda x: x[0] if x[1] != 0 else 0, enumerate(v)))
  r[7] = max(map(lambda x: x[0] if x[1] == 2 else 0, enumerate(v)))
  r[6] = r[7] if len(list(filter(lambda x: x == 2, v))) == 2 else 0
  r[5] = max(map(lambda x: x[0] if x[1] == 3 else 0, enumerate(v)))
  tmp = list(map(lambda x: 1 if x != 0 else 0, v))
  r[4] = max(map(lambda x: x[0] if x[1] == 5 else 0,
                 enumerate(map(lambda x: sum(tmp[x-5:x]), range(5, 15)), start = 1)))
  r[3] = r[8] if len(list(filter(lambda x: x == 5, s))) == 1 else 0
  r[2] = r[5] if r[5] != 0 and r[7] != 0 else 0
  r[1] = max(map(lambda x: x[0] if x[1] == 4 else 0, enumerate(v)))
  r[0] = r[4] if r[4] != 0 and r[3] != 0 else 0
  return r 

f = open('54.txt', 'r')
hand = list(map(lambda x: x.split(), filter(lambda x: len(x) != 0, f.read().split('\n'))))
print(len(list(filter(lambda x: fun(x[:5]) > fun(x[5:]), hand))))
https://github.com/devinizz/project_euler/blob/master/page02/54.py
持续更新中...
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-8-26 16:55:48 | 显示全部楼层
376

Process returned 0 (0x0)   execution time : 0.058 s
Press any key to continue.
十分赞同2#的看法……本题思维难度不大,但极为复杂,情况众多,很容易犯错
我想我的代码或许可以再优化些……
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<string>
#include<cctype>
#include<map>
using namespace std;

const int M = 1000;
const string royal("TJQKA");
const string STRAIGHT("A23456789TJQKA");
string value[2],suit[2];
bool cmp(char i,char j);

int posi(char x){
  for (int i = 0;i < 5;i++)
    if (x == royal[i])  return i;
}

void erase_char(char c,string & s){
  do{
    s.erase(find(s.begin(),s.end(),c) );
  }while(find(s.begin(),s.end(),c) != s.end() );
}

bool p1win(const string & s1,const string & s2){
  for (int i = s1.length() - 1; i >= 0;i--){
    if (s1[i] == s2[i]) continue;
    if (!cmp(s1[i],s2[i]) )  return true;
    if (cmp(s1[i],s2[i]) )  return false;
  }
}

char dom(int p){
  map<char,int> times;  char domin;
  int mx = 0;

  for (int i = 0;i < value[p].length();i++){
    char t = value[p][i];

    if (!times.count(t) )  times[t] = 1;
    else times[t]++;
  }
  for (map<char,int>::iterator it = times.begin();it != times.end();++it)
    if (it->second > mx)  {mx = it->second; domin = it->first;}

  return domin;
}

bool cmp(char i,char j){
  if (isdigit(i) && isdigit(j)) return i < j;

  if (isdigit(i) && isalpha(j)) return true;
  if (isdigit(j) && isalpha(i)) return false;

  return posi(i) < posi(j);
}

bool is_straight(string & s){
  sort(s.begin(),s.end(),cmp);

  for (int i = 0;i < 10;i++)
    if (s == STRAIGHT.substr(i,5)) return true;

  return false;
}

bool isflush(string s){
  for (int i = 0;i < s.length() - 1;i++)
    if (s[i+1] != s[i]) return false;

  return true;
}

int others(string s){
  map<char,int> times;

  for (int i = 0;i < s.length();i++){
    char t = s[i];

    if (!times.count(t) )  times[t] = 1;
    else times[t]++;
  }
  int sz = times.size();
  if (sz == 5)  return 0;
  if (sz == 4)  return 1;
  if (sz == 2)  {
    for (map<char,int>::iterator it = times.begin();it != times.end();++it){
      if (it->second == 4)  return 7;
      if (it->second == 3)  return 6;
    }
  }
  if (sz == 3)  {
    for (map<char,int>::iterator it = times.begin();it != times.end();++it){
      if (it->second == 2)  return 2;
      if (it->second == 3)  return 3;
    }
  }
  return -1;//error
}

int judge_type(int p){
  bool f = isflush(suit[p]);
  bool st = is_straight(value[p]);

  if (f && st)  return 8;
  if (!f && st) return 4;
  if (f && !st) return 5;

  return others(value[p]);

  return -1;//error
}
/*  0:High Card         1:One Pair  2:Two Pairs
    3:Three of a Kind   4:Straight  5:Flush
    6:Full House        7:Four of a Kind
    8:Straight Flush
*/
void print(){
  cout << value[0] << " " << value[1] << endl;
  cout << suit[0] << " " << suit[1] << endl << endl;
}

void ini(){
  for (int i = 0;i < 2;i++){
    value[i].clear();
    suit[i].clear();
  }
}

int main(){
  freopen("i.in","r",stdin);
  int cnt = 0;

  for (int r = 0;r < M;r++){
    ini();

    for (int i = 0;i < 2;i++){
      for (int j = 0;j < 5;j++){
        string s;
        cin >> s;
        value[i].push_back(s[0]);
        suit[i].push_back(s[1]);
      }
    }
    //print();

    int p1 = judge_type(0),p2 = judge_type(1);//此后,点数序列有序
    //cout << p1 << " " << p2 << endl;  cout << value[0] << " " << value[1] << endl;

    if (p1 > p2) {cnt++;  continue;}
    if (p1 == p2){
      switch(p1){
        case 0:
        case 5: if (p1win(value[0],value[1]) )  cnt++;
                break;

        case 4:
        case 8: if (cmp(value[1][4],value[0][4]) )  cnt++;
                break;

        case 1:
        case 3: {
          char c1 = dom(0),c2 = dom(1);
          if (c1 == c2) {
            string s1 = value[0],s2 = value[1];
            erase_char(c1,s1);  sort(s1.begin(),s1.end(),cmp);
            erase_char(c2,s2);  sort(s2.begin(),s2.end(),cmp);

            if (p1win(s1,s2)) {cnt++; break;}
          }
          if (cmp(c2,c1) )   cnt++;
          break;

        }
        case 6:
        case 7: {
          char c1 = dom(0),c2 = dom(1);
            if (c1 == c2){
              char d1,d2;
              for (int i = 0;i < 5;i++){
                if (value[0][i] != c1) {d1 = value[0][i]; break;}
                if (value[1][i] != c2) {d2 = value[1][i]; break;}
              }
              if (cmp(d2,d1) )  {cnt++; break;}
            }
            if (cmp(c2,c1) )   cnt++;
            break;

        }
        case 2: map<char,int> times[2];
                string mypair[2];
                char d[2];
                for (int i = 0;i < 2;i++){
                  for (int j = 0;j < 5;j++){
                    char t = value[i][j];

                    if (!times[i].count(t) )  times[i][t] = 1;
                    else times[i][t]++;

                    if (times[i][t] == 2)  mypair[i].push_back(t);
                  }
                  for (map<char,int>::iterator it = times[i].begin();it != times[i].end();++it)
                    if (it->second = 1)   {d[i] = it->first;  break;}

                  sort(mypair[i].begin(),mypair[i].end(),cmp);
                }
                if (cmp(mypair[1][3],mypair[0][3]) )  {cnt++; break;}
                else if (mypair[1][3] == mypair[0][3]){
                  if (cmp(mypair[1][0],mypair[0][0]) )  {cnt++; break;}
                  else if(mypair[1][0] == mypair[0][0]){
                    if (cmp(d[1],d[0]) )  {cnt++; break;}
                  }
                }
      }
    }
  }
  cout << cnt << endl;
  return 0;
}
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-2-8 10:28:37 From FishC Mobile | 显示全部楼层
实 际 开 发 实 况
我连题目都看不懂
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-10-25 17:16:31 | 显示全部楼层
import time as t
import numpy as np

start = t.perf_counter()


def evaluate_cards(suits, values):
    # Scores. Pair: 3; Three of a kind: 7; Straight: 8; Flush: 9; Four of a Kind: 11; Royal Flush: 18
    cards_value = 0
    set_values = set(values)
    is_straight = True
    if len(set(suits)) == 1:
        cards_value += 9
        if set_values == (8, 9, 10, 11, 12):
            cards_value += 9

    for value in range(4):
        if not (values[value + 1] - values[value] == 1):
            is_straight = False
    if is_straight:
        cards_value += 8

    dict_cards = {value: values.count(value) for value in values}
    pair_count, three_count, four_count = 0, 0, 0
    for value in dict_cards:
        if dict_cards[value] == 2:
            pair_count += 1
        elif dict_cards[value] == 3:
            three_count += 1
        elif dict_cards[value] == 4:
            four_count += 1
    cards_value += (pair_count * 3 + three_count * 7 + four_count * 11)

    return cards_value, dict_cards


def compare_cards(cards_list_1, cards_list_2):
    cards_order = ['2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A']
    values_1, suits_1, values_2, suits_2 = [], [], [], []
    for card in range(5):
        values_1.append(cards_order.index(cards_list_1[card][0]))
        suits_1.append(cards_list_1[card][1])
        values_2.append(cards_order.index(cards_list_2[card][0]))
        suits_2.append(cards_list_2[card][1])
    values_1.sort()
    values_2.sort()
    cards_value_1, cards_dict_1 = evaluate_cards(suits_1, values_1)
    cards_value_2, cards_dict_2 = evaluate_cards(suits_2, values_2)
    if cards_value_1 > cards_value_2:
        return True
    elif cards_value_1 < cards_value_2:
        return False
    elif cards_value_1 == 17 or cards_value_1 == 9 or cards_value_1 == 8 or cards_value_1 == 0:
        for max_value in range(-1, -6, -1):
            if values_1[max_value] > values_2[max_value]:
                return True
            elif values_1[max_value] < values_2[max_value]:
                return False
    elif cards_value_1 == 3 or cards_value_1 == 6 or cards_value_1 == 7 or cards_value_1 == 10 or cards_value_1 == 11:
        while True:
            if max(cards_dict_1.values()) > 1:
                max_value_1 = max(cards_dict_1, key=lambda x: cards_dict_1[x])
                max_value_2 = max(cards_dict_2, key=lambda x: cards_dict_2[x])
            else:
                max_value_1 = max(cards_dict_1)
                max_value_2 = max(cards_dict_2)
            if max_value_1 > max_value_2:
                return True
            elif max_value_1 < max_value_2:
                return False
            else:
                cards_dict_1[max_value_1] = 0
                cards_dict_2[max_value_2] = 0


hands = np.loadtxt('C:/Users/wuhw/Desktop/p054_poker.txt', dtype=str)
count_1_win = 0
for all_cards in hands:
    cards_list = list(all_cards)
    res = compare_cards(cards_list[:5], cards_list[5:])
    if res:
        count_1_win += 1

print(count_1_win)
print("It costs %f s" % (t.perf_counter() - start))

376
It costs 0.038529 s
浪费一个小时做这个破题,我真的是个傻逼
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-12-22 16:49

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表