python实现简单俄罗斯方块


Posted in Python onMarch 13, 2020

本文实例为大家分享了python实现俄罗斯方块的具体代码,供大家参考,具体内容如下

# teris.py
# A module for game teris.
# By programmer FYJ

from tkinter import *
from time import sleep
from random import *
from tkinter import messagebox


class Teris:
  def __init__(self):
    #方块颜色列表
    self.color = ['red','orange','yellow','purple','blue','green','pink']
    # Set a core squre and any shape can be drawn by the relative location.
    #字典 存储形状对应7种形状 元组存储坐标
    self.shapeDict = {1:[(0,0),(0,-1),(0,-2),(0,1)], # shape I
              2:[(0,0),(0,-1),(1,-1),(1,0)], # shape O 
              3:[(0,0),(-1,0),(0,-1),(1,0)], # shape T T型
              4:[(0,0),(0,-1),(1,0),(2,0)], # shape J 右长倒L盖子
              5:[(0,0),(0,-1),(-1,0),(-2,0)], # shape L
              6:[(0,0),(0,-1),(-1,-1),(1,0)], # shape Z
              7:[(0,0),(-1,0),(0,-1),(1,-1)]} # shape S
    #旋转坐标控制
    self.rotateDict = {(0,0):(0,0),(0,1):(-1,0),(0,2):(-2,0),(0,-1):(1,0),
              (0,-2):(2,0),(1,0):(0,1),(2,0):(0,2),(-1,0):(0,-1),
              (-2,0):(0,-2),(1,1):(-1,1),(-1,1):(-1,-1),
              (-1,-1):(1,-1),(1,-1):(1,1)}
    # 初始高度,宽度 核心块位置
    self.coreLocation = [4,-2]
    self.height,self.width = 20,10
    self.size = 32
    # Map can record the location of every square.i宽 j高
    self.map = {}
    #全部置0
    for i in range(self.width):
      for j in range(-4,self.height):
        self.map[(i,j)] = 0
    #添加边界
    for i in range(-4,self.width+4):
      self.map[(i,self.height)] = 1
    for j in range(-4,self.height+4):
      for i in range(-4,0):
        self.map[(i,j)] = 1
    for j in range(-4,self.height+4):
      for i in range(self.width,self.width+4):
        self.map[(i,j)] = 1

    # 初始化分数0 默认不加快 按下时加快
    self.score = 0
    self.isFaster = False
    # 创建GUI界面
    self.root = Tk()
    self.root.title("Teris")
    self.root.geometry("500x645")
    self.area = Canvas(self.root,width=320,height=640,bg='white')
    self.area.grid(row=2)
    self.pauseBut = Button(self.root,text="Pause",height=2,width=13,font=(18),command=self.isPause)
    self.pauseBut.place(x=340,y=100)
    self.startBut = Button(self.root,text="Start",height=2,width=13,font=(18),command=self.play)
    self.startBut.place(x=340,y=20)
    self.restartBut = Button(self.root,text="Restart",height=2,width=13,font=(18),command=self.isRestart)
    self.restartBut.place(x=340,y=180)
    self.quitBut = Button(self.root,text="Quit",height=2,width=13,font=(18),command=self.isQuit)
    self.quitBut.place(x=340,y=260)
    self.scoreLabel1 = Label(self.root,text="Score:",font=(24))
    self.scoreLabel1.place(x=340,y=600)
    self.scoreLabel2 = Label(self.root,text="0",fg='red',font=(24))
    self.scoreLabel2.place(x=410,y=600)
    #按键交互 
    self.area.bind("<Up>",self.rotate)
    self.area.bind("<Left>",self.moveLeft)
    self.area.bind("<Right>",self.moveRight)
    self.area.bind("<Down>",self.moveFaster)
    self.area.bind("<Key-w>",self.rotate)
    self.area.bind("<Key-a>",self.moveLeft)
    self.area.bind("<Key-d>",self.moveRight)
    self.area.bind("<Key-s>",self.moveFaster)
    self.area.focus_set()
    #菜单
    self.menu = Menu(self.root)
    self.root.config(menu=self.menu)
    self.startMenu = Menu(self.menu)
    self.menu.add_cascade(label='Start',menu=self.startMenu)
    self.startMenu.add_command(label='New Game',command=self.isRestart)
    self.startMenu.add_separator()
    self.startMenu.add_command(label='Continue',command=self.play)
    self.exitMenu = Menu(self.menu)
    self.menu.add_cascade(label='Exit',command=self.isQuit)
    self.helpMenu = Menu(self.root)
    self.menu.add_cascade(label='Help',menu=self.helpMenu)
    self.helpMenu.add_command(label='How to play',command=self.rule)
    self.helpMenu.add_separator()
    self.helpMenu.add_command(label='About...',command=self.about)

  #先将核心块的所在位置在map中的元素设为1,通过self.shapeDict获取其余方块位置,将map中对应元素设为1。
  def getLocation(self):
    map[(core[0],core[1])] = 1
    for i in range(4):
      map[((core[0]+getNew[i][0]),
         (core[1]+getNew[i][1]))]=1

  #判断方块下移一格后对应位置map中的元素是否为一,是,则不可移动,返回False;否,可以移动,返回True。
  def canMove(self):
    for i in range(4):
      if map[(core[0]+getNew[i][0]),(core[1]+1+getNew[i][1])] == 1:
        return False
    return True

  # 先用randRange获取1~7中的随机整数,随机到某一整数,那么访问self.shapeDict,获取这种形状方块的核心块及其他方块的相对位置。
  # 访问颜色字典,获取此方块的颜色。建立循环,当方块可移动时(while self. canMove():),且暂停键未被摁下(if isPause:),
  # 核心块纵坐标加一,根据核心块及其他方块对于核心块的相对位置,画出四个方块。用self.getLocation()函数获取方块的位置。
  def drawNew(self):
    global next
    global getNew
    global core
    next = randrange(1,8)
    #形状
    self.getNew = self.shapeDict[next]
    getNew = self.getNew
    core = [4,-2]
    time = 0.2
    while self.canMove():
      if isPause:
        core[1] += 1
        self.drawSquare()
        if self.isFaster:
          sleep(time-0.15)
        else:
          sleep(time+0.22)
        self.isFaster = False  
      else:
        self.drawSquare()
        sleep(time)
    self.getLocation()

  # 绘制当前方块
  def drawSquare(self):
    self.area.delete("new")
    for i in range(4):
      self.area.create_rectangle((core[0]+self.getNew[i][0])*self.size,
                    (core[1]+self.getNew[i][1])*self.size,
                    (core[0]+self.getNew[i][0]+1)*self.size,
                    (core[1]+self.getNew[i][1]+1)*self.size,
                    fill=self.color[next-1],tags="new")
    self.area.update()
    

  # 给底部每行中方块都加上标签:bottom + str(j), j代表该块所在行数,每次遍历map,建立对于range(self. height)的for循环,删去每一行,
  # 若map什么地方的元素为1,画出这一位置的方块,不断更新。这样可以画出底部方块。
  def drawBottom(self):
    for j in range(self.height):
      self.area.delete('bottom'+str(j))
      for i in range(self.width):
        if map[(i,j)] == 1:
          self.area.create_rectangle(self.size*i,self.size*j,self.size*(i+1),
                        self.size*(j+1),fill='grey',tags='bottom'+str(j))    
      self.area.update()
        
  # 判断填满遍历map每一行的各个元素,若所有元素为1,则标签中score值+10,将
  # 此行所有元素改为0,行数map(i,j)=map(i-1,j)(即所有之上的行下移)
  # ,那么后续画底部方块时,可实现消行。
  def isFill(self):
    for j in range(self.height):
      t = 0
      for i in range(self.width):
        if map[(i,j)] == 1:
          t = t + 1
      if t == self.width:
        self.getScore()
        self.deleteLine(j)

  # 加分
  def getScore(self):
    scoreValue = eval(self.scoreLabel2['text'])
    scoreValue += 10
    self.scoreLabel2.config(text=str(scoreValue))

  # 消行
  def deleteLine(self,j):
    for t in range(j,2,-1):
      for i in range(self.width):
        map[(i,t)] = map[(i,t-1)]
    for i in range(self.width):
      map[(i,0)] = 0
    self.drawBottom()
        

  # 遍历每一行,若从顶部到底部map每一行都有某一个元素或更多元素为1,
  # 那么说明方块以顶到最上端,游戏结束。此处不可以简单判定最上一行是否有元素为1就判定结束,
  # 若这样会产生顶部有新的方块产生,然后导致顶部有元素为1,误判为游戏结束。
  def isOver(self):
    t = 0
    for j in range(self.height):
      for i in range(self.width):
        if self.map[(i,j)] == 1:
          t += 1
          break
    if t >= self.height:
      return False
    else:
      return True

  # 先判断方块是否可以旋转(针对其靠近边界时)。先将其现在所在位置对应map中的元素改为0,判断其旋
  # 转后位置对应map中的元素是否有一,若有,说明其旋转后的位置已经被占,是不能旋转的,返回值为False
  # 。否则为可旋转,返回值True。若已判定可以旋转,那么访问self.rotateDict,得出旋转以后所有小块的位置
  # 变换,将变换以后的位置对应map的元素设为1,旋转便已完成。
  def canRotate(self):
    for i in range(4):
      map[((core[0]+getNew[i][0]),
        (core[1]+getNew[i][1]))] = 0
    for i in range(4):
      if map[((core[0]+self.rotateDict[getNew[i]][0]),
          (core[1]+self.rotateDict[getNew[i]][1]))] == 1:
        return False
    return True

  #旋转
  def rotate(self,event):
    if next != 2:
      if self.canRotate():
        for i in range(4):
          getNew[i] = self.rotateDict[getNew[i]]
        self.drawSquare()    
    if not self.canMove():
      for i in range(4):
        map[((core[0]+getNew[i][0]),(core[1]+getNew[i][1]))] = 1

  # 先判断是否左移/右移,同样,将方块现在所处位置的map中元素设为0,看其移动后的位置上map的元素是否有1,
  # 若有,说明这一位置已被占据或已到边界,不可移动,返回False。若可移动,返回True。按下左键,若可
  # 以移动,核心块的横坐标减1,由于我们只讨论其他小块对于核心块的相对位置,所以其他小块的位置自动随
  # 核心块的位置移动而移动。将移动过后的位置对应map中的元素设为1。
  def canLeft(self):
    coreNow = core
    for i in range(4):
      map[((coreNow[0]+getNew[i][0]),(coreNow[1]+getNew[i][1]))] = 0
    for i in range(4):
      if map[((coreNow[0]+getNew[i][0]-1),(coreNow[1]+getNew[i][1]))] == 1:
        return False
    return True

  #左移
  def moveLeft(self,event):
    if self.canLeft():
      core[0] -= 1
      self.drawSquare()
      self.drawBottom()
    if not self.canMove():
      for i in range(4):
        map[((core[0]+getNew[i][0]),(core[1]+getNew[i][1]))] = 1

       
  # 判断右移
  def canRight(self):
    for i in range(4):
      map[((core[0]+getNew[i][0]),(core[1]+getNew[i][1]))] = 0
    for i in range(4):
      if map[((core[0]+getNew[i][0]+1),(core[1]+getNew[i][1]))] == 1:
        return False
    return True

  # 右移
  def moveRight(self,event):
    if self.canRight():
      core[0] += 1
      self.drawSquare()
      self.drawBottom()
    if not self.canMove():
      for i in range(4):
        map[((core[0]+getNew[i][0]),(core[1]+getNew[i][1]))] = 1

      
  # 初始化中有一self. isFaster 的变量被设为False,当其为False时,
  # 程序中的sleep(time)中time的值为0.35,而按下下键,self. isFaster变为True,
  # time变成0.05,通过调整sleep()中变量的大小可以调节方块运动的速度。
  # 此功能通过if语句实现。
  def moveFaster(self,event):
    self.isFaster = True
    if not self.canMove():
      for i in range(4):
        map[((core[0]+getNew[i][0]),(core[1]+getNew[i][1]))] = 1
    
  # run the programe
  def run(self):
    self.isFill()
    self.drawNew()
    self.drawBottom()

  # play the game  
  def play(self):
    self.startBut.config(state=DISABLED)
    global isPause
    isPause = True
    global map
    map = self.map
    while True:
      if self.isOver():
        self.run()
      else:
        break
    self.over()  

  # 重新开始游戏   
  def restart(self):
    self.core = [4,-2]
    self.map = {}
    for i in range(self.width):
      for j in range(-4,self.height):
        self.map[(i,j)] = 0
    for i in range(-1,self.width):
      self.map[(i,self.height)] = 1
    for j in range(-4,self.height+1):
      self.map[(-1,j)] = 1
      self.map[(self.width,j)] = 1    
    self.score = 0
    self.t = 0.07
    for j in range(self.height):
      self.area.delete('bottom'+str(j))
    self.play()

  # 结束后告诉用户失败
  def over(self):
    feedback =messagebox.askquestion("You Lose!","You Lose!\nDo you want to restart?")
    if feedback == 'yes':
      self.restart()
    else:
      self.root.destroy()

  # 退出
  def isQuit(self):
    askQuit =messagebox.askquestion("Quit","Are you sure to quit?")
    if askQuit == 'yes':
      self.root.destroy()
      exit()

  #判断是否按下restart
  def isRestart(self):
    askRestart =messagebox.askquestion("Restart","Are you sure to restart?")
    if askRestart == 'yes':
      self.restart()
    else:
      return

  # 每次一按下暂停键,isPause = not isPause,当isPause = True时,由于之前提到过的if isPause:语句,
  # 方块可以移动,游戏运行。当按下暂停键以后,isPause值为False,方块将不可移动。同时,isPause值为False时
  # ,暂停键变为开始键,即标签由Pause 改为 Resume,当isPause值为True时,Resume改为Pause。这一功能由if语句实现。
  def isPause(self):
    global isPause
    isPause=not isPause
    if not isPause:
      self.pauseBut["text"]="Resume"
    else:
      self.pauseBut["text"]="Pause"
    
  #帮助
  def rule(self):
    ruleTop = Toplevel()
    ruleTop.title('Help')
    ruleTop.geometry('800x400')
    rule ="Start: Press the start button or choose the option 'Continue' to start the game.\n%-s%-s%-s%-s%-s%-s%-s%-s%-s%-s%-s%-s%-s%-s"%("Restart: Press the restart button or choose the option 'New Game' to resatrt the game.\n",                                                                   "Enjoy the Teris game! Have fun!")
    ruleLabel = Label(ruleTop,text=rule,fg='blue',font=(18))
    ruleLabel.place(x=50,y=50)

  # 显示有关信息
  def about(self):
    aboutTop = Toplevel()
    aboutTop.title('About')
    aboutTop.geometry('300x150')
    about = "Teris.py\n\
By Programmer Lee\n\
All Rights Reserved."
    aboutLabel = Label(aboutTop,font=('Curier',20),fg='darkblue',text=about)
    aboutLabel.pack()        

  # Get into mainloop
  def mainloop(self):
    self.root.mainloop()


# TerisPlay.py
# Game Teris
# By programmer FYJ

from teris import *

def main():
  teris = Teris()
  teris.mainloop()
  
main()

运行结构如图所示:

python实现简单俄罗斯方块

更多俄罗斯方块精彩文章请点击专题:俄罗斯方块游戏集合 进行学习。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python实现ftp客户端示例分享
Feb 17 Python
使用python实现strcmp函数功能示例
Mar 25 Python
使用graphics.py实现2048小游戏
Mar 10 Python
Python的Flask框架的简介和安装方法
Nov 13 Python
Python实现曲线拟合操作示例【基于numpy,scipy,matplotlib库】
Jul 12 Python
Pycharm使用之设置代码字体大小和颜色主题的教程
Jul 12 Python
Python爬虫 bilibili视频弹幕提取过程详解
Jul 31 Python
Python pandas实现excel工作表合并功能详解
Aug 29 Python
SELENIUM自动化模拟键盘快捷键操作实现解析
Oct 28 Python
python中使用paramiko模块并实现远程连接服务器执行上传下载功能
Feb 29 Python
快速解决pymongo操作mongodb的时区问题
Dec 05 Python
Pytorch实现图像识别之数字识别(附详细注释)
May 11 Python
Python实现检测文件的MD5值来查找重复文件案例
Mar 12 #Python
python 判断txt每行内容中是否包含子串并重新写入保存的实例
Mar 12 #Python
python 两个一样的字符串用==结果为false问题的解决
Mar 12 #Python
python不相等的两个字符串的 if 条件判断为True详解
Mar 12 #Python
Python 实现使用空值进行赋值 None
Mar 12 #Python
PyCharm永久激活方式(推荐)
Sep 22 #Python
Pycharm激活码激活两种快速方式(附最新激活码和插件)
Mar 12 #Python
You might like
抓取并下载CSS中所有图片文件的php代码
2011/09/26 PHP
PHP包含文件函数include、include_once、require、require_once区别总结
2014/04/05 PHP
php中session定期自动清理的方法
2015/11/12 PHP
PHP 无限级分类
2017/05/04 PHP
php的RSA加密解密算法原理与用法分析
2020/01/23 PHP
accesskey 提交
2006/06/26 Javascript
一页面多XMLHttpRequest对象
2007/01/22 Javascript
Javascript客户端将指定区域导出到Word、Excel的代码
2008/10/22 Javascript
超轻量级的基于jquery的三级展开列表
2011/04/26 Javascript
IE、FF浏览器下修改标签透明度
2014/01/28 Javascript
jQuery中:empty选择器用法实例
2014/12/30 Javascript
Javascript 实现微信分享(QQ、朋友圈、分享给朋友)
2016/10/21 Javascript
微信小程序  modal详解及实例代码
2016/11/09 Javascript
Bootstrap基本组件学习笔记之下拉菜单(7)
2016/12/07 Javascript
JS中from 表单序列化提交的代码
2017/01/20 Javascript
JavaScript实现定时页面跳转功能示例
2017/02/14 Javascript
手把手教你使用vue-cli脚手架(图文解析)
2017/11/08 Javascript
基于datepicker定义自己的angular时间组件的示例
2018/03/14 Javascript
JavaScript对象拷贝与Object.assign用法实例分析
2018/06/20 Javascript
实现Vue的markdown文档可以在线运行的方法示例
2018/12/11 Javascript
如何用RxJS实现Redux Form
2018/12/29 Javascript
细说webpack6 Babel的使用详解
2019/09/26 Javascript
原生JavaScript创建不可变对象的方法简单示例
2020/05/07 Javascript
jQuery HTML css()方法与css类实例详解
2020/05/20 jQuery
[09:22]2014DOTA2西雅图国际邀请赛 主赛事第二日TOPPLAY
2014/07/21 DOTA
python笔记之mean()函数实现求取均值的功能代码
2019/07/05 Python
python 字典套字典或列表的示例
2019/12/16 Python
CSS3 制作旋转的大风车(充满童年回忆)
2013/01/30 HTML / CSS
国际知名军事风格休闲装品牌:Alpha Industries(阿尔法工业)
2017/05/24 全球购物
巴西购物网站:Estrela10
2018/12/13 全球购物
BAILEY 44官网:美国制造的女性服装
2019/07/01 全球购物
struct和class的区别
2015/11/20 面试题
文秘班元旦晚会活动策划方案
2014/08/28 职场文书
机关党员公开承诺书
2014/08/30 职场文书
2014年秘书工作总结
2014/11/25 职场文书
Hive日期格式转换方法总结
2022/06/25 数据库