| 1 |
STDOUT.sync = true |
| 2 |
require "chunky_png" |
| 3 |
else |
| 4 |
end |
| 5 |
next |
| 6 |
require_relative File.join "..", "gems", "rsvgr", "lib", "rsvgr.rb" |
| 7 |
prev = [x, y, r] |
| 8 |
loop do |
| 9 |
varied = ( |
| 10 |
end.min |
| 11 |
break unless varied |
| 12 |
bubbles.each do |x, y, r| |
| 13 |
File.write "temp.svg", svg |
| 14 |
next |
| 15 |
puts "#{Time.now} start" |
| 16 |
fit[bad, xys] |
| 17 |
puts "#{Time.now} end" |
| 18 |
table = {} |
| 19 |
width = 1000 |
| 20 |
height = 500 |
| 21 |
width = height = nil |
| 22 |
bad = load_mask["bad.png"] |
| 23 |
good = load_mask["good.png", 2] |
| 24 |
MIN_R = 20 |
| 25 |
SUB_MIN_R = 0.415 * MIN_R |
| 26 |
min = nil |
| 27 |
stack = [] |
| 28 |
gift = found.dup |
| 29 |
p [x, y] |
| 30 |
found.compact! |
| 31 |
if found.empty? |
| 32 |
min = [*min, bubbles.size].min |
| 33 |
table[x] = table[x] || {} |
| 34 |
puts "#{Time.now} caching hypot" |
| 35 |
puts "#{Time.now} importing '#{filename}' mask" |
| 36 |
png = ChunkyPNG::Image.from_file filename |
| 37 |
(width + 1).times.map do |x| |
| 38 |
(height + 1).times.map do |y| |
| 39 |
table[x][y] = Math::hypot x, y |
| 40 |
table[-x][y] = Math::hypot x, y |
| 41 |
table[x][-y] = Math::hypot x, y |
| 42 |
table[-x][-y] = Math::hypot x, y |
| 43 |
found = gift.select do |x, y, _| |
| 44 |
found.map! do |x, y, _| |
| 45 |
d = table[x - xi][y - yi] |
| 46 |
m = d - ri if d + ri > m && d - ri < m |
| 47 |
p [x, y, m] unless m < MIN_R |
| 48 |
{} while good.find do |xi, yi, ri| |
| 49 |
puts "#{bubbles.size - bad.size} bubbles solution" |
| 50 |
svg = RSVGR::Root.new(x2: width, y2: height) |
| 51 |
[*bubbles, *bad, *good].each do |x, y, r| |
| 52 |
sorted = bubbles.sort_by(&:last).reverse |
| 53 |
sorted.size.times do |i| |
| 54 |
x, y, r = sorted[i] |
| 55 |
[*-10..10].product([*-10..10]). |
| 56 |
next if xv < 0 || yv < 0 || xv > width || yv > height |
| 57 |
).shuffle.find do |xv, yv| |
| 58 |
Math::hypot(xv - xi, yv - yi) - ri |
| 59 |
break [xv, yv, rv] if r < rv |
| 60 |
prev.push (x, y, r = varied) |
| 61 |
sorted[i][0], sorted[i][1], sorted[i][2] = x, y, r |
| 62 |
stack = [*stack.take(depth), (stack[depth] || 0) + 1] |
| 63 |
x, y, r = found.shuffle.max_by(&:last) |
| 64 |
fit[[*bubbles, [x, y, r]], gift, depth + 1, r] |
| 65 |
r, g, b = %i{ r g b }.map{ |c| ChunkyPNG::Color.send c, png[x,y] } |
| 66 |
load_mask = lambda do |filename, mul = 1| |
| 67 |
fit = lambda do |bubbles, gift, depth = 0, max = 100500| |
| 68 |
end.compact.tap{ |_| puts _.size } |
| 69 |
next puts stack.drop(1).join "-" if bubbles.size >= min if min |
| 70 |
bubbles.all?{ |xi, yi, ri| table[x - xi][y - yi] >= MIN_R + ri } |
| 71 |
bubbles.map{ |xi, yi, ri| table[x - xi][y - yi] - ri } |
| 72 |
svg.push RSVGR::Circle.new(cx: x, cy: y, r: r) |
| 73 |
svg.push RSVGR::Rect.new(width: width, height: height, stroke_width: 5, fill_color: "transparent") |
| 74 |
next if bad.any?{ |bubble| bubble.__id__ == sorted[i].__id__ } |
| 75 |
map{ |dx, dy| [dx + x, dy + y, r] } - prev |
| 76 |
rv = [*good, *sorted.rotate(i)[1..-1]].map do |xi, yi, ri| |
| 77 |
svg.push RSVGR::Circle.new(cx: x, cy: y, r: r, fill_color: "transparent", stroke_width: 1) |
| 78 |
found.select!{ |x, y, r| r < bubbles.last[2] } if bubbles.size > 1 |
| 79 |
found.select!{ |xi, yi, ri| table[x - xi][y - yi] < ri + r } |
| 80 |
found.sample(2).sort_by(&:last).reverse_each do |x, y, r| |
| 81 |
[found.max_by(&:last), *found.sample([1 - depth/7, 0].max)].each do |x, y, r| |
| 82 |
[found.max_by(&:last), *(found.sample(0) if depth < 5)].each do |x, y, r| |
Комментарии