python实现俄罗斯方块


Posted in Python onJune 26, 2018

网上搜到一个Pygame写的俄罗斯方块(tetris),大部分看懂的前提下增加了注释,Fedora19下运行OK的

主程序:

#coding:utf8
#! /usr/bin/env python
# 注释说明:shape表示一个俄罗斯方块形状 cell表示一个小方块
import sys
from random import choice
import pygame
from pygame.locals import *
from block import O, I, S, Z, L, J, T

COLS = 16
ROWS = 20
CELLS = COLS * ROWS
CELLPX = 32 # 每个cell的像素宽度
POS_FIRST_APPEAR = COLS / 2
SCREEN_SIZE = (COLS * CELLPX, ROWS * CELLPX)
COLOR_BG = (0, 0, 0)


def draw(grid, pos=None):
 # grid是一个list,要么值为None,要么值为'Block'
 # 非空值在eval()的作用下,用于配置颜色
 if pos: # 6x5
  s = pos - 3 - 2 * COLS # upper left position
  for p in range(0, COLS):
   q = s + p * COLS
   for i in range(q, q + 6):
    if 0 <= i < CELLS:
     # 0 <=i < CELLS:表示i这个cell在board内部。
     c = eval(grid[i] + ".color") if grid[i] else COLOR_BG
     # 执行着色。shape的cell涂对应的class设定好的颜色,否则涂黑(背景色)
     a = i % COLS * CELLPX
     b = i / COLS * CELLPX
     screen.fill(c, (a, b, CELLPX, CELLPX))
 else: # all
  screen.fill(COLOR_BG)
  for i, occupied in enumerate(grid):
   if occupied:
    c = eval(grid[i] + ".color") # 获取方块对应的颜色
    a = i % COLS * CELLPX # 横向长度
    b = i / COLS * CELLPX # 纵向长度
    screen.fill(c, (a, b, CELLPX, CELLPX))
    # fill:为cell上色, 第二个参数表示rect
 pygame.display.flip()
 # 刷新屏幕


def phi(grid1, grid2, pos): # 4x4
# 两个grid之4*4区域内是否会相撞(冲突)
 s = pos - 2 - 1 * COLS # upper left position
 for p in range(0, 4):
  q = s + p * COLS
  for i in range(q, q + 4):
   try:
    if grid1[i] and grid2[i]:
     return False
   except:
    pass
 return True


def merge(grid1, grid2):
 # 合并两个grid
 grid = grid1[:]
 for i, c in enumerate(grid2):
  if c:
   grid[i] = c
 return grid


def complete(grid):
 # 减去满行
 n = 0
 for i in range(0, CELLS, COLS):
  # 步长为一行。
  if not None in grid[i:i + COLS]:
  #这一句很容易理解错误。
  #实际含义是:如果grid[i:i + COLS]都不是None,那么执行下面的语句
   grid = [None] * COLS + grid[:i] + grid[i + COLS:]
   n += 1
 return grid, n
#n表示减去的行数,用作统计分数

pygame.init()
pygame.event.set_blocked(None)
pygame.event.set_allowed((KEYDOWN, QUIT))
pygame.key.set_repeat(75, 0)
pygame.display.set_caption('Tetris')
screen = pygame.display.set_mode(SCREEN_SIZE)
pygame.display.update()

grid = [None] * CELLS
speed = 500
screen.fill(COLOR_BG)
while True: # spawn a block
 block = choice([O, I, S, Z, L, J, T])()
 pos = POS_FIRST_APPEAR
 if not phi(grid, block.grid(pos), pos): break # you lose
 pygame.time.set_timer(KEYDOWN, speed)
 # repeatedly create an event on the event queue
 # speed是时间间隔。。。speed越小,方块下落的速度越快。。。speed应该换为其他名字

 while True: # move the block
  draw(merge(grid, block.grid(pos)), pos)
  event = pygame.event.wait()
  if event.type == QUIT: sys.exit()
  try:
   aim = {
    K_UNKNOWN: pos+COLS,
    K_UP: pos,
    K_DOWN: pos+COLS,
    K_LEFT: pos-1,
    K_RIGHT: pos+1,
   }[event.key]
  except KeyError:
   continue
  if event.key == K_UP:
   # 变形
   block.rotate()

  elif event.key in (K_LEFT, K_RIGHT) and pos / COLS != aim / COLS:
   # pos/COLS表示当前位置所在行
   # aim/COLS表示目标位置所在行
   # 此判断表示,当shape在左边界时,不允许再向左移动(越界。。),在最右边时向右也禁止
   continue

  grid_aim = block.grid(aim)
  if grid_aim and phi(grid, grid_aim, aim):
   pos = aim
  else:
   if event.key == K_UP:
    block.rotate(times=3)
   elif not event.key in (K_LEFT, K_RIGHT):
    break

 grid = merge(grid, block.grid(pos))
 grid, n = complete(grid)
 if n:
  draw(grid)
  speed -= 5 * n
  if speed < 75: speed = 75

调用的模块:

#coding:utf-8
#! /usr/bin/env python
COLS = 16
ROWS = 20

class Block():
 color = (255,255,255)
 def __init__(self):
  self._state = 0
 def __str__(self):
  return self.__class__.__name__
 def _orientations(self):
  raise NotImplementedError()
 def rotate(self, times=1):
  for i in range(times):
   if len(self._orientations())-1 == self._state:
    self._state = 0
    #只要_state比_orientations长度-1还要小,就让_state加1

   else:
    self._state += 1
 def blades(self):
  # 返回对应形状的一种旋转形状。(返回一个list,list中每个元素是一个(x,y))
  return self._orientations()[self._state]

 def grid(self, pos, cols=COLS, rows=ROWS):
  # grid()函数:对于一个形状,从它的cell中的pos位置,按照orientations的位置提示,把所有cell涂色
  # pos表示的是shape中的一个cell,也就是(0,0)
  if cols*rows <= pos:
   return None
  # 这种情况应该不可能出现吧。如果出现<=的情况
  # 那么,pos都跑到界外了。。

  grid = [None] * cols * rows
  grid[pos] = str(self)
  for b in self.blades():
   x, y = b
   # pos/cols表示pos处于board的第几行
   if pos/cols != (pos+x)/cols:
    return None
   i = pos + x + y * cols
   if i < 0:
    continue
   elif cols*rows <= i:
    return None
   grid[i] = str(self)
   # 给相应的其他位置都“涂色”,比如对于方块,是O型的,那么pos肯定是有值的,pos位于有上角。。
  return grid

# 以下每个形状class,_orientations()都返回形状的列表。(0,0)一定被包含在其中,为了省略空间所以都没有写出.
class O(Block):
 color = (207,247,0)
 def _orientations(self):
  return (
   [(-1,0), (-1,1), (0,1)],
   )
class I(Block):
 color = (135,240,60)
 def _orientations(self):
  return (
   [(-2,0), (-1,0), (1,0)],
   [(0,-1), (0,1), (0,2)],
   )
class S(Block):
 color = (171,252,113)
 def _orientations(self):
  return (
   [(1,0), (-1,1), (0,1)],
   [(0,-1), (1,0), (1,1)],
   )
class Z(Block):
 color = (243,61,110)
 def _orientations(self):
  return (
   [(-1,0), (0,1), (1,1)],
   [(1,-1), (1,0), (0,1)],
   )
class L(Block):
 color = (253,205,217)
 def _orientations(self):
  return (
   [(-1,1), (-1,0), (1,0)],
   [(0,-1), (0,1), (1,1)],
   [(-1,0), (1,0), (1,-1)],
   [(-1,-1), (0,-1), (0,1)],
   )
class J(Block):
 color = (140,180,225)
 def _orientations(self):
  return (
   [(-1,0), (1,0), (1,1)],
   [(0,1), (0,-1), (1,-1)],
   [(-1,-1), (-1,0), (1,0)],
   [(-1,1), (0,1), (0,-1)],
   )
class T(Block):
 color = (229,251,113)
 def _orientations(self):
  return (
   [(-1,0), (0,1), (1,0)],
   [(0,-1), (0,1), (1,0)],
   [(-1,0), (0,-1), (1,0)],
   [(-1,0), (0,-1), (0,1)],
   )

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

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

Python 相关文章推荐
简单介绍Python中用于求最小值的min()方法
May 15 Python
机器学习10大经典算法详解
Dec 07 Python
对python中xlsx,csv以及json文件的相互转化方法详解
Dec 25 Python
Python多进程方式抓取基金网站内容的方法分析
Jun 03 Python
Python实现TCP通信的示例代码
Sep 09 Python
使用Python给头像戴上圣诞帽的图像操作过程解析
Sep 20 Python
Python实现PyPDF2处理PDF文件的方法示例
Sep 25 Python
python实现二分类的卡方分箱示例
Nov 22 Python
Python序列类型的打包和解包实例
Dec 21 Python
Python JSON编解码方式原理详解
Jan 20 Python
Python基于类路径字符串获取静态属性
Mar 12 Python
Python中with上下文管理协议的作用及用法
Mar 18 Python
解决python报错MemoryError的问题
Jun 26 #Python
pygame实现俄罗斯方块游戏
Jun 26 #Python
python和pygame实现简单俄罗斯方块游戏
Feb 19 #Python
解决python读取几千万行的大表内存问题
Jun 26 #Python
详解Python3的TFTP文件传输
Jun 26 #Python
python3爬取数据至mysql的方法
Jun 26 #Python
python清除函数占用的内存方法
Jun 25 #Python
You might like
PHP IPV6正则表达式验证代码
2010/02/16 PHP
php检测apache mod_rewrite模块是否安装的方法
2015/03/14 PHP
php微信开发之图片回复功能
2018/06/14 PHP
javascript dom 操作详解 js加强
2009/07/13 Javascript
javascript onmouseout 解决办法
2010/07/17 Javascript
使用cluster 将自己的Node服务器扩展为多线程服务器
2014/11/10 Javascript
ECMAScript5(ES5)中bind方法使用小结
2015/05/07 Javascript
jQuery往textarea中光标所在位置插入文本的方法
2015/06/26 Javascript
javascript实现数字倒计时特效
2016/03/30 Javascript
Angular.js ng-file-upload结合springMVC的使用教程
2017/07/10 Javascript
浅谈Vue-cli单文件组件引入less,sass,css样式的不同方法
2018/03/13 Javascript
Vue单页应用引用单独的样式文件的两种方式
2018/03/30 Javascript
详解Ubuntu安装angular-cli遇到的坑
2018/09/08 Javascript
vue实现的组件兄弟间通信功能示例
2018/12/04 Javascript
angular中两种表单的区别(响应式和模板驱动表单)
2018/12/06 Javascript
通过npm或yarn自动生成vue组件的方法示例
2019/02/12 Javascript
详解JS判断页面是在手机端还是在PC端打开的方法
2019/04/26 Javascript
vue-cli3项目升级到vue-cli4 的方法总结
2020/03/19 Javascript
Python 面向对象 成员的访问约束
2008/12/23 Python
Python中urllib+urllib2+cookielib模块编写爬虫实战
2016/01/20 Python
python3+selenium实现126邮箱登陆并发送邮件功能
2019/01/23 Python
Python动态导入模块:__import__、importlib、动态导入的使用场景实例分析
2020/03/30 Python
Keras实现支持masking的Flatten层代码
2020/06/16 Python
浅析python函数式编程
2020/09/26 Python
爱尔兰灯和灯具网上商店:Lights.ie
2018/03/26 全球购物
万宝龙英国官网:Montblanc手表、书写工具、皮革和珠宝
2018/10/16 全球购物
Hudson Jeans官网:高级精制牛仔裤
2018/11/28 全球购物
C/C++ 笔试、面试题目大汇总
2015/11/21 面试题
iostream与iostream.h的区别
2015/01/16 面试题
能否解释一下XSS cookie盗窃是什么意思
2012/06/02 面试题
竞聘上岗演讲稿范文
2014/01/10 职场文书
教师读书活动总结
2014/05/07 职场文书
预备党员考察意见范文
2015/06/01 职场文书
春节慰问简报
2015/07/21 职场文书
go设置多个GOPATH的方式
2021/05/05 Golang
Redis调用Lua脚本及使用场景快速掌握
2022/03/16 Redis