Last active
January 4, 2020 09:58
-
-
Save pnlybubbles/258114a354ab5d79dc28 to your computer and use it in GitHub Desktop.
Ruby Quine Generator. 2015年の書き初めです。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require "rmagick" | |
# require "pp" | |
raise "input file name" unless ARGV[0] | |
raise "file not found" unless File.exist?(ARGV[0].strip) | |
image = Magick::ImageList.new(ARGV[0]) | |
img_depth = image.depth | |
fill = ARGV[1] || "#FFFFFF" | |
fill = "##{fill.upcase}" if fill !~ /^#/ | |
STDERR.puts "Fill color:" | |
STDERR.puts fill | |
scale_factor = (ARGV[2] || ARGV[1]).chomp.to_i | |
scale_factor = 3 if scale_factor == 0 | |
STDERR.puts "Scale factor:" | |
STDERR.puts scale_factor | |
font_size = [scale_factor, scale_factor * 2] | |
def font_size.x | |
self[0] | |
end | |
def font_size.y | |
self[1] | |
end | |
width = image.columns / font_size.x | |
height = image.rows / font_size.y | |
STDERR.puts "Input file size: " | |
STDERR.puts [image.columns, image.rows].to_s | |
STDERR.puts "Output quine size: " | |
STDERR.puts [width, height].to_s | |
img_da = [] | |
prominent = {} | |
# pixel obj to dict array | |
image.each_pixel { |p, x, y| | |
img_da[y] ||= [] | |
color = p.to_color(Magick::AllCompliance, false, img_depth, true) | |
img_da[y][x] = color | |
prominent[color] ||= 0 | |
prominent[color] += 1 | |
} | |
STDERR.puts "Prominent color: " | |
STDERR.puts prominent.sort_by { |_, v| v }.reverse[0..10].map { |v| v[0] }.join(' ') | |
# pixel data to 0,1 | |
img_dot = (0...height).map { |y| | |
(0...width).map { |x| | |
(0...font_size.y).map { |fy| | |
(0...font_size.x).map { |fx| | |
img_da[y * font_size.y + fy][x * font_size.x + fx] == fill ? 1 : -1 | |
} | |
}.flatten.inject(:+) >= 0 ? 1 : 0 | |
} | |
} | |
# fix orphan pixels | |
chunk_start = [] | |
chunk = 0 | |
img_dot.each_with_index { |line, y| | |
line.each_with_index { |cell, x| | |
if cell == 1 | |
chunk_start = [x, y] if chunk == 0 | |
chunk += 1 | |
else | |
break if chunk != 0 | |
end | |
} | |
break if chunk != 0 | |
} | |
ORPHAN_THRESHOLD = 10 | |
if chunk < ORPHAN_THRESHOLD | |
# print to stdout | |
STDERR.puts "Fix orphan pixels: #{chunk}" | |
start_x = chunk_start[0] + chunk / 2 - ORPHAN_THRESHOLD / 2 | |
start_y = chunk_start[1] | |
start_x = width - ORPHAN_THRESHOLD if start_x + ORPHAN_THRESHOLD > width | |
start_x = 0 if start_x < 0 | |
ORPHAN_THRESHOLD.times { |i| | |
img_dot[start_y][start_x + i] = 1 | |
} | |
end | |
# print to stdout | |
STDERR.puts "AA data: " | |
STDERR.puts img_dot.map { |r| r.join }.join("\n") | |
# output quine | |
bits = img_dot.flatten.join.reverse.to_i(2) | |
bin = [Marshal.dump(bits)].pack("m").gsub("\n", "") | |
$s = "b=\"#{bin}\";n=Marshal.load(b.unpack(\"m\")[0]);e=\"eval$s=%w\"<<39<<($s*<circulation-count>);o=\"\";j=-1;0.upto(#{height}*#{width}-1){|i|o<<((n[i]==1)?e[j+=1]:32);o<<((i%#{width}==#{width-1})?10:\"\")};o[-7,6]=\"\"<<39<<\".join\";puts(o)#" | |
fill_count = img_dot.flatten.join.count("1") | |
if fill_count < $s.gsub(/<circulation-count>/, "*").length | |
raise "AA's fill area is too small" | |
end | |
circulation_count = (fill_count.to_f / $s.gsub(/<circulation-count>/, "").length).ceil + 1 | |
$s.gsub!(/<circulation-count>/, circulation_count.to_s) | |
STDERR.puts "quine: " | |
eval $s |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment