ANSI Escape Sequence 下落的方块
ANSI Escape Sequence 下落的方块
1. ANSI Escape 的用途
无意中发现 B站有人讲解, 完全基于终端实现俄罗斯方块。 基本想法是借助于 ANSI Escape Sequence 实现方方块的绘制、 下落动态效果等。对于只了解 ansi escape sequence 用于 log 的颜色打印的人来说, 这无疑是拓宽了认识。

这一篇简单的列一下 ansi escape sequence 中的稀奇古怪的数字的含义, 并最终给出一个绿色方块下落的动态效果和对应的代码。 基于本篇给出的表格和代码, 可以把它拓展为自由落体的游戏效果, 也可以跟着 B 站视频更容易的写出终端里的俄罗斯方块。
同时也注意到, ansi escape sequence 有它的局限性, 无法绘制比较大的圆形, 使用 ansi escape sequence 会限制界面显示、 游戏开发的上限。
2. ANSI Escape Sequence 有什么用?
终端会把 ANSI Escape 序列的字符解释为命令,而不是原本的内容。这些命令在终端上控制如下内容:
- 鼠标位置
- 颜色
- 字体样式
- 其他选项
使用 ANSI Escape Sequence 做 log 打印的例子比较多, 但其实还可以那它用作绘图显示: 把终端当成是 256 色的图像, 在终端显示图像内容。
3. 形式
3.1 格式概况
- 绝大多数有用的序列:
ESC[开头 - 序列的重置:
ESC[0m, 意思是各种设置的属性都撤销掉,恢复为没有设置时的状态
一些“黑话”:
- CSI (Control Sequence Introducer):
ESC[的别名, ASCII escape 数值是27, 实际使用时 ESC 换成\x1b(16进制),\033(8进制) 或\e - SGR (Select Graphic Rendition):
CSI n m的别名,用于设定字符的颜色和风格。其中:- CSI 要换成
\x1b[,\033[或\e[ - n 要换成具体的数字,在 0~107 之间
- CSI 要换成
根据 wikipedia 得到的解释:
- 起始:
ESC[(这个组合又叫做 CSI, Control Sequence Introducer) - parameter bytes: 任意数量的 0x30-0x3F 范围的字符, 也就是
0-9:;<=>? - intermediate bytes: 任意数量的 0x20-0x2F 范围的字符,也就是
!"#$%&'()*+,-./ - final bytes: 任意数量的 0x40-0x7E 范围的字符,也就是 “@A–Z[]^_`a–z{|}~”
- private bytes: 包含
<=>?或 0x70-0x7E 范围(p-z{|}~) 的字符, 各厂商自行定义和使用的 - 设定多个属性:
;分隔的单个属性 - 重置:
ESC[0m
而网上其他资料, 以及实际验证, 发现维基百科有遗漏内容, ESC[ (CSI) 之后可以紧跟着 0~0x2F 范围的数字, 例如 n=1 对应到 “字体加粗” 的属性。
3.2 格式的具体情况
| n | 名字 | 含义、作用 |
|---|---|---|
| 0 | Reset or normal | 重置所有属性 |
| 1 | Bold or increased intensity | 字体加粗 |
| 2 | Faint, decresed intensity, or dim | 字体变暗 |
| 3 | Italic | 斜体。据说没有被广泛使用 |
| 4 | Underline | 下划线. 算是扩展, 在 Kitty, VTE, mintty, iTERM2, Konsole 里有效 |
| 5 | Slow blink | 设定光标闪烁时间在每分钟内小于150次(暂时不会用) |
| 6 | Rapid blink | 光标闪烁加速,每分钟内超过150次; 没有被广泛支持 |
| 7 | Reverse video or invert | 对调背景和前景的颜色 |
| 8 | Conceal or hide | 没有被广泛的支持,iTerm2 上没有效果 |
| 9 | Crossed-out, or strike | 让字符带有删除线 |
| 10 | Primary(default) font | 默认字体 |
| 11~19 | Alternative font | 选择编号为 n-10 的字体 |
| 20 | Fraktur(Gothic) | 很少使用。iTerm2 上没有效果 |
| 21 | Doubly underlined; or: not bold | 双下划线、或者不要加粗 |
| 22 | Normal intensity | 既不加粗、也不变暗 |
| 23 | Neither italic, nor blackletter | 既不斜体, 也不黑色字母 |
| 24 | Not underlined | 不要有单个下划线, 也不要有双下划线 |
| 25 | Not blinking | 不要闪烁光标 |
| 26 | Proportional spacing | 终端上没有在使用 |
| 27 | Not reserved | iTerm2 上没有效果 |
| 28 | Reveal | 不要"隐瞒" |
| 29 | Not crossed out | 去掉“删除线" |
| 30-37 | Set foreground color | 设置前景颜色 |
| 30 | Black 黑色前景 | |
| 31 | Red 红色前景 | |
| 32 | Green 绿色前景 | |
| 33 | Yellow 黄色前景 | |
| 34 | Blue 蓝色前景 | |
| 35 | Magenta 紫色前景 | |
| 36 | Cyan 靛蓝色前景 | |
| 37 | White 白色前景 | |
| 38 | Set foreground color | 设置前景颜色, 接下来的参数是 5;n 或 2;r;g;b |
| 39 | Default foreground color | 默认前景颜色 |
| 40-47 | 设置背景颜色 | |
| 40 | Black 黑色背景 | |
| 41 | Red 红色背景 | |
| 42 | Green 绿色背景 | |
| 43 | Yellow 黄色背景 | |
| 44 | Blue 蓝色背景 | |
| 45 | Magenta 紫色背景 | |
| 46 | Cyan 靛蓝色背景 | |
| 47 | White 白色背景 | |
| 48 | Set background color | 设置前景颜色, 接下来的参数是 5;n 或 2;r;g;b |
| 49 | 默认背景颜色 | |
| 50 | Disable proportional spacing | 禁用等比例空格 |
| 51 | Framed | mintty 中被实现为 emoji 选择器(?) |
| 52 | Encircled | 同上 |
| 53 | Overlinked | 没效果 |
| 54 | Neither framed nor encircled | |
| 55 | Not overlined | |
| 58 | Set underline color | 设置下划线颜色。不是标准规定的。Kitty, VTE, iTerm2里有实现;下一个参数需要是 5;n 或 2;r;g;b 形式 |
| 59 | Default underline color | 默认下划线颜色. 非标准。在 Kitty, VTE, iTerm2里有实现 |
| 60~65 | 通常没有实现 | |
| 73-74 | Superscript, Subscript | 上标和下标。只在 mintty 里有实现 |
| 75-76 | Neither superscript nor subscript | 取消上标和下标 |
| 90-97 | Set bright foreground color | 设置前景颜色亮度。非标准. iTerm2里有效 |
| 90 | Bright Black | 亮黑色前景色 |
| 91 | Bright Red | 亮红色前景色 |
| 92 | Bright Green | 亮绿色前景色 |
| 93 | Bright Yellow | 亮黄色前景色 |
| 94 | Bright Blue | 亮蓝色前景色 |
| 95 | Bright Magenta | 亮紫色前景色 |
| 96 | Bright Cyan | 亮靛蓝色前景色 |
| 97 | Bright White | 亮白色前景色 |
| 100-107 | Set bright background color | 背景颜色亮度. iTerm2里有效 |
| 100 | Bright Black | 亮黑色背景色 |
| 101 | Bright Red | 亮红色背景色 |
| 102 | Bright Green | 亮绿色背景色 |
| 103 | Bright Yellow | 亮黄色背景色 |
| 104 | Bright Blue | 亮蓝色背景色 |
| 105 | Bright Magenta | 亮紫色背景色 |
| 106 | Bright Cyan | 亮靛蓝色背景色 |
| 107 | Bright White | 亮白色背景色 |
其中 n 为 38 是设置前景颜色 ESC[38;5;{ID}m, n 为 48 是设置背景颜色 ESC[48;5;{ID}m, ID 是具体的颜色, 见下图:

3.3 常见私有模式 (Common Private Modes)
https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797
| ESC 代码序列 | 描述 |
|---|---|
ESC[?25l] | 隐藏光标 |
ESC[?25h] | 显示光标 |
ESC[?47l] | 恢复屏幕 |
ESC[?47h] | 保存屏幕 |
ESC[?1049h] | 启用可选buffer |
ESC[?1049l] | 禁用可选bufer |
3.4 控制光标
https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797#cursor-controls
| ESC 代码序列 | 描述 |
|---|---|
ESC[H | 光标移动到 (0, 0) 位置 |
ESC[#A | 光标向上移动 # 行 |
ESC[#B | 光标向下移动 # 行 |
3.5 擦除功能 (Erase Functions)
https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797#erase-functions
| ESC Code | Description |
|---|---|
ESC[J | 清除光标位置到屏幕结束位置 |
ESC[0J | 同 ESC[J |
ESC[1J | 清除光标位置到屏幕开始 |
ESC[2J | 清除整个屏幕 |
ESC[3J | 清除保存的行 |
ESC[K | 清除当前光标位置到当前行末尾 |
ESC[0K | 同 ESC[K |
ESC[1K | 删除当前光标位置到当前行首 |
ESC[2K | 删除整行 |
4. 简单例子

#include <stdio.h>
#include <iostream>
#include <string>
#include <vector>
#include <numeric>int main()
{std::vector<int> codes = {1, 2, 3, 4, 7, 8, 9};std::generate_n(std::back_inserter(codes), 8, [n = 30]() mutable { return n++; });std::generate_n(std::back_inserter(codes), 8, [n = 40]() mutable { return n++; });std::generate_n(std::back_inserter(codes), 8, [n = 90]() mutable { return n++; });std::generate_n(std::back_inserter(codes), 8, [n = 100]() mutable { return n++; });for (const auto code : codes){printf("\e[%dmHello\e[mworld (n=%d)\n", code, code);}printf("\e[1;34mHello\e[0mworld (n=1;34)\n");printf("\e[38;5;2mHello\e[0mworld (n=38;5;2)\n");printf("\e[48;5;2mHello\e[0mworld (n=48;5;2)\n");return 0;
}
5. 复杂例子 - 方块下落
绘制最小的绿色矩形: 打印“空格” 字符, 并且让空格字符的前景颜色红色的:
printf("\e[42m \e[0m\n");
绘制较大的红色矩形: 每一行打印多个空格, 连续打印多行; 每一行打印时使用转义字符。
printf("\e[42m \e[0m\n");
绘制会下落的红色矩形框: 先绘制一个,长度持续增加的。
void draw_box()
{for (int i = 0; i < 10; i++){printf("\e[42m \e[0m\n");std::this_thread::sleep_for(std::chrono::milliseconds(100));}
}
通过 ANSI Escape Sequence, 修改光标位置, 然后再绘制矩形:
void draw_box2()
{printf("\e[H"); // 光标移动到 (0,0) 位置printf("\e[42m \e[0m"); // 绘制绿色背景的空格printf("\e[1B"); // 光标往下一行。 注意此时 column 方向上, 光标不是在0位置printf("\e[43m \e[0m"); // 绘制黄色背景的空格
}
让每一行的绘制, 都从第 6 列开始绘制, 并且每次绘制后, 等待 100 毫秒:
void draw_box6()
{printf("\e[?25l"); // 隐藏光标, 避免光标导致的白色小方框for (int i = 0; i < 10; i++){printf("\e[2J"); // 清空整个屏幕printf("\x1b[%d;%dH\e[0m", i, 6); // 光标一定到第i 行,第 6 列printf("\e[42m \e[0m"); // 绘制绿色矩形: 也就是绘制绿色背景的空格fflush(stdout); // 确保绘制到控制台std::this_thread::sleep_for(std::chrono::milliseconds(500)); // 暂停 500 毫秒,营造下落的视觉效果}printf("\e[?25h"); // 恢复光标的可见性
}

6. ANSI Escape 的局限
无法绘制圆形。 因为终端绘制的最小单位, 是单个字符,每个字符通常是竖条而不是正方形, 并且竖条比较大, 大于通常看到的图像像素。 这就导致, 稍微复杂的图形无法绘制, 需要选择其他的方案:
- 使用 opencv 的 Mat 绘制, 用 imshow 显示
- 使用 SFML / SDL / Dear imgui / Qt 绘制和显示
7. References
- 手把手教你写俄罗斯方块:2-如何在终端上绘图
- ANSI Escape Codes
- C语言实现 log 库
相关文章:
ANSI Escape Sequence 下落的方块
ANSI Escape Sequence 下落的方块 1. ANSI Escape 的用途 无意中发现 B站有人讲解, 完全基于终端实现俄罗斯方块。 基本想法是借助于 ANSI Escape Sequence 实现方方块的绘制、 下落动态效果等。对于只了解 ansi escape sequence 用于 log 的颜色打印的人来说&…...
Vagrant 虚拟机工具基本操作指南
Vagrant 虚拟机工具基本操作指南 #虚拟机 # #vargant# #ubuntu# 虚拟机virtualbox ,VMWare及WSL等大家都很了解了,那Vagrant是什么东西? 它是一组命令行工具,可以象Docker管理容器一样管理虚拟机,这样快速创…...
中年低端中产程序员从西安出发到海南三亚低成本吃喝万里行:西安-南宁-湛江-雷州-徐闻-博鳌-陵水-三亚-重庆-西安
文章大纲 旅途规划来回行程的确定南宁 - 北海 - 湛江轮渡成为了最终最大的不确定性!感谢神州租车气温与游玩地点总体花费 游玩过程出发时间:Day1-1月25日星期四,西安飞南宁路途中:Day2-1月26日星期五,南宁-湛江-住雷州…...
企业级Spring boot项目 配置清单
目录 一、服务基础配置 二、配置数据库数据源 三、配置缓存 四、配置日志 五、配置统一异常处理 六、配置swagger文档 七、配置用户登录模块 八、配置websocket 九、配置定时任务 十、配置文件服务器 十一、配置Nacos 十二、配置项目启动数据库默认初始化(liquibas…...
WordPress函数wptexturize的介绍及用法示例,字符串替换为HTML实体
在查看WordPress你好多莉插件时发现代码中使用了wptexturize()函数用来随机输出一句歌词,下面boke112百科就跟大家一起来学习一下WordPress函数wptexturize的介绍及用法示例。 WordPress函数wptexturize介绍 wptexturize( string $text, bool $reset false ): st…...
【Iceberg学习三】Reporting和Partitioning原理
Metrics Reporting Type of Reports 从 1.1.0 版本开始,Iceberg 支持 MetricsReporter 和 MetricsReport API。这两个 API 允许表达不同的度量报告,并支持一种可插拔的方式来报告这些报告。 ScanReport(扫描报告) 扫描报告&am…...
肯尼斯·里科《C和指针》第12章 使用结构和指针(1)链表
只恨当时学的时候没有读到这本书,,,,,, 12.1 链表 有些读者可能还不熟悉链表,这里对它作一简单介绍。链表(linked list)就一些包含数据的独立数据结构(通常称为节点)的集…...
Xray 工具笔记
Xray 官方文档 扫描单个url(非爬虫) 并输出文件(不同文件类型) .\xray.exe webscan --url 10.0.0.6:8080 --text-output result.txt --json-output result.json --html-output report.html默认启动所以内置插件 ,指定…...
Linux环境下配置HTTP代理服务器教程
大家好,我是你们可爱的Linux小助手!今天,我将带你们一起探索如何在Linux环境下配置一个HTTP代理服务器。请注意,这不是一次火箭科学的实验,而是一次简单而有趣的冒险。 首先,我们需要明确什么是HTTP代理服…...
JavaEE作业-实验三
目录 1 实验内容 2 实验要求 3 思路 4 核心代码 5 实验结果 1 实验内容 简单的线上图书交易系统的web层 2 实验要求 ①采用SpringMVC框架,采用REST风格 ②要求具有如下功能:商品分类、订单、购物车、库存 ③独立完成,编写实验报告 …...
K8S容器挂了后重启状态正常,但应用无法访问排查处理
K8S容器挂了后重启状态正常,但应用无法访问排查处理 背景: 应用迁移K8S后因POD OOM挂了后重启,集群上POD状态正常,但应用无法访问。 排查: 查看应用日志,是启动时调用特权账号管理系统超时,…...
问题:老年人心理健康维护与促进的原则为________、________、发展原则。 #媒体#知识分享
问题:老年人心理健康维护与促进的原则为________、________、发展原则。 参考答案如图所示...
【超高效!保护隐私的新方法】针对图像到图像(l2l)生成模型遗忘学习:超高效且不需要重新训练就能从生成模型中移除特定数据
针对图像到图像生成模型遗忘学习:超高效且不需要重新训练就能从生成模型中移除特定数据 提出背景如何在不重训练模型的情况下从I2I生成模型中移除特定数据? 超高效的机器遗忘方法子问题1: 如何在图像到图像(I2I)生成模型中进行高效…...
Transformer的PyTorch实现之若干问题探讨(二)
在《Transformer的PyTorch实现之若干问题探讨(一)》中探讨了Transformer的训练整体流程,本文进一步探讨Transformer训练过程中teacher forcing的实现原理。 1.Transformer中decoder的流程 在论文《Attention is all you need》中࿰…...
解释Python中的GIL(全局解释器锁)及其影响。描述Python中的垃圾回收机制。Python中的类变量和实例变量有什么区别
解释Python中的GIL(全局解释器锁)及其影响 Python中的GIL(全局解释器锁)是CPython解释器中的一个机制,用于同步线程的执行。GIL确保任何时候只有一个线程在执行Python字节码。这意味着,即使在多核或多处理器…...
Appium使用初体验之参数配置,简单能够运行起来
一、服务器配置 Appium Server配置与Appium Server GUI(可视化客户端)中的配置对应,尤其是二者如果不在同一台机器上,那么就需要配置Appium Server GUI所在机器的IP(Appium Server GUI的HOST也需要配置本机IP…...
Java:JDK8新特性(Stream流)、File类、递归 --黑马笔记
一、JDK8新特性(Stream流) 接下来我们学习一个全新的知识,叫做Stream流(也叫Stream API)。它是从JDK8以后才有的一个新特性,是专业用于对集合或者数组进行便捷操作的。有多方便呢?我们用一个案…...
【Unity ShaderGraph】| 物体靠近时局部溶解,根据坐标控制溶解的位置【文末送书】
前言 【Unity ShaderGraph】| 物体靠近时局部溶解,根据坐标控制溶解的位置一、效果展示二、根据坐标控制溶解的位置,物体靠近局部溶解三、应用实例👑评论区抽奖送书 前言 本文将使用ShaderGraph制作一个根据坐标控制溶解的位置,物…...
测试OpenSIPS3.4.3的lua模块
这几天测试OpenSIPS3.4.3的lua模块,记录如下: 有bug,但能用 但现实世界就是这样,总是不完美的,发现之后马上提了issue 下面这段代码运行报错: function func1(msg) xlog("ERR","…...
【机器学习】数据清洗之处理缺失点
🎈个人主页:甜美的江 🎉欢迎 👍点赞✍评论⭐收藏 🤗收录专栏:机器学习 🤝希望本文对您有所裨益,如有不足之处,欢迎在评论区提出指正,让我们共同学习、交流进步…...
z.lua 项目贡献指南:如何参与这个开源工具的开发
z.lua 项目贡献指南:如何参与这个开源工具的开发 【免费下载链接】z.lua :zap: A new cd command that helps you navigate faster by learning your habits. 项目地址: https://gitcode.com/gh_mirrors/zl/z.lua 欢迎来到 z.lua 项目贡献指南!z.…...
喜马拉雅音频下载工具:技术实现与高效使用指南
喜马拉雅音频下载工具:技术实现与高效使用指南 【免费下载链接】xmly-downloader-qt5 喜马拉雅FM专辑下载器. 支持VIP与付费专辑. 使用GoQt5编写(Not Qt Binding). 项目地址: https://gitcode.com/gh_mirrors/xm/xmly-downloader-qt5 在数字化学习与娱乐场景…...
GEO时代媒体发布新范式:Infoseek如何用工程思维重构内容分发
上周跟一个做技术社区运营的朋友聊天,他吐槽了一件事:公司新功能上线,想发篇技术解读稿,找了家公关公司报价,一篇3000块,承诺发30家媒体,但具体发哪家、什么时候发、效果怎么样,全凭…...
[OS] Rate Monotonic Scheduling: Optimizing Real-Time Task Prioritization
1. 速率单调调度:实时系统的优先级管理艺术 想象一下急诊室的医生如何决定救治顺序——心跳停止的患者永远优先于感冒发烧的病人。速率单调调度(Rate Monotonic Scheduling,RMS)就是实时操作系统中的这位"分诊专家"&am…...
【图灵完备(Turing Complete)】五、从逻辑门到LEG:指令集与条件跳转的构建
1. 从逻辑门到处理器:LEG架构的诞生之路 记得我第一次用面包板搭建简单逻辑电路时,连个LED灯闪烁都要折腾半天。而现在我们要做的,是把这些基础逻辑门像乐高积木一样拼接成真正的处理器核心。LEG架构的设计初衷就是要解决原始图灵机指令宽度受…...
GD32F450VK移植RT-Thread时如何避免SRAM分区导致的HardFault(附解决方案)
GD32F450VK移植RT-Thread的SRAM分区陷阱与实战解决方案 在嵌入式开发领域,GD32F4系列微控制器凭借其出色的性价比和丰富的外设资源,正逐渐成为工业控制、物联网终端等场景的热门选择。然而,当开发者尝试将RT-Thread实时操作系统移植到GD32F4…...
科研写作效率提升300%:WPS-Zotero跨平台文献管理终极指南
科研写作效率提升300%:WPS-Zotero跨平台文献管理终极指南 【免费下载链接】WPS-Zotero An add-on for WPS Writer to integrate with Zotero. 项目地址: https://gitcode.com/gh_mirrors/wp/WPS-Zotero WPS-Zotero是一款革命性的WPS Office插件,专…...
告别BibTeX混乱:在LaTeX中精准控制单条参考文献格式(颜色、字体)的实战技巧
告别BibTeX混乱:在LaTeX中精准控制单条参考文献格式(颜色、字体)的实战技巧 学术写作中,参考文献的视觉呈现往往被忽视。当审稿人要求"突出显示新增文献"时,当需要区分自己的前期工作与奠基性研究时&#x…...
AudioSeal实战教程:Python API调用AudioSeal模型实现批量音频水印处理
AudioSeal实战教程:Python API调用AudioSeal模型实现批量音频水印处理 1. 项目概述与核心价值 AudioSeal是Meta开源的专业级音频水印系统,专门用于AI生成音频的检测和溯源。这个工具能帮助内容创作者、平台运营者和版权方解决一个关键问题:…...
Inner-IoU: More Effective Intersection over Union Loss with Auxiliary Bounding Box——基于辅助边界框的更有效交并比损失
这篇题为《Inner-IoU: More Effective Intersection over Union Loss with Auxiliary Bounding Box》的论文,主要研究了目标检测中边界框回归(BBR)损失函数的改进问题。以下是其核心研究内容的全面总结概括: 1. 研究背景与问题 现…...
