100行Python代码实现俄罗斯方块,不需要第三方依赖

本文发表于入职啦(公众号: ruzhila) 大家可以访问入职啦学习更多的编程实战。

用100行代码的不同语言(Java、Python、Go、Javascript、Rust)实现项目,通过讲解项目的实现,帮助大家学习编程

我们会定期在群里分享最新的项目实战代码,包括不同语言的实现

老师还会详细讲解代码优化的思路,扫码加入实战群:
入群学习

项目地址

代码已经开源, tetris-py 👏 欢迎Star

所有的项目都在github上开源:100-line-code 欢迎Star 👏

代码运行效果:

在这里插入图片描述

Python图形库实现游戏开发

Python 开发2d游戏,主要是通过pygame,这是一个基于SDL的游戏开发库,但是这个库有点大,所以我们用tkinter这个库来实现这个游戏。

tkinter是python自带的跨平台图形库,提供了最基本的绘制能力,我们可以通过这个库来实现这个游戏

整个代码的思路:

在这里插入图片描述

创建UI后通过两个事件处理来完成游戏逻辑:

  • 定时器用来做UI的逻辑判断和绘制
  • 键盘事件用来处理用户的输入,比如移动方块,旋转方块,然后渲染到UI上

俄罗斯方块游戏规则

俄罗斯方块有7种不同的形状,每种形状都可以旋转,玩家通过键盘控制方块的移动和旋转,当一行被填满时,这一行会消失,方块会继续下落,直到方块堆满或者游戏结束

绘制思路:

  • 一个二维数组(board)来表示游戏区域,每个方块的状态,数组的值为0表示空,1表示方块
  • 一个二维数组(shape)来表示运动方块的形状,每个方块的状态,数组的值为0表示空,1表示方块

游戏逻辑:

  • 通过定时器来判断shape是否与board碰撞,如果碰撞就把shape的状态复制到board中,然后生成新的shape
  • 如果出现一行被填满,就消除这一行,然后把上面的方块往下移动一行
  • 当新生成的shape不能移动时,游戏结束
  • 通过键盘事件来控制shape的移动和旋转

直接上代码

在这里插入图片描述

代码解析

数据结构抽象

在游戏开始之前,我们需要先设计不同方块的形状,前面绘制思路,我们可以得出不同的方块,其实就是多行的二维数组,每个数组的值为0表示空,1表示方块

比如四方形方块:

shape = [
    [1, 1],
    [1, 1]
]

或者J形方块:

shape = [
    [1, 1, 1],
    [0, 0, 1]
]

事件处理

我们实现了key_press的事件处理,这个函数会在用户按下键盘的时候触发,我们通过这个函数来控制方块的移动和旋转。

旋转

旋转的实现是通过list(zip(*reversed(self.shape))) 这样魔法一样的语法:

  1. 这段代码的作用是旋转一个二维列表, 比如:
shape = [[0, 1],
         [1, 1],
         [1, 0]]
  1. reversed(shape) 将 shape 的行反转,结果如下:
[[1, 0],
 [1, 1],
 [0, 1]]
  1. zip(*reversed(shape)) 使用 zip 函数将反转后的 shape 的列转换为行,结果如下:
[(1, 1, 0),
 (0, 1, 1)]
  1. 最后,list(zip(*reversed(shape))) 将结果转换为列表,结果如下:
[[1, 1, 0],
 [0, 1, 1]]

这样就可以将原始的shape旋转90度。

移动

移动的实现是通过修改self.xself.y的值,然后重新绘制方块,在移动之前需要先判断是否可以移动self.can_move, 就是遍历shape的每一个元素,判断是否会碰到边界或者已经有方块:

在这里插入图片描述

这时候会用到一个很常用的enumerate函数,这个函数可以同时返回索引和值。

UI绘制

整个游戏的UI绘制是通过定时器来完成的,通过每秒重新计算shape的位置,判断是否可以消除或者Gameover, 然后重新绘制UI

绘制主流程

在这里插入图片描述

绘制UI和消除行

以下代码分别实现固定shape、消除行、绘制固定块(self.board)和移动块self.shape的逻辑:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

总结

通过这个项目,我们可以学习到如何使用tkinter的使用,面向对象的编程思想,学习listdict等常见的数据结构的使用

游戏开发是一个很好的学习编程的方式,这个代码并没太高深的算法,很多人觉得游戏很需要算法,其实不然,所以我们特意用100行代码实现了这个游戏

我们构建了一个100行代码项目的实战群,大家可以扫码加入,一起学习编程

入群学习

也可以访问入职啦学习更多的编程实战

关注公众号入职啦,每日分享有趣的知识和项目

所有的代码都在github上开源:100-line-code 欢迎Star 👏

大家有感兴趣的项目以及想要实现的语言,可以评论留言哦,我们尽量会安排(语言选择:java,go,python,rust,js)

