本项目是利用python中的Tkinter模块来制作一个可视化的“21点纸牌游戏”
1.基本游戏规则
- 游戏共有两个玩家:电脑和人类,电脑坐庄。
- 游戏开始时,先给人类和电脑分别发两种牌作为底牌,其中庄家仅露出一张牌。
- 判断双方是否直接为21点,如果其中一方为21点,则直接判该方胜利,在该方总分上加一分。如果双方都是21点,则为平局,双方都不得分。
- 当初始牌面都没有21点时,人类玩家根据自己牌面决定是否继续要牌。若要牌,则在牌堆中抽出一张,然后再次判断胜负。如果人类牌面的总数超过21点,则直接判输。
- 如果人类玩家停止要牌,并且在人类没有因为超过21点而被判输的情况下,电脑开始要牌。电脑要牌的规则是:电脑一直要牌,知道比人类玩家大才停止。
- 循环4和5的步骤。
- 完成一轮游戏后,由人类玩家决定,是否继续玩下一轮
2. 游戏计分规则
- 2、3、4、5、6、7、8、9、10分别是正常的分数
- J、Q、K都是10点
- A的计分比较复杂:首先将A记为1分,若牌面总分小于21分,将A记为11分再算一次,若这个时候仍然小于21,则将A按照11分算;若总分大于了21分,则将A计为1分。
3.代码实现
import os
import tkinter as tk
from PIL import Image,ImageTk
from random import shuffle
import random
import numpy as np
from tkinter import messagebox
win = tk.Tk()
win.title("21点纸牌游戏")
class Poker:
def __init__(self,height=720,width=1280):
self.height = height
self.width = width
self.people_poker_list = []
self.computer_poker_list = []
self.people_hand_poker = []
self.computer_hand_poker = []
self.poker_list = []
self.people_score = 0
self.computer_score = 0
self.total_score = np.array([0,0])
self.game_round = 0
self.playing_card = self.make_cards("pokerImage")
self.cv = tk.Canvas(win, height=self.height, width=self.width)
self.desk = Image.open("desk.png")
self.background_image = ImageTk.PhotoImage(self.desk)
self.cv.create_image(0,0,image=self.background_image,anchor=tk.NW)
self.cv.pack()
self.every_round()
self.start()
def make_cards(self,file_dir):
# 读取文件夹中的纸牌文件名,并将文件名和分值构建成一个字典
imgs_name = {}
for img_name in os.listdir(r"./" + file_dir):
if img_name.split(".")[1] == 'jpg':
if int(img_name.split(".")[0][1:3]) < 11:
imgs_name[img_name.split(".")[0]] = int(img_name.split(".")[0][1:3])
else:
imgs_name[img_name.split(".")[0]] = 10
return imgs_name
def cards_name(self, poker_count=1):
# 获取纸牌图片的文件名称
poker_name = list(self.playing_card.keys())
return poker_name*poker_count
def random_cards(self):
# 洗牌,对扑克牌进行随机排列
shuffle(self.poker_list)
def start_game_get_two_poker(self):
# 初始化,给电脑和玩家分别发两张牌
return [self.poker_list.pop(random.randint(0, len(self.poker_list) - 1)),
self.poker_list.pop(random.randint(0, len(self.poker_list) - 1))]
def read_img(self,hand_poker_list):
# 由于tkinter要求图片格式为gif,因此利用ImageTK模块对手中纸牌图片进行格式转换
img_list = []
for i in range(len(hand_poker_list)):
file_name = "./pokerImage/" + hand_poker_list[i] + ".jpg"
card_img = Image.open(file_name)
img_list.append(ImageTk.PhotoImage(card_img))
return img_list
def get_one_poker(self):
# 从随机纸牌序列中抽取一张牌
return self.poker_list.pop(random.randint(0, len(self.poker_list) - 1))
def score_count(self,hand_poker):
# 计算手中的牌的分数
poker_score = 0
have_a = False
for k in hand_poker:
poker_score += self.playing_card[k]
for i in hand_poker:
if i[1:] == '01':
have_a = True
break
else:
continue
if have_a == True:
if poker_score + 10 <= 21:
poker_score = poker_score + 10
return poker_score
def who_win(self,people_score, computer_score):
# 判断每一局牌的输赢
if people_score > 21 and computer_score > 21:
self.disabled_button()
messagebox.showinfo(title="牌局结果", message="平局了!!!")
self.total_score = np.add(self.total_score,np.array([0,0]))
self.score_board()
elif people_score > 21 and computer_score <= 21:
self.disabled_button()
messagebox.showinfo(title="牌局结果", message="对不起,您输了!!!")
self.total_score = np.add(self.total_score, np.array([0, 1]))
self.score_board()
elif people_score <= 21 and computer_score > 21:
self.disabled_button()
messagebox.showinfo(title="牌局结果", message="恭喜,您赢了!!!")
self.total_score = np.add(self.total_score, np.array([1, 0]))
self.score_board()
elif people_score <= 21 and computer_score <= 21:
if people_score < computer_score:
self.disabled_button()
messagebox.showinfo(title="牌局结果", message="对不起,您输了!!!")
self.total_score = np.add(self.total_score, np.array([0, 1]))
self.score_board()
elif people_score > computer_score:
self.disabled_button()
messagebox.showinfo(title="牌局结果", message="恭喜,您赢了!!!")
self.total_score = np.add(self.total_score, np.array([1, 0]))
self.score_board()
else:
self.disabled_button()
messagebox.showinfo(title="牌局结果", message="平局了!!!")
self.total_score = np.add(self.total_score, np.array([0, 0]))
self.score_board()
def disabled_button(self):
# 将要牌与不要两个按钮转变为灰色
self.yes_button['state'] = 'disabled'
self.no_button['state'] = 'disabled'
def score_board(self):
# 分数显示牌
self.round_label = tk.Label(self.cv, text="第 " + str(self.game_round) + " 局", height=1, width=21,
font=("微软雅黑", 20), fg="#00ff00", bg="#cccccc")
self.round_label.place(relx=0.75, rely=0.04)
self.score_label = tk.Label(self.cv,
text="目前比分: 玩家" + str(self.total_score[0]) + " : " + str(
self.total_score[1]) + "庄家",
height=1, width=18, font=("兰亭黑-简 中黑", 20), fg="#339900", bg="#cccccc")
self.score_label.place(relx=0.75, rely=0.08)
def hit_no(self):
# 不要牌按钮及其响应事件
if self.people_score > 21 and self.computer_score <= 21:
# self.score = self.who_win(self.people_score, self.computer_score)
return self.who_win(self.people_score, self.computer_score)
elif self.people_score <= 21 and self.computer_score >= 21:
# self.score = self.who_win(self.people_score, self.computer_score)
return self.who_win(self.people_score, self.computer_score)
elif self.people_score <= 21 and self.computer_score < 21:
while self.computer_score <= self.people_score:
self.computer_hand_poker.append(self.get_one_poker())
self.computer_score = self.score_count(self.computer_hand_poker)
computer_hand_num = len(self.computer_hand_poker)
self.computer_poker_list = self.read_img(self.computer_hand_poker)
for k in range(computer_hand_num):
self.computer_cv = self.cv.create_image(650 - (105 + 20 * computer_hand_num) / 2 + 20 * k, 215,image=self.computer_poker_list[k], anchor=tk.NW)
self.cv.update()
# self.score = self.who_win(self.people_score,self.computer_score)
return self.who_win(self.people_score, self.computer_score)
def hit_yes(self):
# 要牌按钮及其响应事件
print("poker_list:{}".format(self.poker_list))
self.people_hand_poker.append(self.get_one_poker())
people_hand_num = len(self.people_hand_poker)
self.people_poker_list = self.read_img(self.people_hand_poker)
for i in range(people_hand_num):
self.people_cv = self.cv.create_image(650 - (105 + 20 * people_hand_num) / 2 + 20 * i, 485,image=self.people_poker_list[i], anchor=tk.NW)
self.cv.update()
self.people_score = self.score_count(self.people_hand_poker)
if self.people_score > 21:
messagebox.showinfo(title="⚠️警告",message="您手里的牌已经超过21点!")
# self.score = self.who_win(self.people_score, self.computer_score)
return self.who_win(self.people_score, self.computer_score)
def every_round(self):
# 每一轮牌
self.poker_list = self.cards_name()
self.random_cards()
print(self.poker_list)
self.people_hand_poker = []
self.computer_hand_poker = []
self.people_poker_list = []
self.computer_poker_list = []
self.people_score = 0
self.computer_score = 0
# self.score = 0
self.game_round += 1
self.score_board()
self.people_init_poker = self.start_game_get_two_poker()
self.computer_init_poker = self.start_game_get_two_poker()
self.people_hand_poker.extend(self.people_init_poker)
print("people_hand_poker:{}".format(self.people_hand_poker))
self.people_score = self.score_count(self.people_hand_poker)
self.computer_hand_poker.extend(self.computer_init_poker)
print("computer_hand_poker:.{}".format(self.computer_hand_poker))
self.computer_score = self.score_count(self.computer_hand_poker)
self.people_poker_list = self.read_img(self.people_hand_poker)
self.computer_poker_list = self.read_img(self.computer_hand_poker)
people_hand_num = len(self.people_hand_poker)
for i in range(people_hand_num):
print("显示玩家的牌")
self.people_cv = self.cv.create_image(650 - (105 + 20 * people_hand_num) / 2 + 20 * i, 485,image=self.people_poker_list[i], anchor=tk.NW)
computer_hand_num = len(self.computer_hand_poker)
for k in range(computer_hand_num):
print("显示电脑的牌")
self.computer_cv = self.cv.create_image(650-(105+20*computer_hand_num)/2+20*k,215,image=self.computer_poker_list[k],anchor=tk.NW)
if self.people_score == 21 or self.computer_score == 21:
messagebox.showinfo(title="⚠️警告",message="初始化牌面分数有21点!")
return self.who_win(self.people_score, self.computer_score)
else:
if self.people_score <= 21:
self.yes_button = tk.Button(self.cv, text="要 牌", bg='grey', fg='red', font=('微软雅黑', 16),
command=self.hit_yes)
self.yes_button.place(relx=0.45, rely=0.61, height=30, width=50)
self.no_button = tk.Button(self.cv, text='不 要', bg='grey', fg='red', font=('微软雅黑', 16),
command=self.hit_no)
self.no_button.place(relx=0.52, rely=0.61, height=30, width=50)
def restart(self):
# 点击再来一局后的响应
self.cv.delete(self.people_cv)
self.cv.delete(self.computer_cv)
self.every_round()
def start(self):
# 再来一局按钮及其响应事件
self.start_button = tk.Button(self.cv, text="再玩一次", bg='grey', fg='red',
font=('微软雅黑 Bold', 20),
command=self.restart)
self.start_button.place(relx=0.85, rely=0.9, height=40, width=100)
poker = Poker()
win.mainloop()
游戏运行结果如下图: