鱼C论坛

 找回密码
 立即注册
查看: 2633|回复: 11

[技术交流] 小练习:20170109 在扑克游戏中玩家1能赢多少局?

[复制链接]
发表于 2017-1-8 21:09:19 | 显示全部楼层 |阅读模式

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

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

x
本帖最后由 冬雪雪冬 于 2017-1-16 10:29 编辑

从现在开始我们要开展一批欧拉计划的习题练习。
其实在我们论坛中已有欧拉计划的板块,可能有些鱼油还没注意到。
什么是欧拉计划:http://bbs.fishc.com/thread-60405-1-1.html
我们欧拉板块现已给出了200余题,这批练习将从欧拉计划中选题。其实用python语言完成有很多的优势,可以更简洁更方便的实现。
如果大家有兴趣也可浏览欧拉的英文网站:https://projecteuler.net/archives
这里已经有了500余题。


                               
登录/注册后可看大图


题目要求:
以python语言完成,如果是python2请注明。
程序以代码文字格式发帖。
注重程序效率和创意。
答题在一周内完成,即1.16 10:00之前,其后将公开大家的答案,并评比成绩。

另程序和答案可以在网上搜到,希望大家独立完成。题目不难,大家看看谁的效率高。

----回帖需写明解题思路,鼓励在程序中加上注释-----
----除列出程序外,请给出输出的结果。----



题目:

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

  • 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,那么他们手中最大的牌就用来比较大小(见下面例四);如果他们最高面值的牌也相等,那么就用次高面值的牌比较,以此类推。

考虑下面的几个例子:


                               
登录/注册后可看大图


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

其中玩家 1 能赢多少局?



想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2017-1-8 21:36:56 | 显示全部楼层
本帖最后由 jerryxjr1220 于 2017-1-12 18:44 编辑

这题到不是说难,而是比较繁琐,每一种情况都要考虑,从大到小依次写各种情况下的胜负判断。
思路就是按照优胜规则写的,判断依据写在注释里了。
  1. #coding:utf-8

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

  4.     flush = 1
  5.     suit = hand[0][1]
  6.     for card in hand:
  7.         if card[1] != suit:
  8.             flush = 0
  9.             break

  10.     indices = []
  11.     royal = 1
  12.     straight = 1
  13.     for card in hand:
  14.         indices.append(values.index(card[0]))
  15.     indices.sort()
  16.     if indices[4] - indices[0] != 4 \
  17.        or indices.count(indices[0]) > 1 \
  18.        or indices.count(indices[1]) > 1 \
  19.        or indices.count(indices[2]) > 1 \
  20.        or indices.count(indices[3]) > 1 \
  21.        or indices.count(indices[4]) > 1:
  22.         straight = 0
  23.     if indices[0] != 8:
  24.         royal = 0

  25.     kinds = []
  26.     for value in indices:
  27.         count = indices.count(value)
  28.         if count > 1:
  29.             kind = [value, count]
  30.             if kind not in kinds:
  31.                 kinds.append(kind)

  32.     if royal and flush:
  33. #        return "royal flush"
  34.         return [9, 0]
  35.     if straight and flush:
  36. #        return "straight flush"
  37.         return [8, indices[4]]
  38.     if len(kinds) == 1 and kinds[0][1] == 4:
  39. #        return "four of a kind"
  40.         return [7, kinds[0][0]]
  41.     if len(kinds) == 2 and (kinds[0][1] + kinds[1][1] == 5):
  42. #        return "full house"
  43.         return [6, kinds[0][0]]
  44.     if flush:
  45. #        return "flush"
  46.         return [5, indices[4]]
  47.     if straight:
  48. #        return "straight"
  49.         return [4, indices[4]]
  50.     if len(kinds) == 1 and kinds[0][1] == 3:
  51. #        return "three of a kind"
  52.         return [3, kinds[0][0]]
  53.     if len(kinds) == 2 and (kinds[0][1] + kinds[1][1] == 4):
  54. #        return "two pair"
  55.         return [2, max(kinds[0][0], kinds[1][0])]
  56.     if len(kinds) == 1 and kinds[0][1] == 2:
  57. #        return "one pair"
  58.         return [1, kinds[0][0]]
  59. #    return "high card"
  60.     return [0, max(indices)]

  61. c = 0
  62. with open('p054_poker.txt') as f:
  63.     lines = f.readlines()
  64. for line in lines:
  65.     r = line.strip('\n').split()
  66.     p1 = evalHand(r[:5])
  67.     p2 = evalHand(r[5:])
  68.     if p1[0] > p2[0] or (p1[0] == p2[0] and p1[1] > p2[1]):
  69.         c += 1

  70. print (c)
