python连连看小游戏_python tkinter实现连连看游戏_张瑞骁的博客-程序员秘密

技术标签: python连连看小游戏  

这篇文章主要介绍了python tkinter实现连连看游戏的示例,帮助大家更好的理解和使用python,感兴趣的朋友可以了解下

需要自己添加图片素材呦

4f867f4a7cdda3fa1bca88d6d41e62ee.png

运行效果:

f651cf2cf18e6491a9717cf51a85873c.gif

完整代码

#!/usr/bin/env python

# -*- coding: utf-8 -*-

# @Date : 2017-10-02 15:19:24

# @Author : Salamander([email protected])

# @Link : http://51lucy.com

import os, random

import tkinter as tk

import tkinter.messagebox

from PIL import Image, ImageTk

class MainWindow():

__gameTitle = "连连看游戏"

__windowWidth = 700

__windowHeigth = 500

__icons = []

__gameSize = 10 # 游戏尺寸

__iconKind = __gameSize * __gameSize / 4 # 小图片种类数量

__iconWidth = 40

__iconHeight = 40

__map = [] # 游戏地图

__delta = 25

__isFirst = True

__isGameStart = False

__formerPoint = None

EMPTY = -1

NONE_LINK = 0

STRAIGHT_LINK = 1

ONE_CORNER_LINK = 2

TWO_CORNER_LINK = 3

def __init__(self):

self.root = tk.Tk()

self.root.title(self.__gameTitle)

self.centerWindow(self.__windowWidth, self.__windowHeigth)

self.root.minsize(460, 460)

self.__addComponets()

self.extractSmallIconList()

self.root.mainloop()

def __addComponets(self):

self.menubar = tk.Menu(self.root, bg="lightgrey", fg="black")

self.file_menu = tk.Menu(self.menubar, tearoff=0, bg="lightgrey", fg="black")

self.file_menu.add_command(label="新游戏", command=self.file_new, accelerator="Ctrl+N")

self.menubar.add_cascade(label="游戏", menu=self.file_menu)

self.root.configure(menu=self.menubar)

self.canvas = tk.Canvas(self.root, bg = 'white', width = 450, height = 450)

self.canvas.pack(side=tk.TOP, pady = 5)

self.canvas.bind('', self.clickCanvas)

def centerWindow(self, width, height):

screenwidth = self.root.winfo_screenwidth()

screenheight = self.root.winfo_screenheight()

size = '%dx%d+%d+%d' % (width, height, (screenwidth - width)/2, (screenheight - height)/2)

self.root.geometry(size)

def file_new(self, event=None):

self.iniMap()

self.drawMap()

self.__isGameStart = True

def clickCanvas(self, event):

if self.__isGameStart:

point = self.getInnerPoint(Point(event.x, event.y))

# 有效点击坐标

if point.isUserful() and not self.isEmptyInMap(point):

if self.__isFirst:

self.drawSelectedArea(point)

self.__isFirst= False

self.__formerPoint = point

else:

if self.__formerPoint.isEqual(point):

self.__isFirst = True

self.canvas.delete("rectRedOne")

else:

linkType = self.getLinkType(self.__formerPoint, point)

if linkType['type'] != self.NONE_LINK:

# TODO Animation

self.ClearLinkedBlocks(self.__formerPoint, point)

self.canvas.delete("rectRedOne")

self.__isFirst = True

if self.isGameEnd():

tk.messagebox.showinfo("You Win!", "Tip")

self.__isGameStart = False

else:

self.__formerPoint = point

self.canvas.delete("rectRedOne")

self.drawSelectedArea(point)

# 判断游戏是否结束

def isGameEnd(self):

for y in range(0, self.__gameSize):

for x in range(0, self.__gameSize):

if self.__map[y][x] != self.EMPTY:

return False

return True

'''

提取小头像数组

'''

def extractSmallIconList(self):

imageSouce = Image.open(r'images\NARUTO.png')

for index in range(0, int(self.__iconKind)):

region = imageSouce.crop((self.__iconWidth * index, 0,

self.__iconWidth * index + self.__iconWidth - 1, self.__iconHeight - 1))

self.__icons.append(ImageTk.PhotoImage(region))

'''

初始化地图 存值为0-24

'''

def iniMap(self):

self.__map = [] # 重置地图

tmpRecords = []

