|
require 'ripper' |
|
w=62 |
|
h=32 |
|
def line(x,y,points,w) |
|
idx = points.index points.min_by{(_1[0]-x).abs} |
|
dist = ->a,b{ |
|
cx,cy=a |
|
dx,dy=b[0]-cx,b[1]-cy |
|
t=((x-cx)*dx+(y-cy)*dy).fdiv(dx**2+dy**2) |
|
[ |
|
0<=t&&t<=1, |
|
((x-cx)*dy-dx*(y-cy)).abs/Math.hypot(dx,dy)<w |
|
] |
|
} |
|
left, center, right = points[idx-1, 3] |
|
la, lb = dist[left, center] |
|
ra, rb = dist[center, right] |
|
(la && lb) || (ra && rb) || (lb && rb) |
|
end |
|
template = (h+1).times.map{|iy| |
|
w.times.map{|ix| |
|
x = (2.0*(ix+0.5)-w)/w |
|
y = (h-2.0*(iy-[iy-h/3.0,0].max**2*0.004))/h |
|
heart = x**2+(1.2*y-Math.atan(2*x.abs)/2+0.1)**2<1 |
|
up = [[-10,0],[-0.4,0],[-0.2,0.6],[0,-0.3],[0.2,0],[10,0]] |
|
beat = line(x,y+0.113,[[-10,0],[-0.4,0],[-0.2,0.6],[0,-0.3],[0.2,0],[10,0]],0.04) |
|
heart && !beat ? '#' : ' ' |
|
}.join |
|
}.join("\n") |
|
|
|
template = <<TEMPLATE |
|
########### ########### |
|
################## ################## |
|
######################## ######################## |
|
######################################################## |
|
########################################################## |
|
############################################################ |
|
####################### ################################### |
|
######################## #################################### |
|
####################### #################################### |
|
###################### ################################### |
|
###################### ################################### |
|
##################### # ################################## |
|
#################### ### ################################## |
|
################### #### ################################ |
|
################## #### ################################ |
|
################# ###### ############################### |
|
############### ###### ############################# |
|
######## ######### |
|
###################### ####### ############### |
|
##################### ##### ############### |
|
#################### #### ############### |
|
################## # ############## |
|
################# ############## |
|
############### ############## |
|
############################ |
|
######################## |
|
################## |
|
############## |
|
########## |
|
######## |
|
###### |
|
## |
|
TEMPLATE |
|
|
|
def normalize_sexp(sexp) |
|
case sexp |
|
in [Integer, Integer] |
|
:CODE_LOCATION |
|
in Array |
|
sexp.map { normalize_sexp _1 } |
|
else |
|
sexp |
|
end |
|
end |
|
|
|
def ast(code) |
|
normalize_sexp Ripper.sexp code |
|
end |
|
|
|
original_code = File.read('heartbeat.rb').gsub(/# ?rubocop.+\n+/, '') |
|
code = original_code |
|
original_ast = ast original_code |
|
while code.match? /\n/ |
|
a = code.sub(/\n */, '') |
|
b = code.sub(/\n */, ';') |
|
if ast(a) == original_ast |
|
code = a |
|
elsif ast(b) == original_ast |
|
code = b |
|
else |
|
raise "Error at #{code[/.{0,10}\n.{0,10}/].inspect}" |
|
end |
|
end |
|
|
|
chars = code.chars |
|
output = template.lines.map do |line| |
|
chars.shift if chars.first == ';' |
|
line.chars.map do |
|
if _1.match? /\s/ |
|
chars.shift while chars.first&.match? /\s/ |
|
_1 |
|
else |
|
chars.shift || '#' |
|
end |
|
end.join |
|
end.join |
|
puts output |
|
puts ast(original_code) == ast(output) |
|
File.write 'output.rb', output |