Skip to content

Instantly share code, notes, and snippets.

@tompng
Last active May 20, 2024 08:40
Show Gist options
  • Save tompng/a4ca6eca4836014afe8a68227fdd7cac to your computer and use it in GitHub Desktop.
Save tompng/a4ca6eca4836014afe8a68227fdd7cac to your computer and use it in GitHub Desktop.
⠁⠠⠐⢀⢀⠄⠁⠄⠐⠂⠁⢀⠁⢀⠈⢀⢀⠈
⠠⠈⠈⠄⠁⡁⡁⠃⢅⡤⠴⡔⢉⢄⢁⡄⠙⡐⢃⠬⠎⢁⡠⠢⡂⠌⠈⢀⢀⠈
⠁⠠⠐⡈⠆⢁⢅⢅⡰⣐⠔⡖⠍⢑⢕⢩⡲⠃⠌⡆⡊⠴⣔⠔⣐⠢⡜⡜⠠⠏⢀⠁⠆⠢⠊⠁⠐⡀
⠐⢀⡀⠰⠦⠉⢆⠖⠞⢸⠅⢒⢑⠺⡜⢴⣖⡞⢈⠏⡯⣚⠰⠃⣄⡻⢮⢞⣖⠿⢈⢸⡏⡨⠾⡬⠒⢐⡅⢠⠃⢁⡂⠑⠁⠐
⠐⢀⠤⠨⢁⠏⠛⠤⠏⠸⡂⠝;BEGIN{->s{eval((a="⡉⢐⡊⡕⢹⢨⡃⢚⣀⢃⠂⠠⠂⠜⠩⠄⠄⠠
⠄⢀⠑⠋⠅⠫⠄⠒⠏⡪⡕";s.gsub(/[^!-~]/,'')))}.[]"⠩⡖⡶⠹⢳⠄⢪⣇⣌⡪⡐⠃⠕⠜⠒⠈⠈
⠈⠂⠂⠊⢅⡍⡄⡗⣌⡴⠁⡒$s=[⡙⠭⣐⢚];⢧⡸de⢴f⡨(⠮⢵s⠷e⢗⠙⠏lf).⠖⢀⢤⣾⢱⢍⡰⠆⡔⠏⢑⠣⢈⡃⢀⡂⠐⡀
⠁⠁⠆⡢⢈⡡⠔⠛⡪⡲⢂⢊⣏met⣄⠂⣰hod⢭⠱_⢳mi⣷ssin⡫g⡓(a⠴⢸⡲)=$⠝⡎⣓⢵⣏⡢⢼⡐⢸⣋⣁⡰⠮⢤⡨⠤⡀⠂
⠄⠠⣀⡒⡋⠣⢌⠑⣇⡖⠧⣙⡙⣻⡌s<<⡾⡾a⡳.⢸to⢯_⡌s;⢟⣣⡾at_⠞e⡡x⠷⢒it{⢆⡝⣆⢛⠋⢮⡻⡖⡵⣍⡤⢑⡢⣡⠂⠭⠡⠙⠂⢀
⠠⠂⢂⢐⢀⡒⡋⡋⡱⣢⠋⡂⣕⢋⢪⠳⢁a,b⣃⢾=⣯⡆a.sp⡼l⡣it;⢼⡌c,*⣺⠰⢇d,e⢦⠧⡏⣪⣃⢯⢗⠶⣠⠦⠝⡲⠩⣃⢶⡮⠧⠱⡨⠒⠂⠈
⠂⠄⠰⡑⠁⠴⡬⠳⠍⢦⢘⠠⢺⣣⣈⢩⢆⣪⣲=s⠸⢉⡲.⠪⡀⠺⠙⡐⠐⠵⣛⢥⠫⠖⠊⣐⣕⣏⡥⢫⢟⠭spl⡆⡃⡽⢻⡍⡈⢲⢐⡠⠥⡒⢸⣾⣤⡝⡒⡀⢡⠱⠔⠚⠈⠠
⠠⠠⠡⡰⡘⡜⡴⣁⢮⠕⣸⡑⠋⣉⡓⢬⠮⡭⠓⣬it⢉⡻⣋⣇;$s[⡑⢓4]+=?x⠒⡅*20+a;$s[⡧⣿⣝⣔⣦⣿⣻⡡⠠⢣⣭⠔⢡⠙⠔⣂⢠⢌⠃⡂⠜⠠⠁
⠈⡀⠎⠐⡕⢄⢼⢖⣇⢰⣈⢒⠈⠖⣏⣺⣠⡈⣉⢊5]⠄⡮=e+?⡲⢒x*3+⢇⡜⣦⡏$s[5⠞⡹⡘⠗];$s[⣂⡗⡋⣭⢽⢎⡠⣏⢦⡓⣴⠽⢵⣠⠶⡮⡭⢈⠰⢈⠠⠈⠂
⠁⠂⠜⠎⠌⡑⠰⡪⠪⠵⣩⢃⢴⡇⢍⡉⢚⡾⠻⢮⢩5,0]=⣄⠣⠺⠣⣀⠿[b⡔⣚⢪⣻⡴⡖+?x⡬⡲⢿⣰⣉⡥*⢼28⣯⠡⡒⠾⠻⠳⠠⡨⣚⣠⡛⢟⣀⠃⠗⠭⢀⠋⢕⠦⠒⠠⠂
⠂⢀⠁⡂⠭⣢⠜⡹⡻⢶⣝⢕⡺⡂⡪⠮⢖⣠⣊⢉⣊+c]⡟⡮⢚⡾⣢⠯⡧⠹+d⣻⢘⠒⠊⣟⣂;n=⣝⢗⡙⡥⢛⡬0⣲;a⢖⠙⠪⡧⡗⡞⢃⠳⠡⢍⡨⣑⡄⠨⡖⡍⣈⡅⠡⠠⠬⢀⠠
⠠⠁⡀⠩⠧⡡⢁⣅⠴⢴⣈⣶⡔⢩⣻⠤⢙⢍⢛⢶⠚⢖⡝=(1⠨⡫⠺⣌⣷⠰⣟..2⡒⣜⢰⡫⠲⣲55)⡥⠡⣺⠂⡣⡬.⣾so⢮⣼⡚⠅⢯⣗⠼⣜⡑⣀⣲⣾⠹⢎⢇⠱⢇⢣⢂⡊⢈⡀⠐
⠁⠄⠓⣀⠨⡮⣁⡬⢷⣀⡬⡘⡥⢟⠓⡨⣯⢓⠻⢾⠠⢳⠻r⢄t⢛⠈⣼⢈⣹⡏⣠_⢵b⡮⡴⢼⢧⢷⢭y⣖{(⠿⡇⠌⠴⠢⣃'%b⣏⡰⠿⣛⡝⠦⣑⠷⢳⢀⠣⡀⣆⡶⣑⠌⡤⢓⠰⡀⡄⠠⠂
⢀⠁⡁⢅⠌⣠⠾⠘⣎⠽⡼⢦⡮⣣⣢⣓⣓⠝⠐⢵⢁⠎⠳⣆⣟'%⣾⢋⡬⣱⢙⡶⠌⠼_1)⢛⣱⠔⠹⢒.⣯c⣏o⢇⠎⣈⢎⠜unt⡶⡝⢪⢶⣿⠢⠄⡱⣤⣰⠞⢗⡘⠒⣕⠿⣬⠮⠼⠮⠈⠜⠁⠄
⡀⠐⠐⠂⡐⠽⠵⡓⢫⡈⢭⠺⠽⢨⢍⡳⠻⢼⡡⠺⠞⣢⡩⡤⡄(⠪?⢉⠹⠫⠧⡓⡳⠷1⠊)⢲⡿⢆⣕⡝⣦<⡒<⢮1⡴⣕⠏⣡⠩0|_⠐⢰⢍⢞⠑⢭⡤⣻⡪⣢⢑⢙⡨⡼⡥⢖⣖⡑⠏⠕⠂⡀⠐
⠁⢀⠆⠡⣠⠶⡼⣘⡗⣠⡫⢴⢹⣭⡅⣳⡺⡮⠩⢐⢔⠂⢯⣠⣮⢟1};⡧⠥⢊⡤⠞⠊⠃$s.⡋⢗⣁⡱⠶m⣂⡗ap⣅⢝⡿⢬⡻⢌{|⡡⣓⣒⢝⠊⡐⠧⠽⢵⣧⠋⢂⢻⢤⣜⡍⢏⣆⠊⠣⠄⠂⠁
⠠⠂⡈⡐⢅⠇⡊⢄⣲⠂⡆⠱⢍⠓⣸⠰⡻⣦⣟⣮⡩⠭⣔⡷⣤⠢s|(⣲⢖⣇⡲⣆⡜⣕m⡐=⠓⣩⣠⣠⣮s⢪⡥.⡅s⣙⢙⣍⠗⣨iz⣝⣸⠝⡀⢐⢪⠻⠝⣤⡟⢆⡢⡉⠓⣓⡄⠕⠹⡂⠬⡁⠂⠂
⢀⠐⠥⠂⢦⠨⡭⢒⣶⢶⠉⢆⡷⢆⡘⡗⠦⢘⠰⡄⠣⠬⠧⢆⣩⠜e)⣫.⠫⢩⡭⣏⠯⣻⠻tim⢍⢬⢵⣄e⣛⡔⢱s⡐{⣏⣕⢅⣎|i⣴⢟⢰⣷⣣⠢⢂⣖⣊⢶⣙⢿⠙⣄⠚⣠⢬⡙⡊⠘⢠⠂⢀
⡀⠠⠌⠝⠍⣃⠩⢹⢴⡅⢯⣴⡶⣩⣘⢨⡖⣏⡂⢂⡴⡜⡻⠞⠿⣰⠽|⣔⣜r⢌⢌⠃⡴⣐⠨=⡂4⢜⢴⠂⡾0⡮⣺⡜⠗-⡏i⡶⢌⢬*(m⡕⡣⢄⡑⣿⡴⣫⠙⣃⣔⢩⢜⣞⢌⣫⡆⢲⠳⠙⠙⠁⢀
⠠⠈⡈⢢⠡⡛⢁⠡⡂⡃⡍⡟⡬⣄⢄⢎⡩⡖⡷⢼⢎⡌⣞⢮⢁⣗+⢈⡬~⡢⠎⣰⢸⢶⠘⡮i)/⠥⢆⣮4⣨⢙⠳⢖0⣶⢢;⣐⡃s[i⡠⡋⣕⡝⣳⣳⠫⣦⡞⠱⡶⠤⢾⠈⡲⠁⢈⠗⠢⢀⠄
⠐⠄⠂⢤⠪⢬⠖⠑⣋⠱⡆⠍⠠⡵⡓⣤⢹⣥⣉⣗⢺⡗⢥⠖⣬⡹]⢦⠲>⢌⢥⢭⠂⣽⣀⠠?⠼~⣩⢰⢓&⢠⡚⢤⠓⢽&⡸⢧n⣮=a.⡃⣗⡒⡕⢍⣰⣣⢌⡑⡃⢤⣞⡔⠕⣔⠭⠭⠬⠢⠐⠈
⢀⢀⠆⣄⠈⣤⣎⣄⢋⢗⡹⢊⠑⠢⡥⢡⠅⢿⡐⡁⡌⠹⢟⡂⢱in⡩⣫d⡒⣃⢑⣘⠑⣗e⣉x(⠡⣇⢾s⢷⣮⢔⢺⡆[⢜i⠫].⡞o⢴⡶⣄⠽⣷⠗⡃⣃⣊⢜⡑⠊⠮⠖⠔⠄⠈⠠⠐
⠠⠂⠇⢅⡦⢚⢳⢱⣸⡼⣏⣃⠞⠪⠙⡤⡇⠪⣍⢠⣓⠃⡕⠹⡚rd⣥⣭&⢯⢗⢖⣯⠈⢻0⣶xf⢐⠁⡒f⣣⠗⢤⣵⡬)⢈+⣃n*⡿(⡉⢮⡛⡬⠭⡢⠌⡤⡽⠇⣇⣈⠟⢖⢜⠬⠆⠂⠈
⠠⡀⠩⢂⢤⢋⠲⢶⠁⢺⢻⠼⣡⡐⢚⡽⡮⢒⡋⢏⣂⠓⡵⣆8+⣜(⠡⣚⠔⢓⠰⢤⣧3⡅⠻9-⢣⡃r⣤⣆⣗⢪⣧)⣭*⡖22⣬)⡗⣭⠈⡤⢶⠇⠢⠝⣖⡞⡟⠎⢌⠝⠗⠘⠈⠈
⠠⡀⠨⡢⡖⡩⡎⡖⢀⢒⠲⣨⡷⠛⣡⠢⢷⣛⢇⢄⣫⡸⠐⠄.ro⡚⡉⢠⣲⠒⣑⡌u⢙⠟n⣃d⡕⢴.⡚⠽⣞⢇⢌cl⢵am⠴p⡦⠙⡀⢙⠱⣓⡜⠖⠲⣂⠬⣡⡅⢆⠖⠄⠁
⠂⠁⡀⡈⠍⠗⠮⢆⠖⢯⡄⢳⣋⠹⠑⢐⠡⠽⡌⠊⡛⡴⣂(8,⠲⣑⢀⢭⢵⡒⠶2⣁⡍5⢛5⠫⢽)⡴⡣⣻⣻⡌}}⢥⡸;⢓r⠖⢄⢈⣋⡻⠒⣘⢝⠮⡖⡸⡘⠢⠠⠈⠈
⠠⠐⠡⠙⡕⠈⠴⢂⡚⡓⡯⣘⠔⡕⠢⠟⠧⠊⣖⢥⠥⢃eq⡜⣉⣹⣑⠳⢇⡹⢬u⣧⢼i⡦⠕r⡝⡒e⠨⢻⢳⡝'⠿⡘⠬zl⡫⠈⣋⡴⠪⠯⡌⢰⣖⠡⡪⢊⣀⠪⠂⠁
⠠⢀⠍⠦⠝⠔⡈⢂⡭⡦⠦⠠⡣⠆⢿⡞⢦⣊⣨⣫⡟ib'⠤⢶⠧⢰⣋⣚⠟;⣌⣟e⡄⢾v⣡⣐a⡏⣴⢠l(⢰⡐⠪Zl⠱⡱⡊⠒⢔⣏⠽⠝⠜⠇⣐⡃⠪⠈⠁
⠈⠐⠨⠢⡃⠬⡈⡂⢩⢺⠰⠅⡧⡐⣩⡻⡔⠋⣭ib.⡓⡃⣻⠞⣿⠦⢡⣎⢮⢅i⣌⢋n⣘⠤⠘f⡛l⢈a⣇⡽⡄te⣪⠴⣬⡌⡢⠨⢥⡩⠚⠜⡀⠁⠁
⡀⠠⠨⠜⢨⣀⠎⠭⣍⠜⡚⡽⣠⣪⣡⠸⣧(⠉⢸n⣨⣉⣽⣪⢒⠮⢹⠝⡃.⡂⢃⡙⣴d⠮⢡⠩i⢖⡫g⣯⡱⢏it⢿⢆⠩⠦⡣⠦⠬⡄⠉⠌⠁⠠
⡀⠐⠢⣀⠔⢔⠖⣰⠪⣎⡐⢯⠓⣑s⣊⣵⢲(2⣽⡞⢆⠴⣴⡕⠺⢻5⣀⢬⢛⡄6⣷⢶)⡻.p⢁⡝⠖a⢴c⢪⡆⠙⡚⠜⠰⠢⠡⠁⠄
⠐⠂⡂⠘⠄⠁⠗⢑⢩⢣⠐⢁⡌⠚k⡾'⣚⢦⣶⣀⢋⠥⢶c⠝⠉⣔⣞⡫⡽*'⡤⠉⡓)⠐⡐⢏)⠆⡸⠨⢤⡢⡄⠄⠠⡀
⠠⠐⠒⠔⡂⠂⠇⡆⡨⠧⠑⡎⡝⣊⡄⢘⡲⢘⣳⠮⢝}⢜⠌⡃⢙⡸⠈⢦"};⡞⡈⠤⣉⡘⡊⠖⡑⠪⠖⢁⠄⠄⠈
⠠⡀⠂⠑⡐⡉⠎⡡⠐⠵⠊⠏⠳⢦⣈⢆⡌⠩⠢⡓⠗⡃⢣⡬⡘⡢⡘⠸⠈⠰⠔⡰⠎⠈⠡⠠⡀⠁
⠁⠄⠄⠁⢁⠂⢀⠑⡉⠁⢂⠸⠤⠍⢄⡉⠩⡒⠰⡄⠬⡢⠩⠓⠉⡄⠈⠈⠐⠈
⠐⠈⠈⠐⢀⠠⢀⠠⠄⢀⠐⠠⠈⠠⠠⠂⢀⠁
# rubocop:disable all
class KurageString
def initialize(n, len, p0, dir)
@n = n
@l = len.fdiv @n
@px, @py, @vx, @vy = (@n + 1).times.map { [*(p0 + _1 * @l * dir).rect, 0, 0] }.transpose
@arrays = 8.times.map{[]}
end
def update(p0, ff, dt)
p0x = p0.real
p0y = p0.imag
n = @n
px,py,vx,vy = @px,@py,@vx,@vy
fx,fy,dx,dy,a,b,r,ts = @arrays
(n+1).times { |i|
f = ff[@py[i]%1*19.9][@px[i]%1*19.9]
fx[i] = -1.7*@vx[i] + f.real/10
fy[i] = -1.7*@vy[i] + f.imag/10
}
# d[i] = ps[i+1] - ps[i]
# v_next[i] = v[i] + (fs[i] + d[i+1] * ts[i+1] - d[i] * ts[i]) * dt
# dot(v_next[i] - v_next[i - 1]), a[i]) = 0
# first:
# v0 = (p0_next - ps[0]) / dt
# ll*ts[i] - dot(a[i],d[i+1])*ts[i+1] = dot(a[i],(v[i]+fs[i]*dt) - v0)/dt
# normal:
# 2*ll*ts[i] - dot(d[i],d[i+1])*ts[i+1] - dot(d[i],d[i-1])*ts[i-1] = dot(d[i],(v[i]+fs[i]*dt) - (v[i-1]+fs[i-1]*dt))/dt
# last:
# 2*ll*ts[i] - dot(d[i],d[i-1])*ts[i-1] = dot(a[i],(v[i]+fs[i]*dt) - (v[i-1]+fs[i-1]*dt))/dt
n.times { |i|
dx[i] = px[i + 1] - px[i]
dy[i] = py[i + 1] - py[i]
vx[i] += fx[i] * dt
vy[i] += fy[i] * dt
}
vx[0] = (p0x - px[0]) / dt
vy[0] = (p0y - py[0]) / dt
(n - 1).times { a[_1] = dx[_1] * dx[_1 + 1] + dy[_1] * dy[_1 + 1] }
n.times{|i|
b[i] = 2 * (dx[i]**2+dy[i]**2)
r[i] = (dx[i] * (vx[i + 1] - vx[i]) + dy[i] * (vy[i + 1] - vy[i])) / dt
}
b[0] /= 2
(n - 1).times {|i|
b[i + 1] -= a[i] * c = a[i] / b[i]
r[i + 1] += r[i] * c
}
(n - 2).downto(0) { |i| r[i] += r[i + 1] * a[i] / b[i + 1] }
n.times { ts[_1] = r[_1] / b[_1] }
px[0] = p0x
py[0] = p0y
(1..n).each { |i|
qx = px[i] + vx[i] * dt + ((i < n ? dx[i] * ts[i] : 0) - dx[i - 1] * ts[i - 1]) * dt * dt - p0x
qy = py[i] + vy[i] * dt + ((i < n ? dy[i] * ts[i] : 0) - dy[i - 1] * ts[i - 1]) * dt * dt - p0y
qn = [@l / (qx**2+qy**2)**0.5, 1].min
vx[i] = -(px[i] - px[i] = p0x += qx * qn) / dt
vy[i] = -(py[i] - py[i] = p0y += qy * qn) / dt
}
(dx[0] + dy[0].i) * ts[0]
end
def render
hash = Hash.new(0)
lines(@px, @py, hash)
hash
end
end
def line(ax, ay, bx, by, h)
s = 160
n=[s*(ax-bx).abs, s*(ay-by).abs].max.ceil
(n+1).times { |i|
x = ((ax*i+(n-i)*bx)*s/n).round % s
y = ((ay*i+(n-i)*by)*s/n).round % s
h[x/2+y/4*s/2]|=1<<(x%2*4+y%4)
}
end
def lines(xs, ys, h)
(xs.size-1).times { |i|
line xs[i], ys[i], xs[i+1], ys[i+1], h
}
end
def stroke(ps, h)
lines ps.map(&:real), ps.map(&:imag), h
end
def draw(hashes)
lines = 40.times.map{[' '] * 80}
chars = 256.times.map{((_1&135)+(_1>>1&56)+(160+_1[3]<<6)).chr'utf-8'}
{}.merge(*hashes) { _2 | _3 }.each{
lines[_1 / 80][_1 % 80] = chars[_2]
}
print "\e[H" + lines.map { "#{_1.join.rstrip}\e[K\r\n" }.join
end
class Kurage
def initialize
@p = 0.5 + 0.5i
@v = 0
@r = 0
@dir = 1
end
def update(dt, phase, fs, ff)
rf=vf=0
ps(phase).zip(fs).each { |p, f|
vf += f / 1000
rf += (p - @p).rect.zip((f*-1i).rect).sum{_1*_2} / 10
}
t=trans(phase)
4.times { |i|
p = t[1i**i]
f = ff[p.imag%1*19.9][p.real%1*19.9] / 10
vf += f / 16
rf += (p - @p).rect.zip((f*-1i).rect).sum{_1*_2}
}
@v += (-@v + 0.05 * @dir * (1 + Math.sin(phase)) + vf) * dt
@p += @v * dt
@r += (-2 * @r + rf) * dt
@dir *= 1i ** @r
end
def trans(phase)
->z{x,y=z.rect;@p+@dir*0.1*(z+Math.sin(phase+x)*(1-x)*y/8i)}
end
def render(phase)
t=trans(phase)
hash = Hash.new(0)
stroke -1.4.step(1.4,0.02).map{t[(1i**_1)*(1+_1**16/1000-(1i.**4*_1).real/16)]},hash
(-1..1).each{|a|
stroke -1.2.step(1.2,0.2).map{x,y=(1i**_1).rect;t[x/6-0.7+(y/4+0.62*a).i]},hash
}
stroke 0.step(2*Math::PI,0.1).map{|u|t[0.3*(0.3+Math.sin(3*u-phase/27)-Math.cos(5*u)+Math.sin(4*u-phase/35).i+Math.sin(5*u).i)]},hash
hash
end
def ps(phase)
t=trans(phase)
[-3,9.5,-9.5,3].flat_map{|y|[-1,0,1].map{t[-0.8+(y+_1)*0.1i]}}
end
end
kurage = Kurage.new
strings = kurage.ps(0).map { |p0|
Ractor.new(p0) { |p0|
q = rand(30..40)
string = KurageString.new(q, q.fdiv(80), p0, -1)
loop {
f = string.update(*Ractor.receive)
Ractor.yield [f, string.render]
}
}
}
require 'io/console'
STDIN.raw do
$><<"\e[K\e[2J\e[?1000h"
buf = +''
ff = (0..20).map { [0] * 20 }
dt = 0.1
(1..).each { |i|
t=Time.now
buf += STDIN.read_nonblock(1000) rescue ''
break if buf.include? ?\C-c
events = buf.scan(a=/\e\[M.../)
buf=buf.split(a).last.to_s
events.each { |ev|
x=(ev[-2].ord-31)/4
y=(ev[-1].ord-31)/2
next if x>20||y>20
type = ev[3] # mousedown: ' ', mouseup: '#', scrollup: 'a', scrolldown: '`'
a,b=type=='a'?[-1i,0]:type=='`'?[1i,0]:[0,6]
20.times { |iy|
dy = (iy-y+10)%20-10
20.times { |ix|
dx = (ix-x+10)%20-10
r2=(dx*dx+dy*dy)/64.0
ff[iy][ix]+=(1-r2)**2*(a+b*(dx+dy.i)) if r2<1
}
}
}
f=Ractor.make_shareable(ff.map{|l|l.map!{_1*0.9}.dup})
phase = i*0.2
strings.zip(kurage.ps(phase)).each { _1.send [_2, f, dt] }
fs, hashes = strings.map(&:take).transpose
kurage.update(dt, phase, fs, f)
hashes << kurage.render(phase)
draw(hashes)
s=t-Time.now+0.03
sleep s if s>0
}
ensure
$><<"\e[?1000l"
end
# rubocop:disable all
def embed_constants(code)
code.gsub(/[A-Z][A-Z0-9_]*/){
Object.const_get(_1) rescue _1
}
end
HEADER1_LINES = 4
HEADER2_LINES = HEADER1_LINES + 1
RADIUS = 40
RADIUS1 = 39
RPARAM = 22
HEADER1 = ';BEGIN{->s{eval((a="'
HEADER2 = '";s.gsub(/[^!-~]/,\'\')))}.[]"'
FOOTER = '"};'
BODY = embed_constants(<<~RUBY).split.join + FOOTER
$s=[];
def(self).method_missing(a)=$s<<a.to_s;
at_exit{
a,b=a.split;
c,*d,e=s.split;
$s[HEADER1_LINES]+=?x*20+a;
$s[HEADER2_LINES]=e+?x*3+$s[HEADER2_LINES];
$s[HEADER2_LINES,0]=[b+?x*28+c]+d;
n=0;
a=(1..255).sort_by{('%b'%_1).count(?1)<<10|_1};
$s.map{|s|
(m=s.size).times{|i|
r=RADIUS-i*(m+~i)/RADIUS;
s[i]>?~&&n=a.index(s[i].ord&0xff)+n*(8+(RADIUS1-r)*RPARAM).round.clamp(8,255)
}
};
require'zlib';eval(Zlib.inflate(n.digits(256).pack'c*'))
}
RUBY
def normalize_sexp(sexp)
case sexp
in [*rest, Integer, Integer]
rest.map{normalize_sexp(_1)}
in Array
sexp.map{normalize_sexp(_1)}
else
sexp
end
end
def remove_spaces(code)
require 'ripper'
normalized = normalize_sexp(Ripper.sexp(code))
chars = code.chars
chars.each_with_index do |c, i|
next if c !~ /\s/
chars[i] = ''
unless normalize_sexp(Ripper.sexp(chars.join)) == normalized
chars[i] = c
end
end
p [chars.join.size, code.size]
puts chars.join
chars.join
end
require 'zlib'
data = Zlib.deflate(remove_spaces(File.read('kurage_base.rb').gsub(/(^| +)#.+/, '')), Zlib::BEST_COMPRESSION)
number = data.bytes.reverse.reduce{|a,b|a*256+b}
puts number.bit_length / 8
mark = 0x28ff.chr('utf-8')
lines = (RADIUS).times.map do |y|
w = 2 * Math.sqrt(4.0 * (y + 0.5) * (RADIUS - 0.5 - y)).round
' ' * (RADIUS - w / 2) + mark * w
end
pattern_lines = DATA.read.lines
entrypoint_chars = (HEADER1 + HEADER2 + BODY).chars
p entrypoint_chars.size
(HEADER1_LINES...lines.size).each do |y|
pattern = pattern_lines[y - HEADER1_LINES]
next unless pattern
pattern.chars.each_with_index do |c, i|
next unless c == '#'
lines[y][i + 22] = entrypoint_chars.shift || '$'
end
end
chars = (1..255).sort_by{('%b'%_1).count(?1)<<10|_1}.map{(10240 + _1).chr 'utf-8'}
srand 0
lines = lines.reverse.map do |line|
spaces = line[/^ */]
content = line.delete(' ')
m = content.size
spaces + content.chars.reverse.each_with_index.map do |c, i|
next c unless c == mark
r=RADIUS-i*(m+~i)/RADIUS
n=(8+(RADIUS1-r)*RPARAM).round.clamp(8,255)
c = chars[number % n]
number /= n
c
end.join.reverse
end.reverse
output = lines.join("\n") + "\n"
puts output
File.write 'kurage.rb', output
p BODY.size
puts number.bit_length / 8
p [DATA.read.count('#'), HEADER1.size + HEADER2.size + BODY.size]
__END__
####################
############################
#### ## ## # # # # ####
### ### # ## #### # ## ###
### # # ## # ## ### # # ###
### # #### # ### ### ###
## # ###
## #### ###### #########
## #### #### #### #####
##### ## ### # ##
### ## ### # ##
### ### ### # ##
# # # # # ## ###
## ### # # # ###
# # # # # # # ###
### ### # ## ##
### # # # # # ##
## # ### # # # ##
# # # # # # # ###
# # ### # # # ###
# # # # # # # ###
## # # ## # # # ## #
## # # ## # # # ## #
## # # ## # # # ## #
### # # # # ## ## #
### # # # # ## # #
## # # # # # ##
### # # # # ## ##
### # # # # # ##
# # # # # # ##
# ## # # # ## # #
# # # ## # #
# ###
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment