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实现针对中文排序的方法
May 09 Python
基于python中staticmethod和classmethod的区别(详解)
Oct 24 Python
Python中Scrapy爬虫图片处理详解
Nov 29 Python
Python多线程扫描端口代码示例
Feb 09 Python
Python基于更相减损术实现求解最大公约数的方法
Apr 04 Python
Python中logging.NullHandler 的使用教程
Nov 29 Python
在Django的View中使用asyncio的方法
Jul 12 Python
对python 树状嵌套结构的实现思路详解
Aug 09 Python
wxPython实现画图板
Aug 27 Python
150行Python代码实现带界面的数独游戏
Apr 04 Python
Python unittest discover批量执行代码实例
Sep 08 Python
python excel和yaml文件的读取封装
Jan 12 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
windows下PHP APACHE MYSQ完整配置
2007/01/02 PHP
php中try catch捕获异常实例详解
2014/11/21 PHP
PHP中的命名空间相关概念浅析
2015/01/22 PHP
php计算年龄精准到年月日
2015/11/17 PHP
Laravel学习教程之View模块详解
2017/09/18 PHP
php封装db类连接sqlite3数据库的方法实例
2017/12/19 PHP
laravel框架数据库操作、查询构建器、Eloquent ORM操作实例分析
2019/12/20 PHP
PHP中类与对象功能、用法实例解读
2020/03/27 PHP
JS 有名函数表达式全面解析
2010/03/19 Javascript
Jquery插件 easyUI属性汇总
2011/01/19 Javascript
IE6,IE7,IE8下使用Javascript记录光标选中范围(已补全)
2011/08/28 Javascript
JavaScript的常见兼容问题及相关解决方法(chrome/IE/firefox)
2013/12/31 Javascript
一个简单的jquery的多选下拉框(自写)
2014/05/05 Javascript
使用Chrome浏览器调试AngularJS应用的方法
2015/06/18 Javascript
Jquery常用的方法汇总
2015/09/01 Javascript
Jquery左右滑动插件之实现超级炫酷动画效果附源码下载
2015/12/02 Javascript
详解node单线程实现高并发原理与node异步I/O
2017/09/21 Javascript
[01:05:07]DOTA2-DPC中国联赛 正赛 DLG vs Dragon BO3 第一场2月1日
2021/03/11 DOTA
简单介绍Python中的JSON模块
2015/04/08 Python
python实现图片处理和特征提取详解
2017/11/13 Python
python cx_Oracle的基础使用方法(连接和增删改查)
2017/11/19 Python
使用python将多个excel文件合并到同一个文件的方法
2019/07/09 Python
python通过robert、sobel、Laplace算子实现图像边缘提取详解
2019/08/21 Python
浅谈pytorch卷积核大小的设置对全连接神经元的影响
2020/01/10 Python
Keras: model实现固定部分layer,训练部分layer操作
2020/06/28 Python
pyx文件 生成pyd 文件用于 cython调用的实现
2021/03/04 Python
全球知名巧克力品牌:Godiva
2016/07/22 全球购物
英国的一家创新礼品和小工具零售商:Menkind
2019/08/24 全球购物
乐高瑞士官方商店:LEGO CH
2020/08/16 全球购物
小米官方旗舰店:Xiaomi
2020/08/07 全球购物
自考毕业自我鉴定范文
2013/10/27 职场文书
求职信的七个关键技巧
2014/02/05 职场文书
关于读书的演讲稿500字
2014/08/27 职场文书
群众路线教育实践活动心得体会(四风)
2014/11/03 职场文书
2019请假条的基本格式及范文!
2019/07/05 职场文书
html2 canvas svg不能识别的解决方案
2021/06/03 HTML / CSS