WLED TetrisAI_v2 Usermod 实战:在 ESP32 LED 矩阵上运行自玩俄罗斯方块 AI 效果
2026/9/13 10:03:22 网站建设 项目流程

WLED TetrisAI_v2 Usermod 实战:在 ESP32 LED 矩阵上运行自玩俄罗斯方块 AI 效果

【免费下载链接】WLEDControl WS2812B and many more types of digital RGB LEDs with an ESP32 over WiFi!项目地址: https://gitcode.com/GitHub_Trending/wl/WLED

本文基于 WLED 官方 usermod 库中的 TetrisAI_v2 模块(readme.md)撰写,讲解如何将"自玩俄罗斯方块"作为一个 2D 灯光效果编译进 WLED 固件、在 ESP32 + WS2812B 矩阵上启用,并逐项解读其滑块/复选框参数背后的源码实现:从 7-bag 随机出块、位掩码棋盘到启发式 AI 评估函数的完整链路。读完后你可以独立完成该 usermod 的编译安装、按效果元数据正确配置参数,并理解"智能度"滑块实际上是如何扰动 AI 权重的。

一、TetrisAI_v2 是什么

TetrisAI_v2 是一个以 WLED usermod 形式提供的"效果"(effect):它内置一个完整的俄罗斯方块游戏引擎和一个启发式 AI,AI 自动落子、清线,把整个游戏过程实时渲染到 LED 矩阵上。效果在 WebUI 中以名称"Tetris AI"出现,属于 2D 效果,因此:

  • 需要 WLED0.14 及以上版本(依赖 matrix/2D 段支持);
  • 非矩阵(1D 灯带)环境下效果会直接用前景色填充段后返回,不产生游戏画面;
  • 作者声明的测试环境是ESP32 4MB + WS2812B 16x16 矩阵

一个需要特别注意的安全提示(原文档原文强调):光敏性癫痫警告——默认情况下,消行时会有一行以 200ms 周期在灰/黑之间闪烁的动画。该效果可以在 WLED 的 usermod 设置页中通过noFlashOnClear配置项关闭(见第五节)。

二、安装:把 tetrisai_v2 加进编译

2.1 最小安装步骤

按照 readme.md 的说明,只需在platformio_override.ini中加入一行:

custom_usermods = tetrisai_v2

编译后,"Tetris AI" 效果即出现在效果列表中。如果与默认 usermod 共存,可以按 platformio_override.sample.ini 中推荐的写法保留默认集合并追加:

custom_usermods = ${env:esp32dev.custom_usermods} tetrisai_v2

2.2 名字从哪里来

