zoukankan      html  css  js  c++  java
  • 俄罗斯方块:Python实现

    网上搜到一个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)],
                )
    
  • 相关阅读:
    leetcode 155. Min Stack 、232. Implement Queue using Stacks 、225. Implement Stack using Queues
    leetcode 557. Reverse Words in a String III 、151. Reverse Words in a String
    leetcode 153. Find Minimum in Rotated Sorted Array 、154. Find Minimum in Rotated Sorted Array II 、33. Search in Rotated Sorted Array 、81. Search in Rotated Sorted Array II 、704. Binary Search
    leetcode 344. Reverse String 、541. Reverse String II 、796. Rotate String
    leetcode 162. Find Peak Element
    leetcode 88. Merge Sorted Array
    leetcode 74. Search a 2D Matrix 、240. Search a 2D Matrix II
    Android的API版本和名称对应关系
    spring 定时任务执行两次解决办法
    解析字符串为泛型的方法
  • 原文地址:https://www.cnblogs.com/james1207/p/3278383.html
Copyright © 2011-2022 走看看