用电视写代码(电视剧里的代码真能运行吗?)
大家好 ,欢迎来到 Crossin的编程教室 !
前几天 ,后台老有小伙伴留言“爱心代码 ” 。这不是Crossin很早之前发过的内容嘛 ,怎么最近突然又被人翻出来了?后来才知道 ,原来是一部有关程序员的青春偶像剧《点燃我,温暖你》在热播 ,而剧中有一段关于期中考试要用程序画一个爱心的桥段 。
于是出于好奇 ,Crossin就去看了这一集(第5集 ,不用谢) 。这一看不要紧 ,差点把刚吃的鸡腿给喷出来--槽点实在太多了!
忍不住做了个欢乐吐槽向的代码解读视频 ,在某平台上被顶到了20个w的浏览,也算蹭了一波人家电视剧的热度吧…
https://www.bilibili.com/video/BV1GY411o72m/
下面是图文版 ,给大家分析下剧中出现的“爱心 ”代码 ,并且来复刻一下最后男主完成的酷炫跳动爱心 。
剧中代码赏析 首先是路人同学的代码:虽然剧中说是“C语言期中考试”,但这位同学的代码名叫 draw2.py ,一个典型的 Python 文件 ,再结合截图中的 pen.forward 、pen.setpos 等方法来看,应该是用 turtle 海龟作图库来画爱心 。那效果通常是这样的:
import turtle as t t.color(red) t.setheading(50) t.begin_fill() t.circle(-100, 170) t.circle(-300, 40) t.right(38) t.circle(-300, 40) t.circle(-100, 170) t.end_fill() t.done()而不是剧中那个命令行下用1组成的不规则的图形 。
然后是课代表向路人同学展示的优秀代码:及所谓的效果:
这确实是C语言代码了 ,但文件依然是以 .py 为后缀 ,并且 include 前面没有加上 # ,这显然是没法运行的 。
里面的内容是可以画出爱心的 ,用是这个爱心曲线公式:
然后遍历一个1517的方阵 ,计算每个坐标是在曲线内还是曲线外 ,在内部就输出#或 ,外部就是-
用python改写一下是这样的:
for y in range(9, -6, -1): for x in range(-8, 9): print(*##*[(x+10)%4] if (x*x+y*y-25)**3 < 25*x*x*y*y*y else -, end=) print()效果:
稍微改一下输出 ,还能做出前面那个全是1的效果:
for y in range(9, -6, -1): for x in range(-8, 9): print(1 if (x*x+y*y-25)**3 < 25*x*x*y*y*y else , end=) print()但跟剧中所谓的效果相去甚远 。
最后是主角狂拽酷炫D炸天的跳动爱心:代码有两个片段:
但这两个片段也不C语言 ,而是C++,且两段并不是同一个程序 ,用的方法也完全不一样 。
第一段代码跟前面一种思路差不多 ,只不过没有直接用一条曲线,而是上半部用两个圆形 ,下半部用两条直线 ,围出一个爱心。
改写成 Python 代码:
size = 10 for x in range(size): for y in range(4*size+1): dist1 = ((x-size)**2 + (y-size)**2) ** 0.5 dist2 = ((x-size)**2 + (y-3*size)**2) ** 0.5 if dist1 < size + 0.5 or dist2 < size + 0.5: print(V, end=) else: print(, end=) print() for x in range(1, 2*size): for y in range(x): print(, end=) for y in range(4*size+1-2*x): print(V, end=) print()运行效果:
第二段代码用的是基于极坐标的爱心曲线,是遍历角度来计算点的位置 。公式是:
计算出不同角度对应的点坐标 ,然后把它们连起来 ,就是一个爱心 。
from math import pi, sin, cos import matplotlib.pyplot as plt no_pieces = 100 dt = 2*pi/no_pieces t = 0 vx = [] vy = [] while t <= 2*pi: vx.append(16*sin(t)**3) vy.append(13*cos(t)-5*cos(2*t)-2*cos(3*t)-cos(4*t)) t += dt plt.plot(vx, vy) plt.show()效果:
代码中循环时用到的2π是为了保证曲线长度足够绕一个圈 ,但其实长一点也无所谓 ,即使 π=100 也不影响显示效果 ,只是相当于同一条曲线画了很多遍。所以剧中代码里写下35位小数的π ,还被女主用纸笔一字不落地抄写下来 ,实在是让程序员无法理解的迷惑行为 。
但不管写再多位的π ,上述两段代码都和最终那个跳动的效果差了五百只羊了个羊 。
跳动爱心实现作为一个总是在写一些没什么乱用的代码的编程博主 ,Crossin当然也不会放过这个机会,下面就来挑战一下用 Python 实现最终的那个效果。
想要绘制动态的效果 ,必定要借助一些库的帮助 ,不然代码量肯定会让你感动得想哭 。这里我们将使用之前 羊了个羊游戏 里用过的 pgzero 库 。然后结合最后那个极坐标爱心曲线代码,先绘制出曲线上离散的点 。 import pgzrun from math import pi, sin, cos no_p = 100 dt = 2*3/no_p t = 0 x = [] y = [] while t <= 2*3: x.append(16*sin(t)**3) y.append(13*cos(t)-5*cos(2*t)-2*cos(3*t)-cos(4*t)) t += dt def draw(): screen.clear() for i in range(len(x)): screen.draw.filled_rect(Rect((x[i]*10+400, -y[i]*10+300), (4, 4)), pink) pgzrun.go() 把点的数量增加 ,同时沿着原点到每个点的径向加一个随机数 ,并且这个随机数是按照正态分布来的(半个正态分布),大概率分布在曲线上 ,向曲线内部递减 。这样 ,就得到这样一个随机分布的爱心效果 。 ... no_p = 20000 ... while t <= 2*pi: l = 10 - abs(random.gauss(10, 2) - 10) x.append(l*16*sin(t)**3) y.append(l*(13*cos(t)-5*cos(2*t)-2*cos(3*t)-cos(4*t))) t += dt ... 下面就是让点动起来 ,这步是关键 ,也有一点点复杂 。为了方便对于每个点进行控制 ,这里将每个点自定义成了一个Particle类的实例 。从原理上来说 ,就是给每个点加一个缩放系数 ,这个系数是根据时间变化的正弦函数 ,看起来就会像呼吸的节律一样 。
class Particle(): def __init__(self, pos, size, f): self.pos = pos self.pos0 = pos self.size = size self.f = f def draw(self): screen.draw.filled_rect(Rect((10*self.f*self.pos[0] + 400, -10*self.f*self.pos[1] + 300), self.size), hot pink) def update(self, t): df = 1 + (2 - 1.5) * sin(t * 3) / 8 self.pos = self.pos0[0] * df, self.pos0[1] * df ... t = 0 def draw(): screen.clear() for p in particles: p.draw() def update(dt): global t t += dt for p in particles: p.update(t) 剧中爱心跳动时 ,靠中间的点波动的幅度更大,有一种扩张的效果 。所以再根据每个点距离原点的远近 ,再加上一个系数 ,离得越近,系数越大。 class Particle(): ... def update(self, t): df = 1 + (2 - 1.5 * self.f) * sin(t * 3) / 8 self.pos = self.pos0[0] * df, self.pos0[1] * df 最后再用同样的方法画一个更大一点的爱心 ,这个爱心不需要跳动 ,只要每一帧随机绘制就可以了 。 def draw(): ... t = 0 while t < 2*pi: f = random.gauss(1.1, 0.1) x = 16*sin(t)**3 y = 13*cos(t)-5*cos(2*t)-2*cos(3*t)-cos(4*t) size = (random.uniform(0.5,2.5), random.uniform(0.5,2.5)) screen.draw.filled_rect(Rect((10*f*x + 400, -10*f*y + 300), size), hot pink) t += dt * 3合在一起,搞定!
总结一下 ,就是在原本的基础爱心曲线上加上一个正态分布的随机量 、一个随时间变化的正弦函数和一个跟距离成反比的系数 ,外面再套一层更大的随机爱心 ,就得到类似剧中的跳动爱心效果 。
但话说回来 ,真有人会在考场上这么干吗?
除非真的是超级大学霸 ,不然就是食堂伙食太好--
吃太饱撑的……
代码已开源:python666.cn/c/9
如二创发布请注明代码来源:Crossin的编程教室创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!