我们常常会在一些好莱坞电影大片里看到黑客高手,在电脑前轻松“黑”进别人的安全系统的场景。那纯熟自如地输入一大堆复杂的代码,瞬间完成入侵,是不是很羡慕?
电影The Matrix (《黑客帝国》)则是用通过现实与虚拟世界的抗争,摆脱“矩阵”的计算机人工智能系统的控制,尤其是自带超炫酷字符雨背景,总是无时无刻不在散发着黑客无所不能、神出鬼没的魅力。
今天,小编教大家尝试用Python制作一个高仿的matrix字符雨的效果。
在屏幕上输出文字,首先想到的是使用print函数
>>>>
代码原文:
importtime
text="Hello world!"
forcharintext:
print(char)
time.sleep(0.3)
time.sleep(1)
但是,print函数的功能是:换行➩输出字符➩换行,想要在命令行中通过刷新屏幕来输出文字是做不到的
展开全文
无奈耿直的print函数始终保持换行又换行的底线,只能另择他法!
Print函数达不到目的,我们把目光转向更底层的机制--使用标准输出stdout
>>>>
代码原文:
importsys
importtime
text="Hello world!"
forcharintext:
sys.stdout.write(char)
sys.stdout.flush()
time.sleep(0.1)
sys.stdout.write("r"+" "*len(text)+"r")
sys.stdout.flush()
forcharintext:
sys.stdout.write(char)
sys.stdout.flush()
time.sleep(0.1)
sys.stdout.write("n")
sys.stdout.flush()
time.sleep(1)
使用sys.stdout来输出,终于可以在一行内刷新文字了,但是无法回到上一行,遇到换行只能继续向下输出了
使用stdout,仍然一路向下
不得已只好祭出更加底层的杀器-curses库,curses库是linux底层提供的方法库,可以直接操作显示屏的输出和刷新,而不是以字符和换行的形式使用命令行输出,这一定能满足我们的需求
>>>>
代码原文:
importcurses
importtime
importrandom
whileTrue:
stdscr=curses.initscr()
width=80
height=24
text="我在這裏,來抓我呀"
try:
stdscr.clear()
x=random.randrange(1,width)
y=random.randrange(1,height)
ifx+len(text)<width:
stdscr.addstr(y,x,text)
stdscr.refresh()
time.sleep(0.5)
exceptKeyboardInterrupt:
curses.endwin()
exit(0)
好了,现在开始放大招了,编写matrix的字符串效果具体如下↓
先简单设计一下,做一个能填满屏幕的字符串,中间夹杂空格,只要让这个字符串在屏幕不断滚动就能营造出字符雨的效果
>>>>
代码原文:
importcurses,time,random
defrefresh_str(string):
returnstring[-1]+string[0:-1]
defmain(stdscr):
height,width=stdscr.getmaxyx()
string=""
length=0
foriinrange(height*width-1):
iflength==0:
length=random.randrange(int(height/4),int(height/2))
roll=random.random()
ifroll>0.5:
char=" "
else:
char=chr(random.randrange(48,50))
string+=char
length-=1
whileTrue:
string=refresh_str(string)
curses.init_pair(1,curses.COLOR_GREEN,curses.COLOR_BLACK)
count=0
foriinrange(width):
forjinrange(height):
ifcount<len(string):
stdscr.addstr(j,i,string[count],curses.color_pair(1))
count+=1
stdscr.refresh()
time.sleep(0.03)
curses.wrapper(main)
代码有了,现在试试看吧!
奇迹发生了,效果不错哦!但是…好刺眼
前面的程序有两点问题,一是字符是运动的,而原版字不动只是黑色部分动,二是字符不是随机变换的,看着不够逼真那么,再更新我们的算法
根据已经存在的字符长度,随机生成字符和空格,并以合理的几率落下,形成真正的字符雨
>>>>
代码原文:
importcurses
importrandom
importtime
defmatrix(width,height):
matrix={}
foriinrange(1,width):
forjinrange(1,height):
matrix[(i,j)]=" "
whileTrue:
foriinrange(1,width):
ifi%2==0:
forjinrange(height-1,1,-1):
ifmatrix[(i,j)]==" ":
ifmatrix[(i,j-1)]!=" ":
matrix[(i,j)]=chr(random.randrange(33,127))
else:
continue
else:
ifmatrix[(i,j-1)]==" ":
matrix[(i,j)]=" "
else:
continue
roll=random.random()
ifroll>0.5:
ifmatrix[(i,1)]==" ":
is_space=True
else:
is_space=False
length=0
forjinrange(2,height):
ifis_space==Trueandmatrix[(i,j)]==" ":
length+=1
elifis_space==Falseandmatrix[(i,j)]!=" ":
length+=1
if(is_space==Falseand
length<random.randrange(height*45//60,height*5//6)):
matrix[(i,1)]=chr(random.randrange(34,127))
elif(is_space==Falseand
length>random.randrange(height*45//60,height*5//6)):
matrix[(i,1)]=" "
elif(is_space==Trueand
length<random.randrange(height//4,height//2)):
matrix[(i,1)]=" "
elif(is_space==Trueand
length>random.randrange(height//4,height//2)):
matrix[(i,1)]=chr(random.randrange(34,127))
yieldmatrix
defmain(stdscr):
height,width=stdscr.getmaxyx()
m=matrix(width,height)
whileTrue:
curses.init_pair(1,curses.COLOR_GREEN,curses.COLOR_BLACK)
curses.init_pair(2,curses.COLOR_WHITE,curses.COLOR_BLACK)
m_now=next(m)
foriinrange(1,width-1):
forjinrange(1,height-1):
ifm_now[(i,j+1)]==" "andm_now[(i,j)]!=" ":
stdscr.addstr(j,i,m_now[(i,j)],curses.color_pair(2))
else:
stdscr.addstr(j,i,m_now[(i,j)],curses.color_pair(1))
stdscr.refresh()
time.sleep(0.03)
curses.wrapper(main)
终极效果↓↓↓
Emmmmm….效果不错,非常棒
思考
虽然最终完成的效果非常拟真,但我们可以继续改进,观察原版的效果我们可以知道,字符并不是随机出现的,而是偶尔有连续的有意义的字符串,还夹杂有日文字符和编程语言碎片,你能否设计出这样的算法使我们的matrix更加逼真呢?可以留言哦!
感兴趣的小伙伴可以入群讨论哦!