records = []

for i in range(0, int(self.__iconKind)):

for j in range(0, 4):

tmpRecords.append(i)

total = self.__gameSize * self.__gameSize

for x in range(0, total):

index = random.randint(0, total - x - 1)

records.append(tmpRecords[index])

del tmpRecords[index]

# 一维数组转为二维,y为高维度

for y in range(0, self.__gameSize):

for x in range(0, self.__gameSize):

if x == 0:

self.__map.append([])

self.__map[y].append(records[x + y * self.__gameSize])

'''

根据地图绘制图像

'''

def drawMap(self):

self.canvas.delete("all")

for y in range(0, self.__gameSize):

for x in range(0, self.__gameSize):

point = self.getOuterLeftTopPoint(Point(x, y))

im = self.canvas.create_image((point.x, point.y),

image=self.__icons[self.__map[y][x]], anchor='nw', tags = 'im%d%d' % (x, y))

'''

获取内部坐标对应矩形左上角顶点坐标

'''

def getOuterLeftTopPoint(self, point):

return Point(self.getX(point.x), self.getY(point.y))

'''

获取内部坐标对应矩形中心坐标

'''

def getOuterCenterPoint(self, point):

return Point(self.getX(point.x) + int(self.__iconWidth / 2),

self.getY(point.y) + int(self.__iconHeight / 2))

def getX(self, x):

return x * self.__iconWidth + self.__delta

def getY(self, y):

return y * self.__iconHeight + self.__delta

'''

获取内部坐标

'''

def getInnerPoint(self, point):

x = -1

y = -1

for i in range(0, self.__gameSize):

x1 = self.getX(i)

x2 = self.getX(i + 1)

if point.x >= x1 and point.x < x2:

x = i

for j in range(0, self.__gameSize):

j1 = self.getY(j)

j2 = self.getY(j + 1)

if point.y >= j1 and point.y < j2:

y = j

return Point(x, y)

'''

选择的区域变红,point为内部坐标

'''

def drawSelectedArea(self, point):

pointLT = self.getOuterLeftTopPoint(point)

pointRB = self.getOuterLeftTopPoint(Point(point.x + 1, point.y + 1))

self.canvas.create_rectangle(pointLT.x, pointLT.y,

pointRB.x - 1, pointRB.y - 1, outline = 'red', tags = "rectRedOne")

'''

消除连通的两个块

'''

def ClearLinkedBlocks(self, p1, p2):

self.__map[p1.y][p1.x] = self.EMPTY

self.__map[p2.y][p2.x] = self.EMPTY

self.canvas.delete('im%d%d' % (p1.x, p1.y))

self.canvas.delete('im%d%d' % (p2.x, p2.y))

'''

地图上该点是否为空

'''

def isEmptyInMap(self, point):

if self.__map[point.y][point.x] == self.EMPTY:

return True

else:

return False

'''

获取两个点连通类型

'''

def getLinkType(self, p1, p2):

# 首先判断两个方块中图片是否相同

if self.__map[p1.y][p1.x] != self.__map[p2.y][p2.x]:

return { 'type': self.NONE_LINK }

if self.isStraightLink(p1, p2):

return {

'type': self.STRAIGHT_LINK

}

res = self.isOneCornerLink(p1, p2)

if res:

return {

'type': self.ONE_CORNER_LINK,

'p1': res

}

res = self.isTwoCornerLink(p1, p2)

if res:

return {

'type': self.TWO_CORNER_LINK,

'p1': res['p1'],

'p2': res['p2']

}

return {

'type': self.NONE_LINK

}

'''

直连

'''

def isStraightLink(self, p1, p2):

start = -1

end = -1

# 水平

if p1.y == p2.y:

# 大小判断

if p2.x < p1.x:

start = p2.x

end = p1.x

else:

start = p1.x

end = p2.x

for x in range(start + 1, end):

if self.__map[p1.y][x] != self.EMPTY:

return False

return True

elif p1.x == p2.x:

if p1.y > p2.y:

start = p2.y

end = p1.y

else:

start = p1.y

end = p2.y

for y in range(start + 1, end):

if self.__map[y][p1.x] != self.EMPTY:

return False

return True

return False

def isOneCornerLink(self, p1, p2):

pointCorner = Point(p1.x, p2.y)