custom_usermods里的条目名不是随意的。构建脚本 load_usermods.py 会解析该变量,并在usermods/目录下按原名、原名_v2usermod_v2_原名等规则查找对应目录(find_usermod,pio-scripts/load_usermods.py#L13-L28)。本模块目录是usermods/TetrisAI_v2/,其 library.json 声明"name": "TetrisAI_v2""build": { "libArchive": false },因此tetrisai_v2(不区分大小写匹配)能正确命中。

模块的入口在 TetrisAI_v2.cpp:TetrisAIUsermod::setup()调用strip.addEffect(255, &mode_2DTetrisAI, _data_FX_MODE_2DTETRISAI)注册效果(ID 255 表示动态分配),usermod 自身 ID 为USERMOD_ID_TETRISAI = 47(定义于 wled00/const.h#L243)。

2.3 Flash 空间不足时切换分区表

该模块会引入一个完整的游戏引擎 + AI(含递归搜索),可能挤占代码分区。readme 给出的解决方案是换用代码分区更大、文件系统分区更小的布局,例如tools/WLED_ESP32_4MB_256KB_FS.csv(该分区文件实际存在于 tools/WLED_ESP32_4MB_256KB_FS.csv),在platformio_override.ini中追加:

board_build.partitions = tools/WLED_ESP32_4MB_256KB_FS.csv

tools/目录下还有同系列的其他分区表可按需选择(如 512KB、700KB FS 变体,见 tools/ 目录下的WLED_ESP32_4MB_*.csv文件)。注意该分区只适用于 4MB flash 的 ESP32;如果你的 flash 容量不同,请选择对应的WLED_ESP32_*MB*.csv

三、推荐的颜色与调色板配置

readme 给出的观感最佳组合(对应效果元数据中的前景/背景/边框三色):

颜色槽建议值作用(源码依据)
背景色(background)黑色未落子格子的填充色,TetrisAI_v2.cpp#L52-L54 中gridPixel == 0时取SEGCOLOR(1)
边框色(border)浅灰划分"下一块"预览区与棋盘的 1 像素竖线,取SEGCOLOR(2)
前景色(foreground,即 "Game Over" 色)深灰游戏结束动画中逐格"熄灭"的填充色,gridPixel == 254时取SEGCOLOR(0)
调色板(palette)Rainbow各落子方块颜色从调色板按 1/32 分段取色

方块颜色的映射在 TetrisAI_v2.cpp#L64-L68:每个块的colorIndex乘以 32 后加上动态colorOffset,再ColorFromPalette(SEGPALETTE, ...)取色,因此把 7 种块均匀铺满整个调色板——换用 Rainbow 调色板时七块呈现彩虹分布,这是"Rainbow 推荐"的直接原因。

四、参数详解:滑块与复选框如何映射到源码

效果元数据字符串完整定义在 TetrisAI_v2.cpp#L255:

"Tetris AI@!,Look ahead,Intelligence,Rotate color,Mistake free,Show next,Border,Mistakes;Game Over,!,Border;!;2;sx=127,ix=64,c1=255,c2=0,c3=31,o1=1,o2=1,o3=0,pal=11"

按 WLED 效果元数据约定解析:效果名 "Tetris AI";滑块依次为Look ahead(强度槽 intensity)、Intelligence(custom1)、Rotate color(custom2)、Mistake free(custom3);颜色名依次为前景 "Game Over"、背景(默认)、边框 "Border";复选框依次为Show next(check1)、Border(check2)、Mistakes(check3);末尾的2声明这是 2D 效果;分号后为默认值:speed=127、intensity=64、c1=255、c2=0、c3=31、check1=1、check2=1、check3=0、pal=11(Rainbow)。

4.1 滑块(Sliders)

滑块源码映射作用与取值
speed(效果速度槽)msDelayMove = 1024 - (4 * SEGMENT.speed)(TetrisAI_v2.cpp#L129)游戏速度。速度 0 → 每步 1024ms,255 → 约 4ms,即"AI 每一步(落一格或换一个决策周期)的刷新间隔"
Look ahead(intensity)nLookAhead = intensity ? (intensity >> 7) + 2 : 1(TetrisAI_v2.cpp#L133)AI 允许预知多少块:0(intensity=0)只看当前块;1~127 预知 1 块;128~255 预知 2 块。与 readme"0 - 2"一致
Intelligence(custom1)扰动四个启发式权重(TetrisAI_v2.cpp#L191-L200)AI 有多会玩。255 时不扰动(满智能);调低后权重被偏移,决策变差。机制见第五节
Rotate color(custom2)colorInc = SEGMENT.custom2 >> 4(TetrisAI_v2.cpp#L135)让方块颜色每隔几步偏移(旋转)调色板位置,取值 0~16,数值越大色相漂移越快
Mistake free(custom3)失误间隔倒计时mistaceCountdown = SEGMENT.custom3(TetrisAI_v2.cpp#L235-L249)仅在 Mistakes 复选框打开时生效:每 N 步好棋,AI 故意走一次"最坏决策",模仿人类失误

4.2 复选框(Checkboxes)

复选框作用源码依据
Show next打开后在右侧留出 5 像素宽的"下一块"预览区(每块占 5 行高),否则整段宽度都用于棋盘布局计算见 TetrisAI_v2.cpp#L157-L177,绘制见 TetrisAI_v2.cpp#L76-L109
Show border打开后额外占用 1 像素列,在棋盘与预览区之间画一条边框线同上(effectWidth += 1,绘制循环用SEGCOLOR(2)
Mistakes打开后按"mistake free"间隔周期性执行最差决策SEGMENT.check3分支(TetrisAI_v2.cpp#L237)

值得注意的默认值:出厂默认o1=1, o2=1(Show next 与 Border 均开启)、o3=0(Mistakes 关闭)。若段宽不足以容纳棋盘 + 5(预览) + 1(边框),布局代码会自动把棋盘减宽(gridWidth -= ...,TetrisAI_v2.cpp#L160-L174),16x16 矩阵下正好是 10 列棋盘 + 5 预览 + 1 边框。

4.3 游戏状态机

整个游戏循环由TetrisAIGame::poll()驱动的状态机推进(tetrisaigame.h#L63、L99-L143):

INIT → TEST_GAME_OVER → GET_NEXT_PIECE → FIND_BEST_MOVE → ANIMATE_MOVE → (循环) └──────────────────► ANIMATE_GAME_OVER → INIT

mode_2DTetrisAI()每个刷新周期按状态调用poll():动画类状态(ANIMATE_MOVE / ANIMATE_GAME_OVER)受msDelayMove节流,而 GET_NEXT_PIECE / FIND_BEST_MOVE 等逻辑状态不受速度限制地立即推进——即AI 思考不占时间,只有动画受 speed 控制。游戏结束判定为顶部 4 行隐藏区任一格被占(tetrisaigame.h#L93-L97:棋盘实际高度是height + 4,渲染从第 4 行开始);ANIMATE_GAME_OVER 状态会逐格把棋盘像素置为特殊值 254,用前景色重绘,随后自动开新局。

五、AI 与棋盘:源码级实现剖析

5.1 出块:标准 7-bag 随机器

tetrisbag.h 实现经典 7-bag:bag数组预填0,1,2,...,6,耗尽一次后shuffleBag()用 Fisher–Yates 洗牌,queuePiece()维护一个长度等于nLookAheadpiecesQueue。队列头是当前落子块,队列其余部分既是"下一块"预览区的数据源(piecesQueue[nextPieceIdx],TetrisAI_v2.cpp#L91-L107),也是 AI 前瞻搜索的输入——AI 预知的块与玩家看到的块完全一致。

7 种块(I/O/Z/S/L/J/T)的形状以紧凑位图存储:每个旋转用uint16_t rows(4 行 × 4 位)表示,pieces.h#L39-L108,colorIndex决定其在调色板中的分段位置。

5.2 棋盘:32 位行掩码的双棋盘设计

棋盘由两套并行的数据结构组成:

  • GridBW(gridbw.h):每行一个uint32_t位掩码(std::vector<uint32_t> pixels),因此宽度上限 32(构造时超过 32 会被钳制,gridbw.h#L41-L44)。放置/擦除块用|=/&=~整行位运算,碰撞检测noCollision()只需按行&一次,isLineFull()比较行掩码是否全 1——这是 AI 能做深搜索的速度基础。
  • GridColor(gridcolor.h):每格一个uint8_t颜色索引,仅用于渲染;消行/坍塌时与 GridBW 同步偏移。

消行带一个"闪烁缓冲":cleanupFullLines()先只在clearingRows[]上标记满行而不删除;效果层等750ms后才置clearedLinesReadyForRemoval = true并真正移除(TetrisAI_v2.cpp#L203-L215)。闪烁期间满行像素按strip.now % 200 < 150在灰/黑间交替(TetrisAI_v2.cpp#L42-L50)——这就是光敏性癫痫警告的来源。用户mod 配置项noFlashOnClear = true可让满行保持静态灰色,配置通过addToConfig/readFromConfig持久化到 WLED 的 JSON 设置中(TetrisAI_v2.cpp#L269-L281),即 readme 提到的"从 usermod 设置页关闭闪烁"。

5.3 启发式评分函数

AI 的评估逻辑在 tetrisai.h。updateRating()(tetrisai.h#L42-L108)同样以列方向累积位掩码,单次遍历同时算出:各列高度(含 aggregate 高度)、最高列、最低列、满行数、空洞数(当前行掩码与列累积掩码的 XOR 中 1 的个数,countOnes是经典 popcount 位技巧)、凹凸度(相邻列高度差的绝对值之和,tetrisai.h#L101-L105)。最终打分(tetrisai.h#L107):

score = aHeight × aggregatedHeight + fullLines × fullLines + holes × holes + bumpiness × bumpiness

默认权重(tetrisai.h#L110):

权重默认值含义
aHeight-0.510066堆积总高度越高越差
fullLines+0.760666即将/已满的行越多越好
holes-0.35663空洞越多越差
bumpiness-0.184483表面越不平越差

Rating结构体定义于 rating.h,初值score = -FLT_MAX以便"更优者胜"的比较语义。

5.4 搜索与"智能度/失误"的实现

findBestMove()(tetrisai.h#L138-L204)对候选块做递归枚举:对piecesQueue中每一块,穷举"每种旋转 × 每一列落点"(落点由findLandingPosition()沿列下探求出),放置→评分(或递归搜索下一块)→擦除。递归深度即 lookahead,因此 16 列 × 预知 2 块时的候选规模大致是 O(落点数^3),位掩码棋盘保证了这在 ESP32 上可行。

"Intelligence" 滑块通过均匀扰动四个权重来实现(TetrisAI_v2.cpp#L194-L199):

float dui = 0.2f - (0.2f * (intelligence / 255.0f)); ai.aHeight = -0.510066f + dui; ai.fullLines = 0.760666f - dui; ai.holes = -0.35663f + dui; ai.bumpiness = -0.184483f + dui;

intelligence = 255 时dui = 0,权重保持最优组合;调低滑块后正负项相互抵消的幅度增大,评分的区分度下降,AI 决策质量随之降低。

"Mistakes" 复选框 + "Mistake free" 滑块则直接反转比较方向:倒计时归零的那一步把ai.findWorstMove = true,此时搜索保留得分最低的落法(tetrisai.h#L178-L192),随即还原并重置倒计时为custom3——从而呈现"大多数时候很强、偶尔犯一个低级错误"的人类感。

5.5 布局与居中

段重建(速度、尺寸、复选框变化时触发)时,效果会重算占用区域:棋盘宽min(cols, 32)、高min(rows, 255),Show next 追加 5 列、Show border 追加 1 列,然后segOffsetX/Y = (cols/rows - effectW/H) / 2实现整块居中(TetrisAI_v2.cpp#L144-L189)。

六、限制与"最佳观赏效果"

硬限制(与 readme.md "Limits" 一节一致,并得到源码印证):

  • 棋盘最大宽度 32:受GridBW每行uint32_t位掩码限制(gridbw.h#L27);
  • 棋盘最大高度 255:受行索引uint8_t限制(TetrisAI_v2.cpp#L150-L151);
  • 段尺寸超过上限时,整个效果画布会在段内居中显示,而不是拉伸。

最佳观赏建议(原文档 "Best results"):把速度调到"略快于人类高手的实际操作速度",Intelligence 拉满、Mistakes 关闭(或 mistake free 设得很大)——AI 以超人的稳定水平连续清行,观感最"炸场"。反过来,把 Intelligence 调低并启用 Mistakes,可以看到 AI 堆积、出现空洞乃至 Game Over 熄灭动画的全过程,适合演示"AI 也会输"。

七、相关文件索引

文件说明
usermods/TetrisAI_v2/readme.md模块说明(本文依据的原始文档)
usermods/TetrisAI_v2/TetrisAI_v2.cppWLED 效果入口、渲染、参数映射、usermod 配置
usermods/TetrisAI_v2/tetrisaigame.h游戏主循环状态机、game over 判定
usermods/TetrisAI_v2/tetrisai.h启发式评分与最优/最差走法搜索
usermods/TetrisAI_v2/gridbw.h位掩码棋盘:碰撞、落点、消行闪烁缓冲
usermods/TetrisAI_v2/gridcolor.h8 位色索引渲染棋盘
usermods/TetrisAI_v2/tetrisbag.h7-bag 随机出块与下一块队列
usermods/TetrisAI_v2/pieces.h7 种块形状位图与旋转数据
usermods/TetrisAI_v2/rating.h评分结构体
usermods/TetrisAI_v2/library.json库名与 libArchive 设置
tools/WLED_ESP32_4MB_256KB_FS.csvFlash 不足时推荐的大代码区分区表
pio-scripts/load_usermods.pycustom_usermods 的解析与目录匹配逻辑

适用前提再强调一次:需要 0.14+ 版本、具备 2D 段(matrix)的硬件布局(如 16x16 矩阵),以及编译侧在platformio_override.ini中登记tetrisai_v2。该模块属于 WLED 社区 usermod(作者 muebau),随主仓库分发但由上游用户自行维护,升级 WLED 大版本后建议核对效果元数据与 usermod API 的兼容性。

【免费下载链接】WLEDControl WS2812B and many more types of digital RGB LEDs with an ESP32 over WiFi!项目地址: https://gitcode.com/GitHub_Trending/wl/WLED

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询