硬件部件 乐鑫ESP32S× 1个 Raspberry Pi Pi NoIR相机V2× 1个 软件应用程序和在线服务 Arduino IDE 这次我们为机器人配备了摄像头,使其成为监控机器人车。可以使用ESP32-CAM模块轻松构建此网络控制的监视车。除了ESP32-Camera模块之外,在这里我们还将使用两个带有Robot底盘的DC电动机和L293D电动机驱动器模块来制造此Robotic小车。ESP32构建基于IoT的项目的最受欢迎的开发板之一的AI-思想者ESP32-CAM模块带有一个ESP32-S芯片,非常小的尺寸OV2640照相机和microSD卡插槽。MicroSD卡插槽可用于存储从相机拍摄的图像。在此,HTTP通信协议将用于通过Web浏览器从OV2640摄像机接收视频流。网页上还将包含按钮,用于在上,左,右,前进和后退方向上移动汽车,如上图所示。 电路原理图 ESP32-监控摄像头的所有连接信息如下: ESP32-CAM没有USB连接器,因此您需要一个FTDI板将代码上传到ESP32-CAM。ESP32的VCC和GND引脚与FTDI板的VCC和GND引脚连接。ESP32的Tx和Rx与FTDI板的Rx和Tx连接。两颗直流电机通过L293D模块连接到ESP32。模块引脚连接到ESP32的IO4,IO2,IO14和IO15引脚。 注意:在上传代码之前,将IO0接地。IO0确定ESP32是否处于闪烁模式。当GPIO 0连接到GND时,ESP32处于闪烁模式。 我们通过使用现成的机器人底盘,车轮和直流电动机来构建机器人。我们使用电池为电机驱动模块和ESP32-CAM供电。这是我的监视机器人的外观:
### 回答1: 在 TURBO C 2.0 中,您可以使用 biosdisk() 函数来格式化软盘。 下面是一段代码示例: ``` #include <stdio.h> #include <dos.h> int main() { // 定义扇区的大小 unsigned int sector_size[3] = {512, 512, 1024}; // 定义填充字节 unsigned char fill_char[3] = {0xF6, 0xF6, 0x48}; // 格式化磁道 70 面 0 的前三个扇区 for (int i = 0; i < 3; i++) { int result = biosdisk(2, 0, 70, 0, i + 1, 1, sector_size[i], fill_char[i]); if (result != 0) { printf("格式化扇区 %d 失败,返回码: %d\n", i + 1, result); } } return 0; } ``` 请注意,在使用 biosdisk() 函数之前,需要包含 dos.h 头文件。 希望这能帮到您! ### 回答2: 使用TURBO C 2.0语言,可以通过以下代码格式化软盘的70磁道0面,并分别格式化3个扇区,大小分别为512字节、512字节和1024字节。其中,前两个扇区使用F6填充,第三个扇区使用48填充。 ```c #include<stdlib.h> #include<stdio.h> #include<dos.h> void formatFloppyDisk(){ union REGS regs; regs.h.ah = 0x0;// To format a floppy disk, we set AH=0 regs.h.dl = 0;// Drive number (0=A, 1=B, etc.) regs.x.cx = 0;// Track number to format regs.h.dh = 0;// Head number regs.h.al = 0;// Sector size (0=default, 1=512 bytes, 2=1024 bytes, 3=2048 bytes etc.) int FILL_BYTE = 0;// The byte value to fill the sectors with during formatting int NUM_SECTORS = 3;// Number of sectors to format // To format 70th track 0th head regs.x.ax = 0x1301; // 0x13 = Reset disk system, 01H = Reset only specified drive int86(0x13, &regs, &regs); // BIOS interrupt to reset disk system for (int i=0; i<NUM_SECTORS; i++){ regs.x.ax = 0x3101; // 0x31 = Write Format, 01H = Format only current track regs.x.bx = 0x0001; // 0x00 = Drive A:, 01H = Head 1, 0 = Generate ID Field depending on the disk in the drive 1 = Keep the ID Field all zeros regs.x.cx = 0x0170; // Track number=70(0-79 range) regs.h.dh = 0x00; // Head number=0 or 1 regs.h.al = 0x02; // Control byte=always zero regs.x.dx = i+1; // Sector number starting from 1 regs.x.si = 0x0000; // segment and offset of read/write buffer regs.x.di = 0x0000; // segment and offset of result if(i == 2){ FILL_BYTE = 0x48; // Fill the third sector with 48 regs.x.ax = 0x3102; // 0x31 = Write Format, 02H = Format sequential tracks immediately following the one being formatted }else{ FILL_BYTE = 0xF6; // Fill the first two sectors with F6 } regs.h.ah = FILL_BYTE; // Fill the sector with specified byte int86(0x13, &regs, &regs); // BIOS interrupt to format the specified sector } } int main(){ formatFloppyDisk(); return 0; } ``` 上述代码使用了INT 0x13,即BIOS中断服务例程,来执行软盘格式化操作。通过设置寄存器的不同参数,可以指定要格式化的磁道、面、扇区大小和填充字节。在这个例子中,我们格式化了软盘70磁道0面的3个扇区,前两个扇区使用F6填充,第三个扇区使用48填充。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值