​咱们好,欢迎来到 Crossin的编程教室 !

前几天,后台老有小伙伴留言“爱心代码”。这不是Crossin很早之前发过的内容嘛,怎样最近忽然又被人翻出来了?后来才知道

,原来是一部有关程序员的芳华偶像剧《点燃我,温暖你》在热播,而剧中有一段关于期中考试要用程序画一个爱心的桥段。

于是出于猎奇,Crossin就去看了这一集(第5集,不用谢)。这一看不要紧,差点把刚吃的鸡腿给喷出来–槽点实在太多了!

不由得做了个欢乐吐槽向的代码解读视频,在某平台上被顶到了20个w的阅读,也算蹭了一波人家电视剧的热度吧……电视剧里的代码真能运行吗?

下面是图文版,给咱们分析下剧中出现的“爱心”代码,而且来复刻一下终究男主完结的酷炫跳动爱心。

剧中代码赏析

1. 首先是路人同学的代码:

电视剧里的代码真能运行吗?

尽管剧中说是“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组成的不规则的图形。

2. 然后是课代表向路人同学展示的优异代码:

电视剧里的代码真能运行吗?

及所谓的作用:

电视剧里的代码真能运行吗?

这确实是C语言代码了,但文件仍然是以 .py 为后缀,而且 include 前面没有加上 #,这显然是没法运转的。

里边的内容是可以画出爱心的,用是这个爱心曲线公式:

电视剧里的代码真能运行吗?

然后遍历一个15*17的方阵,核算每个坐标是在曲线内仍是曲线外,在内部就输出#或*,外部便是-

用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()

电视剧里的代码真能运行吗?

但跟剧中所谓的作用相去甚远。

3. 终究是主角狂拽酷炫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 完成终究的那个作用。

1. 想要绘制动态的作用,必定要借助一些库的帮助,不然代码量肯定会让你感动得想哭。这儿咱们将使用之前 羊了个羊游戏 里用过的 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()

电视剧里的代码真能运行吗?

2. 把点的数量添加,同时沿着原点到每个点的径向加一个随机数,而且这个随机数是按照正态散布来的(半个正态散布),大概率散布在曲线上,向曲线内部递减。这样,就得到这样一个随机散布的爱心作用。

...
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
...

电视剧里的代码真能运行吗?

3. 下面便是让点动起来,这步是关键,也有一点点复杂。为了便利关于每个点进行操控,这儿将每个点自定义成了一个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)

电视剧里的代码真能运行吗?

4. 剧中爱心跳动时,靠中间的点动摇的幅度更大,有一种扩张的作用。所以再根据每个点间隔原点的远近,再加上一个系数,离得越近,系数越大。

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

电视剧里的代码真能运行吗?

5. 终究再用相同的办法画一个更大一点的爱心,这个爱心不需要跳动,只需每一帧随机绘制就可以了。

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的编程教室