全文一览
一、前言
1.1 需求来源
我们通常能在电影中看到这样的场景:一个黑客坐在幽暗的房间中央,脸上打着来自屏幕的绿光,而屏幕则在匀速地向上滚动,一个个英文字符划过,宛如天空上的流星……
这个场景很酷,本文决定对该场景做一个小小的模拟。
1.2 模拟思路
这个场景其实本质上可以拆解为黑底绿字、屏幕滚动并引入随机三个功能。
1.2.1 黑底绿字
要实现黑底绿字,可以通过终端的输出格式来控制。通过转义方 “\033[显示方式;前景色;背景色m” 来控制其后面字符的显示格式、显示颜色和背景色.
①“\033[1;32;40m” 表示高亮显示 、绿色、黑色背景。
②打印“\033[0;0;40m” 能将后续输出的背景全部设置为黑色。
③通过不同的显示方式和绿色的组合,能够打印不同程度绿色的字符。
④在运行结束时,通过打印 “\033[0m” 可以将打印格式恢复到默认形式。
1.2.2 屏幕滚动
确定每行能打印的字符数 num 后,在打印完 num 个字符后换行打印,结合 time.sleep即可实现屏幕匀速滚动。
本文中确定了两个函数 print_line 和 print_random_char。前者用于实现按行打印,后者则辅助前者用于确认每一行中每一个位置应该以什么颜色打印什么字符。
1.2.3 随机引入
在一行中,有的位置会打印空格。首先初始化 status_list 来确定每个位置是否打印空格以及打印的格式。打印字符的比例为 p1。
在下一行中:
①不打印空格的位置,以 p2 的概率仍不打印空格,以 1-p2 的概率打印空格。
②打印空格的位置,,以 p3 的概率不打印空格。
要维持下一行与上一行中,字符与空格的占比动态稳定,需满足:
# p1 * (p2) + (1 - p1) * p3 = p1
p3 = p1 * (1 - p2) / (1 - p1)
二、代码解析
2.1 颜色类 Color
本文将颜色封装在 Color 类中。包含背景色、不同的绿色以及原色。
# 要打印的字符颜色
class Color:
LIGHT_GREEN = '\033[28;92m'
LIGHT_BOLD_GREEN = '\033[1;92m'
DARK_GREEN = '\033[28;32m'
DARK_BOLD_GREEN = '\033[1;32m'
BACK_GROUND = '\033[40m' # 默认黑色背景
END = '\033[0m' # 清除格式
背景色应放在打印最初,用于设置后续背景;原色则放在最后,用于消除格式、恢复初始打印状态。
print(Color.BACK_GROUND + "BACK_GROUND")
print(Color.LIGHT_GREEN + "LIGHT_GREEN")
print(Color.LIGHT_BOLD_GREEN + "LIGHT_BOLD_GREEN")
print(Color.DARK_GREEN + "DARK_GREEN")
print(Color.DARK_BOLD_GREEN + "DARK_BOLD_GREEN")
print(Color.END + "END")
打印结果如下图。可知,Color.BACK_GROUND 可以将后续背景设置为黑色;Color.END 能将打印恢复为图原先的样式;不同的颜色和显示方式的组合,打印的字符样式不同(不同设备上会略有差异)。
2.2 屏幕滚动类 HackerScreen
2.2.1 初始化
设置屏幕能显示的字符数 num、每行中不打印空格的比率 p1、下一行中仍打印字符的概率 p2、下一行中不打印空格了的概率 p3、每行显示的时间间隔 time_span 秒。
def __init__(self, num=150, p1=0.19, p2=0.93, p3=0.01641975308641974, time_span=0.05):
# 要打印的字符集
self.chars = [chr(ord('a') + i) for i in range(26)] + [