• python 从一道作业题到制作一个图形界面的“诈金花”游戏


    题目很简单:就是自己写一个程序,实现诈金花游戏的发牌、判断输赢。

    规则:

    一付扑克牌,去掉大小王,每个玩家发3张牌,最后比大小,看谁赢。

    牌型:

    豹子:一样大的三张牌,如10,10,10
    顺金:又称同花顺,即3张同花色的顺子, 如红桃 5、6、7
    金花:又称同花,即3张牌同花色但非顺子,如草花J、8、7
    顺子:3张连续大小但花色不全相同,如红桃5、方片6、黑桃7
    对子:只有2张一样大的牌,如果对子一样大就比第3张的大小
    单张:3张牌不同花不成对也不成顺子,最大的是A带头的单张

    版型大小顺序: 豹子>顺金>金花>顺子>对子>单张

    从网上百科到的诈金花各种牌型的出现概率,一起放进代码中增加一点趣味小知识。你可能不知道豹子出现的概率比同花顺大,实际打牌时同花顺反而比豹子小;顺子出现的概率比金花小,实际打牌时顺子反而比金花小;最大牌为5、6、7的单张牌型出现的概率都要比金花和顺子小,所以有的地方额外规定同一局中拿到“235”三张牌要比同局的豹子大。

    回到正题,直接上代码,主要2个函数:一个计分、一个比大小

    1. from random import shuffle as DealCards
    2. Players = 5 #人数
    3. pkPacks = 1 #扑克副数
    4. W = "单张","对子","顺子","金花","顺金","豹子"
    5. X = 74.38, 16.94, 3.26, 4.96, 0.22, 0.24 #出现概率
    6. Y = 0.54, 1.36, 2.44, 3.8, 5.43, 7.33, 9.5, 11.95, 14.66, 17.38 #单张概率
    7. V = *(str(i) for i in range(2,10)),*'TJQKA' #T代表10
    8. F = '♠', '♥', '♣', '♦'
    9. P = [f+v for f in F for v in V]*pkPacks
    10. def Scores(pokers):
    11. f,p = [],[]
    12. for poker in pokers:
    13. f.append(F.index(poker[0])+1)
    14. p.append(V.index(poker[1])+2)
    15. t = sorted(p)
    16. intSame = len(set(t))
    17. isFlush = int(len(set(f))==1)
    18. isStraight = t[0]+1==t[1]==t[2]-1
    19. if intSame==1:
    20. return 500_0000+t[0] #豹子
    21. elif intSame==2: #对子一样大比较剩下的单张
    22. return (100+t[1])*10000+(t[2] if t[0]==t[1] else t[0])
    23. else: #顺金(同花顺)顺子 else #单张或金花
    24. return 200_0000*(1+isFlush)+t[2] if isStraight else ((300*isFlush+t[2])*100+t[1])*100+t[0]
    25. def WhoWins(P):
    26. Pokers,Winner = [],[]
    27. for i in range(0,3*Players,3):
    28. Pokers.append(P[i:i+3])
    29. for i,p in enumerate(Pokers,1):
    30. win = Scores(p)
    31. idx = win//100_0000
    32. print(f"Player{i}: {*p,} - {W[idx]}")
    33. Winner.append(win)
    34. win = max(Winner) #没有判断“一样大”,如是则谁在前谁为大
    35. idx = Winner.index(win)
    36. big = win//10000
    37. win = big//100
    38. per = X[win] if win else Y[big-5]
    39. pok = W[win] if win else '单'+V[big-2]
    40. print(f"【Player{idx+1} win!】--> {*Pokers[idx],} {pok}({per}%)\n".replace('T','10'))
    41. return P[3*Players:] #去掉每一局已发的牌
    42. if __name__ == '__main__':
    43. DealCards(P) #以随机洗牌来模拟发牌
    44. #Players = int(input('请输入参加的人数?'))
    45. PlayersMax = 52*pkPacks//3+1
    46. if not 0
    47. print(f'请注意:参与人数的范围 0 < Players < {PlayersMax} !')
    48. else:
    49. count = 1
    50. while len(P)>=3*Players: #所有牌(52*PokerPairs)发不够一局为止
    51. print(f'第{count}局:')
    52. count += 1
    53. P = WhoWins(P)

    运行结果:

    第1局:
    Player1: ('♥Q', '♣2', '♣8') - 单张
    Player2: ('♦10', '♥7', '♠6') - 单张
    Player3: ('♣4', '♠4', '♦2') - 对子
    Player4: ('♠5', '♠9', '♥6') - 单张
    Player5: ('♠7', '♠3', '♣5') - 单张
    【Player3 win!】--> ('♣4', '♠4', '♦2') 对子(16.94%)

    第2局:
    Player1: ('♥2', '♥8', '♦4') - 单张
    Player2: ('♦9', '♦3', '♥A') - 单张
    Player3: ('♠J', '♣A', '♦K') - 单张
    Player4: ('♠8', '♥9', '♥10') - 顺子
    Player5: ('♣7', '♣9', '♣10') - 金花
    【Player5 win!】--> ('♣7', '♣9', '♣10') 金花(4.96%)

    第3局:
    Player1: ('♦7', '♦J', '♠2') - 单张
    Player2: ('♥J', '♦A', '♥K') - 单张
    Player3: ('♥4', '♥5', '♦6') - 顺子
    Player4: ('♣Q', '♣J', '♠10') - 顺子
    Player5: ('♣K', '♦8', '♦5') - 单张
    【Player4 win!】--> ('♣Q', '♣J', '♠10') 顺子(3.26%)

    【扩展】学习要举一反三,做完题目想到把这个程序的界面图形化。为方便摆放牌堆,就只指定一付扑克四个玩家。然后,无非就是把原代码中扑克牌对应花色、大小的下标值从以下牌型图中索引出相应的图来,放到对应的Image控件上;而想要输出的文字就对应到text控件上;再整几个button控件绑定对应的事件动作,就搞定了!

    牌型图: Pokers.png

    初始界面:

    发牌界面:

    开牌界面:

    PokersV1.py 完整源代码:

    1. import tkinter as tk
    2. from PIL import Image,ImageTk
    3. from time import sleep
    4. from random import shuffle as DealCards
    5. W = "单张","对子","顺子","金花","顺金","豹子" #牌型
    6. X = 74.38, 16.94, 3.26, 4.96, 0.22, 0.24 #各牌型出现概率
    7. Y = 0.54, 1.36, 2.44, 3.8, 5.43, 7.33, 9.5, 11.95, 14.66, 17.38 #单张概率
    8. V = *(str(i) for i in range(2,10)),*'TJQKA' #T代表10
    9. F = '♠', '♥', '♣', '♦'
    10. def loadCards():
    11. infile = Image.open("pokers.png")
    12. Images = []
    13. for j in range(4):
    14. image = []
    15. for i in range(15):
    16. box = infile.crop((i*100,j*150,i*100+100,j*150+150))
    17. img = ImageTk.PhotoImage(image=box)
    18. image.append(img)
    19. Images.append(image)
    20. infile.close()
    21. return Images
    22. def initCards():
    23. global isReady,P
    24. isReady = True
    25. P = [f+v for f in F for v in V]
    26. DealCards(P)
    27. def dealCards():
    28. global cv,cards,isReady,P,Pokers
    29. if not isReady: return
    30. cv.itemconfig(txt1, text="")
    31. cv.itemconfig(txt2, text="")
    32. if len(Pokers):
    33. for j in range(3):
    34. for i in range(4):
    35. cv.itemconfig(cards[i][j], image=Cards[0][0])
    36. cv.update()
    37. sleep(0.3)
    38. for j in range(3):
    39. for i in range(4):
    40. cv.itemconfig(cards[i][j], image=Cards[1][0])
    41. cv.update()
    42. sleep(0.2)
    43. if len(P)<12:
    44. initCards()
    45. isReady = False
    46. def playCards():
    47. global cv,isReady,P,Pokers,cards,Cards
    48. if isReady: return
    49. P = WhoWins(P)
    50. for i,pok in enumerate(Pokers):
    51. for j,p in enumerate(pok):
    52. x = F.index(p[0])
    53. y = V.index(p[1])
    54. #print(x,y,'-',i,j)
    55. cv.itemconfig(cards[i][j], image=Cards[x][y+2])
    56. cv.update()
    57. isReady = True
    58. def Scores(pokers):
    59. f,p = [],[]
    60. for poker in pokers:
    61. f.append(F.index(poker[0])+1)
    62. p.append(V.index(poker[1])+2)
    63. t = sorted(p)
    64. intSame = len(set(t))
    65. isFlush = int(len(set(f))==1)
    66. isStraight = t[0]+1==t[1]==t[2]-1
    67. if intSame==1:
    68. return 500_0000+t[0] #豹子
    69. elif intSame==2: #对子一样大比较剩下的单张
    70. return (100+t[1])*10000+(t[2] if t[0]==t[1] else t[0])
    71. else: #顺金(同花顺)顺子 else #单张或金花
    72. return 200_0000*(1+isFlush)+t[2] if isStraight else ((300*isFlush+t[2])*100+t[1])*100+t[0]
    73. def WhoWins(P):
    74. global cv,txt1,txt2,Pokers
    75. Pokers,Winner = [],[]
    76. for i in range(0,3*4,3):
    77. Pokers.append(P[i:i+3])
    78. for i,p in enumerate(Pokers,1):
    79. win = Scores(p)
    80. idx = win//100_0000
    81. print(f"Player{i}: {*p,} - {W[idx]}".replace('T','10'))
    82. Winner.append(win)
    83. win = max(Winner) #没有判断“一样大”,如是则谁在前谁为大
    84. idx = Winner.index(win)
    85. big = win//10000
    86. win = big//100
    87. per = X[win] if win else Y[big-5]
    88. pok = W[win] if win else '单'+V[big-2]
    89. text1 = f"【Player{idx+1} win!】"
    90. text2 = f"{pok}{*Pokers[idx],} {per}%\n".replace('T','10')
    91. print(text1,'--> ',text2)
    92. cv.itemconfig(txt1, text=text1)
    93. cv.itemconfig(txt2, text=text2)
    94. return P[3*4:] #去掉一局已发的牌
    95. def test():
    96. global P
    97. initCards()
    98. print("测试用:",P)
    99. if __name__ == '__main__':
    100. root = tk.Tk()
    101. root.geometry('1024x768')
    102. root.title('诈金花')
    103. cv = tk.Canvas(root, width=1024, height=680, bg='darkgreen')
    104. cv.pack()
    105. Pokers = []
    106. initCards()
    107. Cards = loadCards()
    108. cards = [[None]*3 for _ in range(4)]
    109. x1, x2, x3, dx = 400, 80, 730, 105
    110. y1, y2, y3 = 100, 550, 320
    111. imgxy = [[(x1,y1),(x1+dx,y1),(x1+2*dx,y1)],[(x3,y3),(x3+dx,y3),(x3+2*dx,y3)],
    112. [(x1,y2),(x1+dx,y2),(x1+2*dx,y2)],[(x2,y3),(x2+dx,y3),(x2+2*dx,y3)]]
    113. for x,lst in enumerate(imgxy):
    114. for y,coord in enumerate(lst):
    115. cards[x][y] = cv.create_image(coord, image=Cards[0][0])
    116. cv.create_rectangle(coord[0]-50,coord[1]-75,coord[0]+50,coord[1]+75)
    117. tx,ty = coord[0]-100,coord[1]+95
    118. cv.create_text(tx,ty, text=f'Player{x+1}', fill='white')
    119. btn = []
    120. btnCmd = ['发牌',dealCards,'发牌',playCards,'重新理牌',test]
    121. for i in range(3):
    122. btn.append(tk.Button(root,text=btnCmd[i*2],command=btnCmd[i*2+1],width=10))
    123. btn[i].place(y=710, x=350+i*110)
    124. txt1 = cv.create_text(510,300, fill='red', font=("宋体", 16))
    125. txt2 = cv.create_text(510,360, fill='yellow', font=("宋体", 10))
    126. root.mainloop()

    【编译程序】

    Windows的Cmd窗口中执行如下命令,Mac系统自行百度对应的编译命令:

    pyinstaller -F exam.py --noconsole

    注意:记得把上面的牌型图保存为Pokers.png和代码或程序放一起运行。

  • 相关阅读:
    【白帽子讲Web安全】第一章 我的安全世界观
    大型语言模型:通过代码生成、调试和 CI/CD 集成改变软件开发的游戏规则
    平台系统老板驾驶舱的重要性,我选云表
    UDP丢包替代:用PCAP实现C/C++以太网SDR吞吐
    【leetcode 力扣刷题】栈和队列的基础知识 + 栈的经典应用—匹配
    深度学习之 8 深度模型优化与正则化2
    RabbitMQ之消息模式简单易懂,超详细分享~~~
    Dubbo多协议支持
    [从零开始学习FPGA编程-56]:视野篇-常见概念:chip(芯片)、chipset(芯片组)、chiplet(芯粒)、die(裸片)的区别
    1.3 互联网的组成
  • 原文地址:https://blog.csdn.net/boysoft2002/article/details/128146513