诈金花游戏下载:python 图形界面“诈金花”游戏,更新了!附完整代码

旧版本的代码请见上一篇博文: 

python 从一道作业题到制作一个图形界面的“诈金花”游戏_Hann Yang的博客-CSDN博客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%)

演示代码:

import tkinter as tkfrom PIL import Image,ImageTkdef load(i=0): img = Image.open("pokers.png").resize((375,150)) box = img.rotate(90*i) res = ImageTk.PhotoImage(image=box) img.close() return resif __name__ == '__main__': root = tk.Tk() root.geometry('800x480') root.title('图片旋转') cv = tk.Canvas(root, width=1600, height=800, bg='darkgreen') cv.pack() png = [None]*4 coord = ((i,j) for j in (120,345) for i in (200,600)) for i,xy in enumerate(coord): png[i] = load(i) cv.create_image(xy, image=png[i]) cv.create_text(xy[0],xy[1]+95, text=f'逆时针转动{i*90}度',fill='white') root.mainloop()

为保存全图在转动之前,设置一个正方形框 box = img.crop((0,0,375,375)).rotate(-90*i),顺时针转动的效果如下:

演示代码:

import tkinter as tkfrom PIL import Image,ImageTkdef load(i=0): img = Image.open("pokers.png").resize((375,150)) box = img.crop((0,0,375,375)).rotate(-90*i) res = ImageTk.PhotoImage(image=box) img.close() return resif __name__ == '__main__': root = tk.Tk() root.geometry('800x800') root.title('图片旋转') cv = tk.Canvas(root, width=1600, height=800, bg='darkgreen') cv.pack() png = [] coord = ((i,j) for j in (200,600) for i in (200,600)) for i,xy in enumerate(coord): png.append(load(i)) cv.create_image(xy, image=png[i]) root.mainloop()

然后再用crop()方法来截取出黑色背景除外的部分,就是所需的转动四个方向上的图像;最后把这些图片再次分割成一张张小纸牌,存入一个三维列表备用。 

二、增加筹码变量,使得比大小游戏有累积输赢过程

在玩家文本框后各添加一个筹码文本框,动态显示每一局的输赢情况;各玩家的筹码值存放于全局变量Money列表中,主要代码如下:

ALL, ONE = 1000, 200 #筹码初始值、单次输赢值 Money = [ALL]*4 #设置各方筹码初始值 ... ... cv.create_text(tx,ty, text=f'Player{x+1}', fill='white') #玩家1-4显示文本框 txt.append(cv.create_text(tx+60,ty, fill='gold',text=Money[x])) #筹码显示框 ... ... Money[idx] += ONE*4 #每次赢ONE*3,多加自己的一份 for i in range(4): Money[i] -= ONE #多加的在此扣减 cv.itemconfig(txt[i], text=str(Money[i])) #修改各方的筹码值 cv.update()

三、界面增加下拉式菜单,菜单项调用绑定函数

显示效果见题图左上角,主要代码如下:

btnCmd = '发牌',dealCards,'开牌',playCards,'洗牌',Shuffle Menu = tk.Menu(root) menu = tk.Menu(Menu, tearoff = False) for t,cmd in zip(btnCmd[::2],btnCmd[1::2]): menu.add_radiobutton(label = t, command = cmd) menu.add_separator() #菜单分割线 menu.add_command(label = "退出", command = ExitApp) Menu.add_cascade(label="菜单",menu = menu) root.config(menu = Menu)

四、导入信息框库,增加提示信息框的使用

使用了2种信息框类型:提示showinfo()和确认选择askokcancel()

tkinter.messagebox库共有8种信息框类型,其使用方法基本相同,只是显示的图标有区别:

Help on module tkinter.messagebox in tkinter:

NAME
    tkinter.messagebox

FUNCTIONS
   askokcancel(title=None, message=None, **options)
        Ask if operation should proceed; return true if the answer is ok
    
    askquestion(title=None, message=None, **options)
        Ask a question
    
    askretrycancel(title=None, message=None, **options)
        Ask if operation should be retried; return true if the answer is yes
    
    askyesno(title=None, message=None, **options)
        Ask a question; return true if the answer is yes
    
    askyesnocancel(title=None, message=None, **options)
        Ask a question; return true if the answer is yes, None if cancelled.
    
    showerror(title=None, message=None, **options)
        Show an error message
    
   showinfo(title=None, message=None, **options)
        Show an info message
    
    showwarning(title=None, message=None, **options)
        Show a warning message

DATA
    ABORT = 'abort'
    ABORTRETRYIGNORE = 'abortretryignore'
    CANCEL = 'cancel'
    ERROR = 'error'
    IGNORE = 'ignore'
    INFO = 'info'
    NO = 'no'
    OK = 'ok'
    OKCANCEL = 'okcancel'
    QUESTION = 'question'
    RETRY = 'retry'
    RETRYCANCEL = 'retrycancel'
    WARNING = 'warning'
    YES = 'yes'
    YESNO = 'yesno'
    YESNOCANCEL = 'yesnocancel'