if self.isStraightLink(p1, pointCorner) and self.isStraightLink(pointCorner, p2) and self.isEmptyInMap(pointCorner):

return pointCorner

pointCorner = Point(p2.x, p1.y)

if self.isStraightLink(p1, pointCorner) and self.isStraightLink(pointCorner, p2) and self.isEmptyInMap(pointCorner):

return pointCorner

def isTwoCornerLink(self, p1, p2):

for y in range(-1, self.__gameSize + 1):

pointCorner1 = Point(p1.x, y)

pointCorner2 = Point(p2.x, y)

if y == p1.y or y == p2.y:

continue

if y == -1 or y == self.__gameSize:

if self.isStraightLink(p1, pointCorner1) and self.isStraightLink(pointCorner2, p2):

return {'p1': pointCorner1, 'p2': pointCorner2}

else:

if self.isStraightLink(p1, pointCorner1) and self.isStraightLink(pointCorner1, pointCorner2) and self.isStraightLink(pointCorner2, p2) and self.isEmptyInMap(pointCorner1) and self.isEmptyInMap(pointCorner2):

return {'p1': pointCorner1, 'p2': pointCorner2}

# 横向判断

for x in range(-1, self.__gameSize + 1):

pointCorner1 = Point(x, p1.y)

pointCorner2 = Point(x, p2.y)

if x == p1.x or x == p2.x:

continue

if x == -1 or x == self.__gameSize:

if self.isStraightLink(p1, pointCorner1) and self.isStraightLink(pointCorner2, p2):

return {'p1': pointCorner1, 'p2': pointCorner2}

else:

if self.isStraightLink(p1, pointCorner1) and self.isStraightLink(pointCorner1, pointCorner2) and self.isStraightLink(pointCorner2, p2) and self.isEmptyInMap(pointCorner1) and self.isEmptyInMap(pointCorner2):

return {'p1': pointCorner1, 'p2': pointCorner2}

class Point():

def __init__(self, x, y):

self.x = x

self.y = y

def isUserful(self):

if self.x >= 0 and self.y >= 0:

return True

else:

return False

'''

判断两个点是否相同

'''

def isEqual(self, point):

if self.x == point.x and self.y == point.y:

return True

else:

return False

'''

克隆一份对象

'''

def clone(self):

return Point(self.x, self.y)

'''

改为另一个对象

'''

def changeTo(self, point):

self.x = point.x

self.y = point.y

MainWindow()

以上就是python tkinter实现连连看游戏的详细内容,更多关于python tkinter连连看的资料请关注脚本之家其它相关文章!

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_34923852/article/details/113992485

智能推荐

Masonry介绍与使用实践:快速上手Autolayout_honey199396的博客-程序员秘密

前言1MagicNumber -> autoresizingMask -> autolayout以上是纯手写代码所经历的关于页面布局的三个时期在iphone1-iphone3gs时代 window的size固定为(320,480) 我们只需要简单计算一下相对位置就好了在iphone4-iphon

eclipse详细使用教程--2(java开发)_eclipse使用教程java_前端适配的博客-程序员秘密

前面的那一篇博客讲了怎么下载eclipse与创建Dynamic Web Project上一篇博客点击此处跳转这一篇主要将eclipse怎么创建Maven项目。maven项目与老的eclipse项目(也就是上篇博客讲的 Dynamic Web Project项目)的区别?maven项目其项目根路径会又一个 pom.xml文件,这个文件就是maven项目的核心,你的项目使用了那些jar包在po...

Spark基础学习(一)_gongrui_59的博客-程序员秘密

Spark核心概念 – RDD(弹性分布式数据集)1、分布在集群中的只读对象集合(由多个Partition构成) 2、可以存储在磁盘或是内存 3、通过并行“转换”构成 4、失效后自动重构基本操作 transformations 1、可以通过scala集合和hadoop数据集构成新的RDD 2、通过已有的RDD产生新的RDD action 3、通过RDD计算得到一个值或是一组值

Framework层的学习研究_linux framework层[email protected]的博客-程序员秘密

1.Framework的介绍Android的Framework是直接应用之下的一层,叫做应用程序框架层。这一层是核心应用程序所使用的API框架,为应用层提供各种API,提供各种组件和服务来支持我们的Android开发,包括ActivityManager,WindowManager,ViewSystem等。Android系统架构图:二、有什么Android Framework框架包含了3个...