复制代码

输出:
376
[Finished in 0.3s]

评分

参与人数 1荣誉 +15 鱼币 +15 收起 理由
冬雪雪冬 + 15 + 15

查看全部评分

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

使用道具 举报

发表于 2017-1-9 17:34:14 | 显示全部楼层
我只想知道T是什么

点评

T代表10  发表于 2017-1-10 10:05
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-1-10 14:28:39 | 显示全部楼层
本帖最后由 小Q学Python 于 2017-1-10 15:09 编辑

对于新手的我来讲有点难,本打算用面向对象的办法来做,可转化不过来,放弃。
从看到题,到思考,找方法,花了不少时间,最终思路如下:
问题1.如何把5张牌定型为10种形态(其实是9种,最后的Royal Flush也属于Straight Flush)。
问题2.如何比较形态,如果形态相同,如何继续比较。
1.  5张牌的花色和数字分别处理,花色比较简单,如果都一样,即为“清一色”。数字定位比较麻烦,通过摸索,发现个规律:list的count函数,可以得出每个数字的出现次数,把5个数字的出现次数相加得到的总数,可以对应不同的形态。(如Four of a Kind,这个值为17,Full House的值为13)
2.  如果形态相同,每个形态继续比较的方式也不尽相同。(如Four of a Kind,就要找到4个相同的数字进行比较,Three of a Kind和Full House就要找三个相同的数字比较,而Two Pairs,不仅要对2对从大到小的对子进行比较,如果两对都相同,还要对单牌进行比较)。在这里,我把每个形态需要返回的比较值,按顺序通过list方式返回,同时,顺便把在list的第一位打上形态标志位。
  1. import time
  2. def datainit(a):   # a like“8C TS KC 9H 4S”
  3.     '数据初始化,将扑克的数字和花色分开,数字转为int'
  4.     part1 = []
  5.     part2 = []
  6.     dict1 = {'2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9,
  7.              'T': 10, 'J': 11, 'Q': 12, 'K': 13, 'A': 14} #创建个字典,T对应10,J-11,Q-12,K-13,A-14
  8.     for i in range(0, 14, 3):
  9.         part1.append(dict1[a[i]]) #将数字放入part1
  10.     for i in range(1, 14, 3):
  11.         part2.append(a[i]) #将花色放入part2
  12.     part1.sort() #数字排序
  13.     part1.reverse() #数字按从大往小排序
  14.     return [part1, part2]

  15. def getflush(part2):
  16.     '判断是否同花'
  17.     if part2.count(part2[0]) == 5:
  18.         return True
  19.     else:
  20.         return False

  21. def gettype(b):
  22.     '判断牌属于哪种类型,并回返比较值'
  23.     part1 = b[0]
  24.     counts = 0   #记录5张牌每张牌出现次数的总和
  25.     result = []  #返回牌的类型
  26.     count = [[], [], [], []] #其中第一个list为出现过1次的数字,第二个list为出现过2次的数字,以此类推
  27.     for i in range(5): #遍历5次
  28.         if part1.count(part1[i]) == 4: #当前数字如果list.count=4,则进入count的第4个list
  29.             count[3].append(part1[i])
  30.         elif part1.count(part1[i]) == 3:#当前数字如果list.count=3,则进入count的第3个list
  31.             count[2].append(part1[i])
  32.         elif part1.count(part1[i]) == 2:#同上
  33.             count[1].append(part1[i])
  34.         else:
  35.             count[0].append(part1[i])   #同上
  36.         counts += part1.count(part1[i])
  37.     # 为每个类型定义一个数值作为返回值result的第一位,最大的Straight Flush(Royal Flush也属于Straight Flush)为10,最小的High Card为2。以此类推。
  38.     if counts == 17:  #Four of a Kind,相同的4个牌,每个牌出现4次,剩下的牌出现1次,总和为17.
  39.         result = [9] + [count[3][0]]  #Four of a Kind定义为9,count[3][0]就是出现4次的数字
  40.     elif counts == 13: #Full House 3*3+2*2=13
  41.         result = [8] + [count[2][0]]  #Full House 定义为8,[count[2][0]]为出现3次的数字
  42.     elif counts == 11: #Three of a Kind
  43.         result = [5] + [count[2][0]]
  44.     elif counts == 9:  #Two Pairs
  45.         result = [4] + [count[1][0], count[1][2]] + count[0]
  46.     elif counts == 7:  #One Pair
  47.         result = [3] + [count[1][0]] + count[0]
  48.     else: #counts为5,就是5张单牌
  49.         if part1[0] == part1[1]+1 == part1[2]+2 == part1[3]+3 == part1[4]+4: #part1是倒序,所以直接+1比较,判断是否顺子
  50.             if getflush(b[1]):  #判断是否同花
  51.                 result = [10] + [max(part1)]  #Straight Flush定义为10 ,+ 同花顺中的最大值
  52.             else:
  53.                 result = [6] + [max(part1)]  #Straight 定义为6 ,+ 顺子中的最大值
  54.         else:
  55.             if getflush(b[1]):
  56.                 result = [7] + part1   #Flush
  57.             else:
  58.                 result = [2] + part1   #High Card
  59.     return result

  60. start = time.time()
  61. file = open('p054_poker.txt', 'r')
  62. play1wins = 0   #记录play1赢的次数
  63. for line in file:
  64.     play1 = line[:14]  #取前5张牌
  65.     play2 = line[14:].strip()  #取后5张牌
  66.     if gettype(datainit(play1)) > gettype(datainit(play2)):  #list比较,第一位是类型大小,类型相同,再逐一比较
  67.         play1wins += 1

  68. print(play1wins)
  69. print('Time used: %.3f sec' % (time.time()-start))