:发牌、开牌、洗牌按钮可否点击,由两个全局变量控制,当不能使用时弹出提示信息框。但更好方式通常是设置按钮的state状态,在 tk.DISABLED 和 tk.NORMAL 之间切换,用以下代码:

if btn[0]['state'] == tk.DISABLED:btn[0]['state'] = tk.NORMALelse:btn[0]['state'] = tk.DISABLED #使得按钮灰化,无法被按下#或者在初始按钮时使用:tk.Button(root,text="点不了",command=test,width=10,state=tk.DISABLED)

“诈金花”完整源代码

import tkinter as tkimport tkinter.messagebox as msgfrom PIL import Image,ImageTkfrom time import sleepfrom random import shuffle as DealCards#代码中所有print()语句行测试用都可删除#Written by Hann@CSDN,2022.12.06#https://hannyang.blog.csdn.net/def loadCards(): PngList = [] infile = Image.open("pokers.png") for k in range(4): box = 0,0,1500,1500 #设置正方形区域存放图片旋转后的状态 box = infile.crop(box).rotate(90*k) #图片逆时间旋转90度的整数倍 if k==0: rng = (0,0,1500,600) elif k==1: rng = (0,0,600,1500) elif k==2: rng = (0,900,1500,1500) elif k==3: rng = (900,0,1500,1500) box = box.crop(rng) #截取掉旋转产生的黑色背景 images = [] for j in range(4): #分割所有纸牌的图像存入三维列表 image = [] for i in range(15): if k%2: rng = (j*150,i*100,j*150+150,i*100+100) else: rng = (i*100,j*150,i*100+100,j*150+150) img = ImageTk.PhotoImage(image=box.crop(rng)) image.append(img) images.append(image) PngList.append(images) '''调整并统一各方向上的纸牌图像顺序''' PngList[0],PngList[2] = PngList[2],PngList[0] for i in range(4): for j in range(2): PngList[j][i]=PngList[j][i][::-1] for i in range(0,4,3): PngList[i]=PngList[i][::-1] infile.close() return PngList def initCards(): global P P = [f+v for f in F for v in V] DealCards(P) print('洗牌结果:\n',P)def clearCards(): global cv cv.itemconfig(txt1, text="") cv.itemconfig(txt2, text="") if len(Pokers): for j in range(3): for i in range(4): cv.itemconfig(cards[i][j], image=Cards[i][0][0]) cv.update() sleep(0.3)def dealCards(): global cv,isReady1,isReady2 if not isReady1: showInfo('不要重复发牌,发牌结束后请开牌!') return clearCards() isReady1 = False for j in range(3): for i in range(4): cv.itemconfig(cards[i][j], image=Cards[i][1][0]) cv.update() sleep(0.2) if len(P)<12: initCards() isReady2 = False def playCards(): global cv,isReady1,isReady2,P,Pokers if isReady1: showInfo('还没发牌,请发牌或者洗牌!') elif isReady2: showInfo('发牌还未结束,请勿开牌!') else: P = Result(P) isReady1,isReady2 = True,True for i,pok in enumerate(Pokers): for j,p in enumerate(pok): x,y = F.index(p[0]), V.index(p[1]) cv.itemconfig(cards[i][j], image=Cards[i][x][y+2]) cv.update() for i in range(4): cv.itemconfig(txt[i], text=str(Money[i])) #修改各方的筹码值 cv.update() if min(Money)<=0: #统计输赢成绩 zero = [f'Player{i}' for i,j in enumerate(Money,1) if j<=0] winner = [f'Player{i}({j})' for i,j in enumerate(Money,1) if j>ALL] info = '、'.join(zero)+'已输光筹码,点击确定重新开始!\n\n' info += f'本轮胜者(筹码多于初始值):'+'、'.join(winner) sleep(1) msg.showinfo(title = '提示',message=info) for i in range(4): Money[i] = ALL #重置各方筹码初始值 cv.itemconfig(txt[i], text=str(Money[i])) cv.update() clearCards() initCards() isReady1,isReady2 = True,False def Scores(pokers): f,p = [],[] for poker in pokers: f.append(F.index(poker[0])+1) p.append(V.index(poker[1])+2) t = sorted(p) intSame = len(set(t)) isFlush = int(len(set(f))==1) isStraight = t[0]+1==t[1]==t[2]-1 if intSame==1: return 500_0000+t[0] #豹子 elif intSame==2: #对子一样大比较剩下的单张 return (100+t[1])*10000+(t[2] if t[0]==t[1] else t[0]) else: #顺金(同花顺)顺子 else #单张或金花 Straight = 200_0000*(1+isFlush)+t[2] Flush = ((300*isFlush+t[2])*100+t[1])*100+t[0] return Straight if isStraight else Flush def Result(P): global cv,Pokers Pokers,Winner = [],[] for i in range(0,3*4,3): Pokers.append(P[i:i+3]) for i,p in enumerate(Pokers,1): win = Scores(p) idx = win//100_0000 print(f"Player{i}: {*p,} - {W[idx]}".replace('T','10')) Winner.append(win) win = max(Winner) #没有判断“一样大”,如是则谁在前谁为大 idx = Winner.index(win) big = win//10000 win = big//100 per = X[win] if win else Y[big-5] pok = W[win] if win else '单'+V[big-2] text1 = f"【Player{idx+1} win!】" text2 = f"{pok}{*Pokers[idx],} {per}%\n".replace('T','10') print(text1,'--> ',text2) cv.itemconfig(txt1, text=text1) cv.itemconfig(txt2, text=text2) Money[idx] += ONE*4 #每次赢ONE*3,多加自己的一份 for i in range(4): Money[i] -= ONE #多加的在此扣减 return P[3*4:] #去掉一局已发的牌 def Shuffle(): global isReady1 if isReady1: clearCards() initCards() showInfo('已重新洗牌,请发牌!') else: showInfo('还没开牌呢,请勿洗牌!')def showInfo(info): msg.showinfo(title='提示',message=info)def ExitApp(): if msg.askokcancel(title='确认',message='确定要退出吗?'): root.destroy() #关闭窗口退出程序if __name__ == '__main__': W = "单张","对子","顺子","金花","顺金","豹子" #牌型 X = 74.38, 16.94, 3.26, 4.96, 0.22, 0.24 #各牌型出现概率 Y = 0.54, 1.36, 2.44, 3.8, 5.43, 7.33, 9.5, 11.95, 14.66, 17.38 #单张概率 V = *(str(i) for i in range(2,10)),*'TJQKA' #T代表10 F = '♠', '♥', '♣', '♦' ALL, ONE = 1000, 200 #筹码初始值、单次输赢值 Money = [ALL]*4 #设置各方筹码初始值 '''Written by HannYang@CSDN, 2022.12.03''' root = tk.Tk() root.title('诈金花') root.geometry('1024x768') root.resizable(0,0) #禁止窗体改变大小 cv = tk.Canvas(root, width=1024, height=680, bg='darkgreen') cv.pack() Pokers = [] initCards() Cards = loadCards() isReady1,isReady2 = True,True #发牌、开牌的准备标记 cards = [[None]*3 for _ in range(4)] '''设置发牌区域''' x1, x2, x3, dx = 400, 180, 830, 105 y1, y2, y3 = 100, 550, 220 #调整坐标,使左右两家的牌横向显示 imgxy = [[(x1,y1),(x1+dx,y1),(x1+2*dx,y1)], [(x3,y3),(x3,y3+dx),(x3,y3+2*dx)], [(x1,y2),(x1+dx,y2),(x1+2*dx,y2)], [(x2,y3),(x2,y3+dx),(x2,y3+2*dx)]] btn,txt = [],[] for x,lst in enumerate(imgxy): for y,coord in enumerate(lst): cards[x][y] = cv.create_image(coord, image=Cards[x][0][0]) x1,y1,x2,y2 = coord[0]-50,coord[1]-50,coord[0]+50,coord[1]+50 if x%2: cv.create_rectangle(x1-25,y1,x2+25,y2) #纸牌外框 else: cv.create_rectangle(x1,y1-25,x2,y2+25) if x%2: tx,ty = coord[0]-25,coord[1]+65 #玩家、筹码的显示坐标 else: tx,ty = coord[0]-130,coord[1]+90 cv.create_text(tx,ty, text=f'Player{x+1}', fill='white') #玩家1-4显示文本框 txt.append(cv.create_text(tx+60,ty, fill='gold',text=Money[x])) #筹码显示框 '''设置显示每次开牌的胜者、牌型和出现概率的文本框''' txt1 = cv.create_text(510,300, fill='tomato', font=("宋体", 24)) txt2 = cv.create_text(510,360, fill='yellow', font=("宋体", 12)) '''设置命令按钮和菜单''' btnCmd = '发牌',dealCards,'开牌',playCards,'洗牌',Shuffle for i in range(3): btn.append(tk.Button(root,text=btnCmd[i*2],command=btnCmd[i*2+1],width=10)) btn[i].place(y=710, x=350+i*110) Menu = tk.Menu(root) menu = tk.Menu(Menu, tearoff = False) for t,cmd in zip(btnCmd[::2],btnCmd[1::2]): menu.add_radiobutton(label = t, command = cmd) menu.add_separator() #菜单分割线 menu.add_command(label = "退出", command = ExitApp) Menu.add_cascade(label="菜单",menu = menu) root.config(menu = Menu) '''''' root.mainloop()

运行结果:

相关推荐

相关文章