Python开源项目之蜘蛛纸牌
目录
- 概述
- 特色
- 功能演示
- 详细说明
- CardSuit(纸牌花色枚举)
- Card(纸牌类)
- SpiderSolitaire(蜘蛛纸牌类)
- 常量
- 抽象数据结构(ADT)
- 翻牌的实现
- 纸牌移动的实现
- buttone1Press()
- button1Motion()
- button1Release()
概述
使用Python语言开发的蜘蛛纸牌游戏, 与蜘蛛纸牌游戏的功能基本一致(目前缺少"撤销"操作, 后续可能会添加).
代码可从我的资源下载, 该资源为付费资源(!!创作不易, 敬请谅解!!)
特色
- 界面基于
tkinter
模块; - 支持游戏的保存和导入;
- 纸牌的移动和发牌通过鼠标操作.
功能演示
- 移动纸牌演示:
- 发牌演示
- 保存与导入演示.
详细说明
CardSuit(纸牌花色枚举)
CardSuit
枚举类用于表示纸牌的花色, 分别为: 红桃(Hearts
), 黑桃(Spades
), 方片(Diamonds
), 梅花(Clubs
). 目前游戏只用到了黑桃. 后续可以扩充为使用 两种花色 和 四种花色.
class CardSuit(Enum):Hearts = 0Spades = 1Diamonds = 2,Clubs = 3
Card(纸牌类)
Card
类用于表示纸牌. 纸牌的属性包括:
- 点数(
points: int
), - 花色(
suit: CardSuit
), - 是否正面朝上(
isfront: bool
), - 在
canvas
中对应的项目ID - 正面图像(
_imfront: ImageTk.PhotoImage
), - 反面图像(
_imback: ImageTk.PhotoImage
)
image()
方法用于返回要显示的图像. isfront==True
时, 返回正面图像, 否则返回反面图像.
class Card:def __init__(self, points: int, suit: CardSuit, imfront: ImageTk.PhotoImage, imback: ImageTk.PhotoImage,isfront: bool = False) -> None:self.points = pointsself.suit = suitself._imfront = imfrontself._imback = imbackself.isfront = isfrontself.itemId = Nonedef image(self):if self.isfront:return self._imfrontelse:return self._imback...
SpiderSolitaire(蜘蛛纸牌类)
SpiderSolitaire
为蜘蛛纸牌类, 包含整个游戏的界面的显示, 事件响应, 游戏逻辑等.
SpiderSolitaire
类继承自Mainwindow
.
class SpiderSolitaire(Mainwindow):"""蜘蛛纸牌"""def __init__(self, master: Tk, **kw):super().__init__(master, **kw)self.createMenu()self.canvas = Canvas(self.mainframe, width=CANVAS_WIDTH, height=CANVAS_HEIGHT, background='gray55')self.canvas.grid(row=0, column=0, sticky=NS)... # set window's title.self.master.title('Spider Solitaire')# set window's geometry sizeself.master.geometry(f'{CANVAS_WIDTH+10}x{CANVAS_HEIGHT+10}')self.showmessage('Ready.')
常量
以下常量在SpiderSolitaire
类中被用到.
# 纸牌的宽度和高度
CARD_WIDTH = 68
CARD_HEIGHT = 103# 列宽. COL_WIDTH > CARD_WIDTH
COL_WIDTH = 90
# 行宽
ROW_WIDTH = 25# 左侧空白宽度
COL_PAD = (COL_WIDTH - CARD_WIDTH) // 2# 列数
COL_NUM = 10
# 待发牌堆数, 每堆 COL_NUM 张牌
HEAP_NUM = 5# 牌的组数. 牌的总数为: PACK_NUM * 13
PACK_NUM = 8# 右下角牌堆显示的宽度
HEAP_WIDTH = 20
# 待发牌堆的水平偏移和垂直偏移
HEAP_OS_H = COL_WIDTH*COL_NUM - HEAP_WIDTH * HEAP_NUM - CARD_WIDTH
HEAP_OS_V = ROW_WIDTH * 25# 显示文字的水平偏移和垂直偏移
TEXT_OS_H = COL_WIDTH*COL_NUM//2
TEXT_OS_V = ROW_WIDTH * 25 + CARD_HEIGHT//2# CANVAS的宽高
CANVAS_WIDTH = COL_WIDTH*COL_NUM
CANVAS_HEIGHT = HEAP_OS_V + CARD_HEIGHT + 25
抽象数据结构(ADT)
- 纸牌队列
游戏界面中每一列纸牌(card_queue
), 用一个列表(list
)表示. 列表元素为Card
. 所有纸牌列用一个列表(list
)表示.
class SpiderSolitaire(Mainwindow):...def start(self):...self.card_queues = [[] for k in range(COL_NUM)]while len(cards) > 0:for k in range(COL_NUM):self.card_queues[k].append(cards.pop())if len(cards) <= 0:break
- 待发纸牌
待发纸牌(card_heaps
)分成5组, 每组10张(对应纸牌的列数). 每组纸牌(card_heap
)用一个列表(list
)表示, 所有待发的纸牌构成一个列表(list
)
class SpiderSolitaire(Mainwindow):...def start(self):...self.card_heaps = []for k in range(HEAP_NUM):self.card_heaps.append([cards.pop() for i in range(COL_NUM)])
- 分数
分数(score
)用int
表示, 初始分数为500, 每移动一组纸牌, 分数-1. 完成一组序列(从"K"到"A"连续递减), 分数+100. - 操作计数
操作计数(moves
)用int
表示, 初始为0, 每移动一组纸牌, 操作计数+1.
翻牌的实现
每一张在纸牌队列和待发纸牌中的纸牌, 在canvas
中都对应一个image
项, 该项通过调用self.canvas.create_image()
创建.
翻牌动作通过删除该纸牌对应的image
项( self.canvas.delete(card.itemId)
), 然后创建新的image
项实现.
def flopTop(self, col: int):"""翻最上面的一张牌"""if len(self.card_queues[col]) == 0:return Falsecard: Card = self.card_queues[col][-1]card.isfront = Trueself.canvas.delete(card.itemId)card.itemId = self.canvas.create_image(self.col_from*COL_WIDTH+COL_PAD, (len(self.card_queues[self.col_from])-1)*ROW_WIDTH, image=card.image(), anchor='nw')return True
纸牌移动的实现
- 纸牌的移动用到了鼠标左键的"按下(
<ButtonPress-1>
)", “拖动(<B1-Motion>
)”, "释放(<ButtonRelease-1>
)"三个预定义事件.分别绑定self.buttone1Press()
,self.button1Motion()
,self.button1Release()
三个函数.
class SpiderSolitaire(Mainwindow):def __init__(self, master: Tk, **kw):...self.canvas.bind("<ButtonPress-1>", self.buttone1Press)self.canvas.bind("<ButtonRelease-1>", self.button1Release)self.canvas.bind("<B1-Motion>", self.button1Motion)
buttone1Press()
- 在
buttone1Press()
函数中, 获取当前点击的纸牌(card
)所在的行和列, 并判断该纸牌是否正面朝上(card.isfront == True
), 且其上的所有要移动的纸牌(self.select_cards
)是否满足连续递减的条件 (该函数同时需要判断点击区域是否为待发牌区域). - 因为
Canvas
中的所有项目是按照创建先后进行堆叠的, 如果只是单纯移动项目的位置, 可能导致意想不到的遮盖混乱. 因此需要调用self.canvas.lift(card.itemId)
函数, 将要移动的纸牌的堆叠顺序,移动到最上层. - 因为可能出现移动失败的情况(移动到的列跟移动的纸牌不能衔接, 或者将移动头纸牌的点数不是13的纸牌放置到空列, 则移动失败), 因此需要保存移动的起始列(
self.col_from
) - 为了在
button1Motion()
函数中, 纸牌能够跟着鼠标移动, 需要保存移动纸牌与鼠标的相对位置(self.offset_x
,self.offset_y
)
def selectCheck(self, col: int, row: int):card_queue = self.card_queues[col]if card_queue[row].isfront == False:return Falsefor i in range(row+1, len(card_queue)):if card_queue[i-1].points - card_queue[i].points != 1:return Falsereturn True....def buttone1Press(self, event):"""鼠标左键按下事件.判断选中的卡片. 或者发牌."""# 发牌if event.x >= HEAP_OS_H and event.y >= HEAP_OS_V:self.dealCard()col = (event.x - COL_PAD) // COL_WIDTHrow = event.y // ROW_WIDTHself.offset_x = event.x - col * COL_WIDTH + COL_PADself.offset_y = event.y - row * ROW_WIDTHqueue_len = len(self.card_queues[col])if row >= queue_len:if event.y < (queue_len - 1) * ROW_WIDTH + CARD_HEIGHT:row = queue_len - 1else:returnif self.selectCheck(col, row) == False:self.select_cards = []returnself.select_cards = self.card_queues[col][row:]for card in self.select_cards:card: Cardself.canvas.lift(card.itemId)self.col_from = coldel self.card_queues[col][row:]
button1Motion()
button1Motion()
函数的功能很简单, 只要调用self.canvas.coords()
修改所有要移动的纸牌(self.select_cards
)的坐标值即可
def button1Motion(self, event):col = event.x // COL_WIDTHfor row, card in enumerate(self.select_cards):self.canvas.coords(card.itemId, event.x - self.offset_x, event.y - self.offset_y + row * ROW_WIDTH)
button1Release()
button1Release()
函数是纸牌移动的最终过程, 需要判断移动是否符合条件;- 如果移动成功, 将移动的纸牌添加到该列纸牌的末尾, 并翻转移动纸牌的起始列的最上面的一张牌;
- 如果移动失败, 将移动的纸牌归还给起始列;
- 同时, 需要判断是否构成收牌条件(从"K"到"A"依次递减), 如果符合条件, 需要删除响应的纸牌, 修改分数.
def button1Release(self, event):if len(self.select_cards) == 0:returncol = event.x // COL_WIDTHif self.moveCheck(col) == False:col = self.col_fromfor row, card in enumerate(self.select_cards, len(self.card_queues[col])):self.canvas.coords(card.itemId, col * COL_WIDTH + COL_PAD, row * ROW_WIDTH)self.card_queues[col].extend(self.select_cards)self.select_cards.clear()self.moves += 1self.score -= 1self.canvas.itemconfig(self.text_item, text=f'分数: {self.score}\n操作: {self.moves}')ok = self.tryTakeup(col)if ok:self.flopTop(col)if col != self.col_from:# 翻转最后一张牌if len(self.card_queues[self.col_from]) > 0:self.flopTop(self.col_from)
全部代码请从我的资源下载, 该资源为付费资源(!!创作不易, 敬请谅解!!)
Python开源项目之蜘蛛纸牌相关推荐
- GitHub上的“金矿”(236个Python开源项目,涵盖了15个领域)
人生苦短,越来越多的人,都开始用Python了. 但寻找好的项目资源,费时又费力,成了头号难题. 现在,好消息来了.最近,有人在GitHub上放了一座"金矿". 目前里面有236个 ...
- python开源库推荐_推荐5个值得关注的Python开源项目
原标题:推荐5个值得关注的Python开源项目 今天小编看到了五个开源项目,觉得还错,推荐给大家. 1.Wagtail CMS Wagtail是一个基于Django的CMS系统 它拥有优质的用户体验 ...
- python开源项目贡献_通过为开源项目做贡献,我如何找到理想的工作
python开源项目贡献 by Utsab Saha 由Utsab Saha 通过为开源项目做贡献,我如何找到理想的工作 (How I found my dream job by contributi ...
- 9月Python开源项目Top10
原文链接: 9月Python开源项目Top10 - TinyMind https://www.tinymind.cn/articles/3776 声明:转载的, 就是让自己记住,以后熟练了Python ...
- 近万个Python开源项目中精选Top34!
作者 | Mybridge 编译 | 仲培艺 出品 | CSDN(ID:CSDNNews) [导语]踏着人工智能.区块链的东风,近年来一路"横冲直撞"的 Python 在实现了从小 ...
- 2018年Python开源项目Top100!只在这里!
整理 | Jane 出品 | Python大本营 2018 年的最后一天,营长为大家新鲜出炉了一份 2018 年 Python 开源项目 Top100 清单!这些项目都是营长每月通过收集 Mybrid ...
- 精选180+Python开源项目,随你选!做项目何愁没代码
编辑 | Jane 出品 | Python大本营 每一位程序员,每天大部分时间都是在和代码打交道.但是对于广大的普通用户来说,最重要的不是代码,而是代码最终生成的应用程序.但是,每个项目都从头开始自己 ...
- 精选Python开源项目Top10!
作者 | MyBridge 译者 | Linstancy 整理 | Jane 出品 | AI科技大本营 [导读]过去一个月里,我们对近 250 个 Python 开源项目进行了排名,并挑选出热度前 1 ...
- 8月精选Python开源项目Top10
作者 | Mybridge 译者 | linstancy 编辑 | Jane 出品 | AI科技大本营 [导读]过去一个月里,我们对近 250 个 Python 开源项目进行了排名,并挑选出热度前 1 ...
最新文章
- 工作5年才有自己博客...汗...
- 在命令行导出MySQL数据到Excel
- c语言回文串判定代码_C语言编写一个程序,判断输入的一个字符串是否是回文。...
- bzoj 2878 [Noi2012]迷失游乐园——树上的期望dp
- 【整理】RPA选择器针对SAP系统的设置
- Python自学——python的常用模块
- Xml的编码和Bom
- 安装VCSA6.7(vCenter Server Appliance 6.7) 2019.7.9
- caffe 源码阅读与运行流程
- YUI 3:Node
- win7科学计算机不支持,win7“不支持的硬件,你的电脑使用的处理器专为最新版win...
- 04.使用元字符 (Python)
- Excel实战 第1章 数据处理
- 你今天因为 YYYY-MM-dd 被提 BUG 了吗?
- 无论你英语多差,只要想学,看了此文必有改变
- MGRE结合OSPF(超详解)
- 设置git使用vimdiff比较差异
- 6.4.1等价关系2
- MySQL中 (GROUP BY 用法)和(ORDER BY用法)
- 梦想照进现实:挣扎中的国产操作系统