复制代码


376
Time used: 0.031 sec


评分

参与人数 1荣誉 +15 鱼币 +15 收起 理由
冬雪雪冬 + 15 + 15

查看全部评分

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

使用道具 举报

发表于 2017-1-10 15:37:55 | 显示全部楼层
本帖最后由 余欲渔 于 2017-1-11 11:38 编辑

每次看完别人的都觉得自己的写的好死板啊。。。。

  1. cishu=0
  2. f=open("F:/p054_poker.txt") #按文件位置打开所需文件

  3. #下面的是ceshi函数,返回一个列表
  4. def ceshi(zhi,hua):         
  5.     s=[]

  6.         #第一个判断同花顺
  7.     if zhi[4]-zhi[3]==zhi[3]-zhi[2]==zhi[2]-zhi[1]==zhi[1]-zhi[0]==1 and len(set(hua))==1:
  8.         s.append(9);s.append(zhi[4])

  9.         #下面是四张,两种情况
  10.     elif zhi[0]==zhi[1]==zhi[2]==zhi[3] :
  11.         s.append(8);s.append(zhi[0])
  12.     elif zhi[4]==zhi[1]==zhi[2]==zhi[3]:
  13.         s.append(8);s.append(zhi[4])

  14.         #下面是葫芦,大二小三和大三小二两种可能
  15.     elif zhi[0]==zhi[1]==zhi[2] and zhi[3]==zhi[4]:
  16.         s.append(7);s.append(zhi[0])
  17.     elif zhi[3]==zhi[4]==zhi[2] and zhi[0]==zhi[1]:
  18.         s.append(7);s.append(zhi[4])
  19.         
  20.         #下面是同花,只有一种可能
  21.     elif len(set(hua))==1:
  22.         s.append(6);s.append(zhi[4]);s.append(zhi[3]);s.append(zhi[2]);s.append(zhi[1]);s.append(zhi[0])

  23.         #下面是顺子,只有1种可能
  24.     elif zhi[4]-zhi[3]==zhi[3]-zhi[2]==zhi[2]-zhi[1]==zhi[1]-zhi[0]==1:
  25.         s.append(5);s.append(zhi[4])

  26.         #下面是三条,左中右三种可能
  27.     elif zhi[0]==zhi[1]==zhi[2] :
  28.         s.append(4);s.append(zhi[0])
  29.     elif zhi[3]==zhi[1]==zhi[2] :
  30.         s.append(4);s.append(zhi[1])
  31.     elif zhi[3]==zhi[4]==zhi[2]:
  32.         s.append(4);s.append(zhi[2])
  33.         
  34.         #下面是两对,单张在左中右三种可能
  35.     elif zhi[0]==zhi[1]and zhi[2]==zhi[3]:
  36.         s.append(3);s.append(zhi[2]);s.append(zhi[1]);s.append(zhi[4])
  37.     elif zhi[1]==zhi[2]and zhi[3]==zhi[4]:
  38.         s.append(3);s.append(zhi[3]);s.append(zhi[2]);s.append(zhi[0])
  39.     elif zhi[0]==zhi[1]and zhi[3]==zhi[4]:
  40.         s.append(3);s.append(zhi[3]);s.append(zhi[1]);s.append(zhi[2])
  41.         
  42.         #下面是对子,左三,左二右一,左一右二,右三,四种可能
  43.     elif zhi[0]==zhi[1] :
  44.         s.append(2);s.append(zhi[1]);s.append(zhi[4]);s.append(zhi[3]);s.append(zhi[2])
  45.     elif zhi[2]==zhi[1] :
  46.         s.append(2);s.append(zhi[2]);s.append(zhi[4]);s.append(zhi[3]);s.append(zhi[0])
  47.     elif zhi[2]==zhi[3] :
  48.         s.append(2);s.append(zhi[3]);s.append(zhi[4]);s.append(zhi[1]);s.append(zhi[0])   
  49.     elif zhi[3]==zhi[4]:
  50.         s.append(2);s.append(zhi[4]);s.append(zhi[2]);s.append(zhi[1]);s.append(zhi[0])

  51.         #下面是单张
  52.     else:
  53.         s.append(1);s.append(zhi[4]);s.append(zhi[3]);s.append(zhi[2]);s.append(zhi[1]);s.append(zhi[0])

  54.     return s      

  55. def tihuan(wj):        #把值部分字符换成数字
  56.     for i in range(5):
  57.         if wj[i]=='T':
  58.             wj[i]=10
  59.         elif wj[i]=='J':
  60.             wj[i]=11
  61.         elif wj[i]=='Q':
  62.             wj[i]=12
  63.         elif wj[i]=='K':
  64.             wj[i]=13
  65.         elif wj[i]=='A':
  66.             wj[i]=14
  67.         else:
  68.             wj[i]=int(wj[i])
  69.     return wj

  70. for i in range(1000):
  71.     a=f.readline()
  72.     wj1zhi=[]       #这里做的比较复杂,是把牌的值zhi和花色hua分开了
  73.     wj1hua=[]
  74.     wj2zhi=[]
  75.     wj2hua=[]
  76.    
  77.     for i in range(5):      #这个循环就是把读取到的一行数据分出来
  78.         wj1zhi.append(a[3*i:3*i+1])
  79.         wj1hua.append(a[3*i+1:3*i+2])
  80.         wj2zhi.append(a[3*(i+5):3*(i+5)+1])
  81.         wj2hua.append(a[3*(i+5)+1:3*(i+5)+2])
  82.         
  83.     wj1zhi=tihuan(wj1zhi)      
  84.     wj2zhi=tihuan(wj2zhi)
  85.     wj1zhi.sort()                  #排序,以便后面处理
  86.     wj2zhi.sort()
  87.     w1=ceshi(wj1zhi,wj1hua)        #两个玩家的牌分别带入ceshi函数算出大小
  88.     w2=ceshi(wj2zhi,wj2hua)

  89.     if w1>w2:                      #判断大小
  90.         cishu+=1

  91. f.close()
  92. print("玩家1共计赢了%d次!"%cishu)
复制代码

  1. = RESTART: C:\Users\ASUS\AppData\Local\Programs\Python\Python35-32\poker.py =
  2. 玩家1共计赢了376次!
  3. >>>
复制代码

评分

参与人数 1荣誉 +15 鱼币 +15 收起 理由
冬雪雪冬 + 15 + 15

查看全部评分

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

使用道具 举报

发表于 2017-1-11 17:34:59 | 显示全部楼层
T是啥?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-1-11 19:55:42 | 显示全部楼层
看看~~~~~~~~~~~
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2017-1-13 00:39:20 | 显示全部楼层
哈哈不错哦
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-1-21 20:56:09 | 显示全部楼层
附件只有167b,下载之后是空压缩包。可以补一下档吗?
我也想做做看
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-2-18 18:10:03 | 显示全部楼层
jerryxjr1220 发表于 2017-1-8 21:36
这题到不是说难,而是比较繁琐,每一种情况都要考虑,从大到小依次写各种情况下的胜负判断。
思路就是按照 ...

感觉有个小问题,flush和high card的时候不能只返回最大值比较,two pairs的时候也是有可能要比剩下的单张大小的
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-2-18 18:18:49 | 显示全部楼层
理这个思路花了好久

  1. nums = ('2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A')

  2. def evalcard(cards):

  3.     flush = 0
  4.     straight = 0
  5.     royal = 0
  6.    
  7. # 判断手牌同花
  8.     suit = []
  9.     for card in cards:
  10.         if card[1] not in suit:
  11.             suit.append(card[1])
  12.     if len(suit) == 1:
  13.         flush == 1

  14. # 统计手牌数字
  15.     handvalue = []
  16.     for card in cards:
  17.         handvalue.append(nums.index(card[0]))
  18.     handvalue.sort(reverse = True) #reverse便于后面列表比大小
  19.    
  20. #分辨牌型
  21.     if handvalue[4] == handvalue[3] - 1 \
  22.        == handvalue[2] - 2 \
  23.        == handvalue[1] - 3 \
  24.        == handvalue[0] - 4:
  25.         straight = 1        #判断顺子
  26.     if handvalue[0] == 12:  #判断ACE
  27.         royal = 1

  28.     kinds = []
  29.     for each in handvalue:
  30.         kind = [handvalue.count(each), each]
  31.         if kind not in kinds:
  32.             kinds.append(kind)
  33.     kinds.sort(reverse = True)

  34.    
  35.     if flush == 1 and straight == 1 and royal == 1:
  36.         return [9]
  37.     elif flush == 1 and straight == 1:
  38.         return [8, handvalue[0]]
  39.     elif kinds[0][0] == 4:
  40.         return [7, kinds[0][1]]
  41.     elif kinds[0][0] == 3 and kinds[1][0] == 2:
  42.         return [6]
  43.     elif flush == 1:
  44.         return [5, handvalue]
  45.     elif straight == 1:
  46.         return [4, handvalue[0]]
  47.     elif kinds[0][0] == 3:
  48.         return [3, kinds[0][1]]
  49.     elif kinds[0][0] == 2 and kinds[1][0] == 2:
  50.         return [2, [kinds[0][1], kinds[1][1], kinds[2][1]]]
  51.     elif kinds[0][0] == 2 and kinds[1][0] == 1:
  52.         return [1, [kinds[0][1], kinds[1][1], kinds[2][1], kinds[3][1]]]
  53.     else:
  54.         return [0, handvalue]

  55. c = 0

  56. with open('p054_poker.txt') as f:
  57.     lines = f.readlines()
  58. for line in lines:
  59.     r = line.strip('\n').split()
  60.     p1 = evalcard(r[:5])
  61.     p2 = evalcard(r[5:])
  62.     if p1 > p2 or (p1[0] == p2[0] and p1[1] > p2[1]):
  63.         c += 1

  64. print(c)
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-4-25 00:50

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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