Laxcus大数据管理系统2.0(14)- 后记_LAXCUS分布式操作系统的博客-程序员秘密

Laxcus是Laxcus大数据实验室全体系自主设计研发的多用户多集群大数据管理系统,支持一到百万台级节点,提供零至EB量级数据存储、计算能力,集运行、开发、部署、维护为一体的平台。现在已经在多地部署和投入运营。本文为最新的2.0版本,现逐段发表此文,与诸君共享我们的设计开发经验和体会。

整数拆分的两种解法(已完成)_dovebs的博客-程序员秘密

前几天在算法书上看到一个整数拆分的题目,觉得挺有意思,记录如下: 题目:给定一个整数n,输出这个整数拆分的可能总数例如:n==6有65+14+2    4+1+13+3    3+2+1     3+1+1+12+2+2     2+2+1+1        2+1+1+1+11+1+1+1+1+1共11种分解方法,所以输出应该为11。分析一拆分按照

随便推点

QString,QByteArray和QBitArray之间的转换(原创)_lbsljn的博客-程序员秘密

QString,QByteArray和QBitArray之间的转换(原创)1:QBitArray2QString :也可以转化为整型,测试程序: 测试输出结果是否和移位结果相同; QBitArray x; int bit; bit = 10; x.resize(32); x.fill(false); x.setBit(bit,true); QBitArray b; b = this->BitArrayInvert(x);

css样式--超出三个点,以及换行_css grid 元素超过三个自动换行_浊清。。。的博客-程序员秘密

1.超出一定宽度后,超出部分用 ...表示display: -webkit-box; /** 将对象作为伸缩盒子模型显示 **/-webkit-box-orient: vertical; /** 设置或检索伸缩盒对象的子元素的排列方式 **/-webkit-line-clamp: 2; /** 显示的行数,显示高度设置成行高,多余部分隐藏 **/ overflow: hidden; ...

NO.75——python解决倒水问题_倒水问题 图算法 python_one named slash的博客-程序员秘密

问题描述给你两个容器A和B,A的容量是3,B的容量是5。现在拿一个水壶可以向任意容器倒水,两个容器相互间也可以倒水,问经过多少步骤,可以使得B中盛有4升水?解题思路Initial State :(0,0)Oprations(算符):将杯子A的水倒空将杯子B的水倒空将杯子A装满水将杯子B装满水将杯子A的水倒入B,直至A的水被倒空将杯子A的水倒入B,直至B被倒满将杯子B的水倒入...

ElasticSearch 分页搜索[email protected]的博客-程序员秘密

之前的文章[ElasticSearch]搜索我们知道,我们的空搜索匹配到集群中的13个文档。 但是,命中数组中只有10个文档(文章只显示了2条数据,故意省略掉)。 我们如何查看其他文档呢?与SQL使用LIMIT关键字返回一个“页面”的结果数据相同,Elasticsearch接受from和size参数:size 表示应返回的结果数,默认为10from 表示应跳过的初始结果数,默认为0如果想每页显示五

python采集修改原创_Python采集伪原创发布一条龙,好奇心日报数据采集处理发布..._weixin_39874379的博客-程序员秘密

#好奇心日报采集import requestsimport reimport osglobal iimport urllib.parsei=1str1="多稀奇网站收集全球创意设计,精选好设计,精品设计创意,找寻好设计灵感,欣赏稀奇设计,个性设计,创意设计,尽在多稀奇网!"str2="多稀奇网不定时分享创意设计,给你更多设计创意灵感,欣赏更多稀奇个性潮流设计,多稀奇(www.duoxiqi.cn)...

7-vue-2_loveX001的博客-程序员秘密

[email protected]、设计目标不以解决实际业务痛点的更新都是耍流氓,下面我们来列举一下之前我们或许会面临的问题而 经过长达两三年时间的筹备,做了哪些事情?我们从结果反推一句话概述,就是更小更快更友好了更小更快主要体现在编译方面:更友好在兼顾的的同时还推出了,大大增加了代码的逻辑组织和代码复用能力这里代码简单演示下:存在一个获取鼠标位置的函数我们只需要调用这个函数,即可获取、的坐标,完全不用关注实现过程试想一下,如果很多类似的第三方库,我们只需要调用即可,不必关注实现过程,开发效率