【Python】用Python写一个俄罗斯方块玩玩
【Python】用Python写一个俄罗斯方块玩玩
- 一、引言
- 1.成品效果展示
- 二、思考准备
- 1.思考设计
- 2.代码设计
- 2.1 游戏页面
- 2.2 控件设计
- 2.2.1 方块生成
- 2.2.2 方块碰撞
- 2.2.3 方块消融
- 2.2.4 游戏主循环
- 2.2.5 游戏窗口
- 三、游戏完整版
一、引言
- 今日看到侄子在玩游戏,凑近一看,原来是俄罗斯方块。熟悉又怀念,童年的记忆瞬间涌上心头。小时候觉得这游戏老厉害了,现在想想,好像就是数组的组合和消融,便想着自己写一个试试。说干就干,冲!
1.成品效果展示
俄罗斯方块实现过程
二、思考准备
1.思考设计

- 俄罗斯方块作为风靡一时的游戏,由俄罗斯人阿列克谢·帕基特诺夫于1984年6月发明的休闲游戏,主要是通过方块的组合、消融完成的;
- 所以得先设计有哪些方块、方块如何组合、完成一行时方块消融并下降一行、方块组合还得回旋转,单次90°等等,考虑中ing…
2.代码设计
2.1 游戏页面
- 游戏首先得有个操控页面,所以得设计一个
# 设计游戏窗口尺寸
SCREEN_WIDTH, SCREEN_HEIGHT = 300, 600
# 方块大小
GRID_SIZE = 30
# 各种图形颜色 可自定义调整
COLORS = [ # 颜色配置(含背景色+7种方块色)(0, 0, 0), # 0: 黑色背景(255, 0, 0), # 1: 红色-I型(0, 255, 0), # 2: 绿色-T型(0, 0, 255), # 3: 蓝色-J型(255, 165, 0), # 4: 橙色-L型(255, 255, 0), # 5: 黄色-O型(128, 0, 128), # 6: 紫色-S型(0, 255, 255) # 7: 青色-Z型
]
2.2 控件设计
2.2.1 方块生成
- 游戏开始最上方会有方块掉落,随机形状和颜色
def new_piece(self):"""生成新方块,随机形状和颜色"""shape = random.choice(SHAPES)return {'shape': shape, # 方块形状矩阵'x': (SCREEN_WIDTH//GRID_SIZE - len(shape[0])) // 2, # 初始水平居中'y': 0, # 初始垂直位置'color': random.randint(1, len(COLORS)-1) # 随机颜色(排除背景色)}
2.2.2 方块碰撞
- 方块会一直下降,碰撞,下降时还要符合可以多次旋转
def check_collision(self, dx=0, dy=0, rotate=False):"""碰撞检测函数:param dx: 水平移动偏移量:param dy: 垂直移动偏移量:param rotate: 是否正在旋转:return: 是否发生碰撞"""shape = self.current_piece['shape']# 旋转时生成临时形状if rotate: shape = [list(row[::-1]) for row in zip(*shape)] # 矩阵旋转算法:先转置再反转每行(顺时针90度)for y, row in enumerate(shape):for x, cell in enumerate(row):if cell: # 仅检测实体方块new_x = self.current_piece['x'] + x + dxnew_y = self.current_piece['y'] + y + dy# 边界检测(左右越界/触底/与其他方块重叠)if not (0 <= new_x < len(self.grid[0])) or new_y >= len(self.grid):return Trueif new_y >=0 and self.grid[new_y][new_x]:return Truereturn False
2.2.3 方块消融
- 方块接触时,合适的会消融、不合适的会叠加,消融了计算分数,消融的还要剔除
def merge_piece(self):"""将当前方块合并到游戏网格,并触发消行检测"""for y, row in enumerate(self.current_piece['shape']):for x, cell in enumerate(row):if cell:# 将方块颜色写入网格对应位置self.grid[self.current_piece['y']+y][self.current_piece['x']+x] = self.current_piece['color']# 消行并更新分数lines = self.clear_lines()self.score += lines * 100def clear_lines(self):"""消除满行并返回消除行数"""lines = 0# 从底部向上扫描for i, row in enumerate(self.grid):if all(cell !=0 for cell in row): # 检测整行填满del self.grid[i] # 删除该行self.grid.insert(0, [0]*len(row)) # 在顶部插入新空行lines +=1return lines
2.2.4 游戏主循环
- 游戏主体逻辑写入,方块的处理时间、操作事项和刷新等
def run(self):"""游戏主循环"""fall_time = 0 # 下落时间累计器while True:self.screen.fill(COLORS[0]) # 用背景色清屏# 计时系统(控制自动下落速度)fall_time += self.clock.get_rawtime()self.clock.tick() # 保持帧率稳定# 自动下落逻辑(每800ms下落一格)if fall_time >= 800:if not self.check_collision(dy=1):self.current_piece['y'] +=1 # 正常下落else:self.merge_piece() # 触底合并self.current_piece = self.new_piece() # 生成新方块# 游戏结束检测(新方块无法放置)if self.check_collision():print("Game Over 你完蛋啦! Score:", self.score)returnfall_time =0 # 重置计时器# 事件处理(适配Mac键盘布局)for event in pygame.event.get():if event.type == QUIT:pygame.quit()returnif event.type == KEYDOWN:# 左右移动(带碰撞检测)if event.key == K_LEFT and not self.check_collision(dx=-1):self.current_piece['x'] -=1elif event.key == K_RIGHT and not self.check_collision(dx=1):self.current_piece['x'] +=1# 软下落(手动加速)elif event.key == K_DOWN:if not self.check_collision(dy=1):self.current_piece['y'] +=1# 旋转方块(带碰撞检测)elif event.key == K_UP and not self.check_collision(rotate=True):self.current_piece['shape'] = [list(row[::-1]) for row in zip(*self.current_piece['shape'])]# 硬下落(空格键一键到底) elif event.key == K_SPACE: while not self.check_collision(dy=1):self.current_piece['y'] +=1# 绘制逻辑,游戏网格for y, row in enumerate(self.grid):for x, color in enumerate(row):if color:# 绘制已落下方块(留1像素间隙)pygame.draw.rect(self.screen, COLORS[color], (x*GRID_SIZE, y*GRID_SIZE, GRID_SIZE-1, GRID_SIZE-1))# 绘制当前操作方块for y, row in enumerate(self.current_piece['shape']):for x, cell in enumerate(row):if cell:pygame.draw.rect(self.screen, COLORS[self.current_piece['color']],((self.current_piece['x']+x)*GRID_SIZE, (self.current_piece['y']+y)*GRID_SIZE, GRID_SIZE-1, GRID_SIZE-1))# 刷新画面pygame.display.flip()
2.2.5 游戏窗口
- 最后,游戏设计好了,必须有个游戏窗口来展示
def __init__(self):# 初始化游戏窗口self.screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))pygame.display.set_caption("Mac M1俄罗斯方块")self.clock = pygame.time.Clock() # 游戏时钟控制帧率# 游戏状态初始化self.grid = [[0]*(SCREEN_WIDTH//GRID_SIZE) for _ in range(SCREEN_HEIGHT//GRID_SIZE)] # 20x10游戏网格self.current_piece = self.new_piece() # 当前操作方块self.score = 0
三、游戏完整版
# 俄罗斯方块设计
# -*- coding: utf-8 -*-
"""
功能:俄罗斯方块,童年的回忆
作者:看海的四叔
最后更新:2025-04-16
"""import pygame
import random
from pygame.locals import *# 初始化配置
pygame.init()
SCREEN_WIDTH, SCREEN_HEIGHT = 300, 600
GRID_SIZE = 30
COLORS = [ (0, 0, 0), (255, 0, 0), (0, 255, 0), (0, 0, 255), (255, 165, 0), (255, 255, 0), (128, 0, 128), (0, 255, 255)
]SHAPES = [[[1,1,1,1]], [[1,1],[1,1]], [[0,1,0], [1,1,1]], [[1,1,1], [1,0,0]], [[1,1,1], [0,0,1]], [[0,1,1], [1,1,0]], [[1,1,0], [0,1,1]]
]class Tetris:"""游戏主控制类,处理游戏逻辑与渲染"""def __init__(self):self.screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))pygame.display.set_caption("Mac M1俄罗斯方块")self.clock = pygame.time.Clock() self.grid = [[0]*(SCREEN_WIDTH//GRID_SIZE) for _ in range(SCREEN_HEIGHT//GRID_SIZE)] self.current_piece = self.new_piece() self.score = 0 def new_piece(self):"""生成新方块(随机形状和颜色)"""shape = random.choice(SHAPES)return {'shape': shape, 'x': (SCREEN_WIDTH//GRID_SIZE - len(shape[0])) // 2, 'y': 0, 'color': random.randint(1, len(COLORS)-1) }def check_collision(self, dx=0, dy=0, rotate=False):"""碰撞检测函数:param dx: 水平移动偏移量:param dy: 垂直移动偏移量:param rotate: 是否正在旋转:return: 是否发生碰撞"""shape = self.current_piece['shape']if rotate: shape = [list(row[::-1]) for row in zip(*shape)] for y, row in enumerate(shape):for x, cell in enumerate(row):if cell: new_x = self.current_piece['x'] + x + dxnew_y = self.current_piece['y'] + y + dyif not (0 <= new_x < len(self.grid[0])) or new_y >= len(self.grid):return Trueif new_y >=0 and self.grid[new_y][new_x]:return Truereturn Falsedef merge_piece(self):"""将当前方块合并到游戏网格,并触发消行检测"""for y, row in enumerate(self.current_piece['shape']):for x, cell in enumerate(row):if cell:self.grid[self.current_piece['y']+y][self.current_piece['x']+x] = self.current_piece['color']lines = self.clear_lines()self.score += lines * 100def clear_lines(self):"""消除满行并返回消除行数"""lines = 0for i, row in enumerate(self.grid):if all(cell !=0 for cell in row): del self.grid[i] self.grid.insert(0, [0]*len(row)) lines +=1return linesdef run(self):"""游戏主循环"""fall_time = 0 while True:self.screen.fill(COLORS[0]) fall_time += self.clock.get_rawtime()self.clock.tick() if fall_time >= 800:if not self.check_collision(dy=1):self.current_piece['y'] +=1 # 正常下落else:self.merge_piece() self.current_piece = self.new_piece() # 游戏结束检测(新方块无法放置)if self.check_collision():print("Game Over 你完蛋啦! Score:", self.score)returnfall_time =0 # 重置计时器for event in pygame.event.get():if event.type == QUIT:pygame.quit()returnif event.type == KEYDOWN:if event.key == K_LEFT and not self.check_collision(dx=-1):self.current_piece['x'] -=1elif event.key == K_RIGHT and not self.check_collision(dx=1):self.current_piece['x'] +=1elif event.key == K_DOWN:if not self.check_collision(dy=1):self.current_piece['y'] +=1elif event.key == K_UP and not self.check_collision(rotate=True):self.current_piece['shape'] = [list(row[::-1]) for row in zip(*self.current_piece['shape'])]elif event.key == K_SPACE: while not self.check_collision(dy=1):self.current_piece['y'] +=1for y, row in enumerate(self.grid):for x, color in enumerate(row):if color:pygame.draw.rect(self.screen, COLORS[color], (x*GRID_SIZE, y*GRID_SIZE, GRID_SIZE-1, GRID_SIZE-1))for y, row in enumerate(self.current_piece['shape']):for x, cell in enumerate(row):if cell:pygame.draw.rect(self.screen, COLORS[self.current_piece['color']],((self.current_piece['x']+x)*GRID_SIZE, (self.current_piece['y']+y)*GRID_SIZE, GRID_SIZE-1, GRID_SIZE-1))pygame.display.flip() if __name__ == "__main__":game = Tetris()game.run()相关文章:
【Python】用Python写一个俄罗斯方块玩玩
【Python】用Python写一个俄罗斯方块玩玩 一、引言1.成品效果展示 二、思考准备1.思考设计2.代码设计2.1 游戏页面2.2 控件设计2.2.1 方块生成2.2.2 方块碰撞2.2.3 方块消融2.2.4 游戏主循环2.2.5 游戏窗口 三、游戏完整版 一、引言 今日看到侄子在玩游戏,凑近一看…...
Java 本地缓存的实现:常见的四种方式
在 Java 中,常用的本地缓存实现主要有以下几种,以下是它们的代码示例及适用场景: 一、使用 ConcurrentHashMap 实现简单缓存 适合轻量级、无需复杂淘汰策略的场景。 import java.util.concurrent.ConcurrentHashMap;public class Simp…...
记录一次生产中mysql主备延迟问题处理
登录库: mysql -uXXXX -pXXXX -P3306 -hXXXXXX -A 备库上执行:show slave status\G 查看 seconds_Behind_Master,延迟 2705s,而且还一直在增加。 SHOW CREATE TABLE proc_i_income_temp; -- 查看表的结构 show index from proc…...
路由器原理与配置技术详解
一、路由基础原理 1.1 路由器的核心功能 网络层设备:工作在OSI参考模型第三层,实现不同网络间的互联互通智能路径选择:基于路由表为数据包选择最优传输路径协议转换:处理不同网络接口间的协议差异(如以太网与PPP&…...
第五节:React Hooks进阶篇-如何用useMemo/useCallback优化性能
反模式:滥用导致的内存开销React 19编译器自动Memoization原理 React Hooks 性能优化进阶:从手动到自动 Memoization (基于 React 18 及以下版本,结合 React 19 新特性分析) 一、useMemo/useCallback 的正确使用场景…...
STL迭代器:C++泛型编程的核心工具 [特殊字符]
在C中,STL(标准模板库)的迭代器是泛型编程的核心,它不仅解决了指针的局限性,还为算法与容器之间提供了抽象的访问接口。接下来,我们将探讨迭代器的核心作用、与指针的关键区别以及其设计哲学。 一、迭代器的…...
ffmpeg无损转格式的命令行
将ffmpeg.exe拖入命令行窗口 c:\users\zhangsan>D:\ffmpeg-2025-03-11\bin\ffmpeg.exe -i happy.mp4 -c:v copy -c:a copy 格式转换后.mkv -c:v copy 仅做拷贝视频,不重新编码 -c:a copy 仅做拷贝音频 ,不重新编码...
Monorepo 是什么?前端项目的多模块管理终极方案
前言 你是否曾经维护过多个前端项目?是否在多个项目之间来回复制粘贴组件,工具函数?是否经常被"组件更新没同步","构建时间太长","依赖版本冲突"等问题困扰? 这些问题都指向一个关键点: 项目结构和管理方式 今天,我来聊聊一种非常火但又容…...
对象池模式在uniapp鸿蒙APP中的深度应用
文章目录 对象池模式在uniapp鸿蒙APP中的深度应用指南一、对象池模式核心概念1.1 什么是对象池模式?1.2 为什么在鸿蒙APP中需要对象池?1.3 性能对比数据 二、uniapp中的对象池完整实现2.1 基础对象池实现2.1.1 核心代码结构2.1.2 在Vue组件中的应用 2.2 …...
条款05:了解C++默默编写并调用哪些函数
目录 1.默认生成的函数 2.无法生成的情况 2.1当成员函数有引用 或者 被const修饰 2.2.operator在基类被私有 1.默认生成的函数 class empty {};//相当于class empty { public:empty(){ ... } // 构造函数empty(const empty& rhs) { ... }// 拷贝构造~empty(){ ... } //…...
PythonFlask打造高效流式接口的实战
一、环境搭建与项目初始化 要使用 Flask 提供流式接口,首先得确保开发环境正确配置。在 Ubuntu 系统上,可借助 apt 包管理器便捷安装 Python 和 pip: sudo apt update sudo apt install python3 python3-pip对于 Windows 用户,推荐从官网下载安装包进行安装。安装完成后,…...
强化学习算法系列(五):最主流的算法框架——Actor-Critic算法框架
强化学习算法 (一)动态规划方法——策略迭代算法(PI)和值迭代算法(VI) (二)Model-Free类方法——蒙特卡洛算法(MC)和时序差分算法(TD) (三)基于动作值的算法——Sarsa算法与Q-Learning算法 (四…...
设计模式(结构型)-桥接模式
目录 摘要 定义 类图 角色 具体实现 优缺点 优点 缺点 使用场景 使用案例 JDBC 和桥接模式 总结 摘要 在软件开发领域,随着系统规模和复杂性的不断攀升,如何设计出具有良好扩展性、灵活性以及可维护性的软件架构成为关键挑战。桥接模式作为一…...
【MySQL】MySQL数据库 —— 简单认识
目录 1. 数据库的介绍 1.1 什么是数据库 1.2 数据库和数据结构之间关系 2. 数据库分类 2.1 关系型数据库(RDBMS) 2.2 非关系型数据库 2.3 区别 一些行内名词简单解释: 3. 关于mysql 主要学什么 4. MySQL中重要的概念 4.1 概念 4…...
RNN - 语言模型
语言模型 给定文本序列 x 1 , … , x T x_1, \ldots, x_T x1,…,xT,语言模型的目标是估计联合概率 p ( x 1 , … , x T ) p(x_1, \ldots, x_T) p(x1,…,xT)它的应用包括 做预训练模型(eg BERT,GPT-3)生成本文ÿ…...
过拟合、归一化、正则化、鞍点
过拟合 过拟合的本质原因往往是因为模型具备方差很大的权重参数。 定义一个有4个特征的输入,特征向量为,定义一个模型,其只有4个参数,表示为。当模型过拟合时,这四个权重参数的方差会很大,可以假设为。当经过这个模型后…...
【python画图】:从入门到精通绘制完美柱状图
目录 Python数据可视化:从入门到精通绘制完美柱状图一、基础篇:快速绘制柱状图1.1 使用Matplotlib基础绘制1.2 使用Pandas快速绘图 二、进阶篇:专业级柱状图定制2.1 多系列柱状图2.2 堆叠柱状图2.3 水平柱状图 三、专业参数速查表Matplotlib …...
基础知识:离线安装docker、docker compose
(1)离线安装docker 确认版本:Ubuntu 18.04 LTS - bionic 确认架构:X86_64 lsb_release -a uname -a 官方指南:https://docs.docker.com/engine/install/ 选择Ubuntu,发现页面上最低是Ubuntu20.04, 不要紧...
畅游Diffusion数字人(27):解读字节跳动提出主题定制视频生成技术Phantom
畅游Diffusion数字人(0):专栏文章导航 前言:主题定制视频生成,特别是zero-shot主题定制视频生成,一直是当前领域的一个难点,之前的方法效果很差。字节跳动提出了一个技术主题定制视频生成技术Phantom,效果相比于之前的技术进步非常显著。这篇博客详细解读一下这一工作。 …...
《Adaptive Layer-skipping in Pre-trained LLMs》- 论文笔记
作者:Xuan Luo, Weizhi Wang, Xifeng Yan Department of Computer Science, UC Santa Barbara xuan_luoucsb.edu, weizhiwangucsb.edu, xyancs.ucsb.edu 1. 引言与动机 1.1 背景 LLM 的成功与挑战: 大型语言模型 (LLMs) 在翻译、代码生成、推理等任务上取得巨大成…...
阅读分析Linux0.11 /boot/head.s
目录 初始化IDT、IDTR和GDT、GDTR检查协处理器并设置CR0寄存器初始化页表和CR3寄存器,开启分页 初始化IDT、IDTR和GDT、GDTR startup_32:movl $0x10,%eaxmov %ax,%dsmov %ax,%esmov %ax,%fsmov %ax,%gslss _stack_start,%espcall setup_idtcall setup_gdtmovl $0x1…...
android11 DevicePolicyManager浅析
目录 📘 简单定义 📘应用启用设备管理者 📂 文件位置 🧠 DevicePolicyManager 功能分类举例 🛡️ 1. 安全策略控制 📷 2. 控制硬件功能 🧰 3. 应用管理 🔒 4. 用户管理 &am…...
《前端性能优化秘籍:打造极致用户体验》
在当下,网站和应用的性能表现直接关乎用户去留。快速加载、流畅交互的页面能让用户沉浸其中,反之,缓慢的响应速度则会让他们毫不犹豫地离开。对于前端开发者而言,性能优化不仅是技术追求,更是提升用户体验、增强产品竞…...
微信小程序实现table样式,自带合并行合并列
微信小程序在代码编写过程好像不支持原生table的使用,在开发过程中偶尔又得需要拿table来展示。 1.table效果展示 1.wxml <view class"table-container"><view class"table"><view class"table-row"><view cla…...
学习笔记十二——Rust 高阶函数彻底入门(超详细过程解析 + 每步数值追踪)
💡 彻底搞懂 Rust 高阶函数!新手最容易卡住的语法 调用流程全讲透(含逐步拆解) Rust 函数式编程中有一个常见却经常让人懵的概念:高阶函数(Higher-Order Function) 一看到 fn(i32) -> i32、…...
电脑的品牌和配置
我的笔记本是2020年买的,之前的订单找不到了,就知道是联想,不清楚具体的配置。 本文来源:腾讯元宝 检查系统信息(Windows) 这通常是 联想(Lenovo) 的型号代码。 81XV 是联想…...
Redis面试——常用命令
一、String (1)设置值相关命令 1.1.1 SET 功能:设置一个键值对,如果键已存在则覆盖旧值语法: SET key value [EX seconds] [PX milliseconds] [NX|XX]EX seconds:设置键的过期时间为 seconds 秒 PX milli…...
Swin-Transformer-UNet改进:融合Global-Local Spatial Attention (GLSA) 模块详解
目录 1.模块概述 2.swinUNet网络 3. 完整代码 1.模块概述 Global-Local Spatial Attention (GLSA) 是一种先进的注意力机制模块,专为计算机视觉任务设计,能够同时捕捉全局上下文信息和局部细节特征。 该模块通过创新的双分支结构和自适应融合机制,显著提升了特征表示能…...
ubuntu 向右拖动窗口后消失了、找不到了
这是目前单显示器的设置,因为实际只有1个显示器,之前的设置如下图所示,有2个显示器,一个主显示器,一个23寸的显示器 ubuntu 22.04 系统 今天在操作窗口时,向右一滑,发现这个窗口再也不显示了、找…...
大语言模型(LLMs)中的强化学习(Reinforcement Learning, RL)
第一部分:强化学习基础回顾 在深入探讨LLMs中的强化学习之前,我们先快速回顾一下强化学习的核心概念,确保基础扎实。 1. 强化学习是什么? 强化学习是一种机器学习范式,目标是让智能体(Agent)…...
