Skip to content

Instantly share code, notes, and snippets.

@JoshCheek
Created April 11, 2016 04:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JoshCheek/ba2b8f8070bc2fa152beadd215ad103b to your computer and use it in GitHub Desktop.
Save JoshCheek/ba2b8f8070bc2fa152beadd215ad103b to your computer and use it in GitHub Desktop.
Shitty nonworking code to try and make a flyer wall like you'd see at a bar.
require 'set'
class Image
def self.box(name, colour:, w:, h:)
new name, Array.new(h) { Array.new w, [colour] }
end
attr_reader :name
def initialize(name, pixels)
@name, @pixels = name, pixels
end
def width
@width ||= pixels.first ? pixels.first.length : 0
end
def height
@height ||= pixels.length
end
def to_s
@pixels.map { |row|
row.map { |colours| "#{colours.first} \e[0m" }.join
}.join("\n")
end
def add(image)
return image if width.zero? && height.zero?
potential_additions(image)
.select { |image| image.max_depth == 1 }
.select { |image| image.connected? }
.select { |image| true } # image.roundish? } # needs the roundish? method to work before it does what I want (probably)
.sort_by { |image|
metric1 = image.num_edges - (image.width * image.height)
metric2 = image.width - image.height
metric3 = metric1.abs - metric2.abs
metric3.abs
}
.first
.tap do |i|
require "pry"
binding.pry unless i
end
end
def roundish?
edges = Set.new
pixels = @pixels.map { |row| row.map &:any? }
pixels.each_cons(2).each_with_index do |(top, bottom), y|
top.zip(bottom).each_with_index do |(top_px, bottom_px), x|
if top_px && !bottom_px
edges << [y+1, x]
elsif !top_px && bottom_px
edges << [y, x]
end
end
end
pixels.each_with_index do |row, y|
row.each_cons(2).each_with_index do |(left, right), x|
if left && !right
edges << [y, x]
elsif !left && right
edges << [y+1, x]
end
end
end
pixels[0].each_with_index do |cell, x|
edges << [-1, x] if cell
end
pixels[-1].each_with_index do |cell, x|
edges << [pixels.length, x] if cell
end
left_edge, *, right_edge = pixels.transpose
left_edge.each_with_index do |cell, y|
edges << [y, -1] if cell
end
(right_edge||left_edge).each_with_index do |cell, y|
edges << [y, pixels[0].length] if cell
end
edge = edges.first
path = [edge]
choose = Proc.new do |neighbour|
edges.include?(neighbour) && !path.include?(neighbour)
end
loop do
y, x = edge
upleft = [y-1, x-1]
up = [y-1, x ]
upright = [y-1, x+1]
left = [y , x-1]
right = [y , x+1]
downleft = [y+1, x-1]
down = [y+1, x ]
downright = [y+1, x+1]
potentials = [up, left, right, down, upleft, upright, downleft, downright]
adjacent = potentials.find(&choose)
if adjacent
path.push adjacent
else
if potentials.any? { |p| p == path[0] }
break
else
require "pry"
binding.pry
end
end
edge = adjacent
end
directions = path.each_cons(2).flat_map do |(x1, y1), (x2, y2)|
this_path = []
this_path << :right if x1+1 == x2
this_path << :left if x1-1 == x2
this_path << :down if y1+1 == y2
this_path << :up if y1-1 == y2
this_path
end
horizontal_count = directions.select { |dir| dir == :left || dir == :right }.each_cons(2).count { |dir1, dir2| dir1 != dir2 }
vertical_count = directions.select { |dir| dir == :up || dir == :down }.each_cons(2).count { |dir1, dir2| dir1 != dir2 }
horizontal_count < 2 && vertical_count < 2
end
def max_depth
pixels.flat_map { |row| row.map(&:length) }.max
end
def connected?
pixels = @pixels
.flat_map.with_index { |row, y|
row.map.with_index { |colours, x| [[y, x], colours.any?] }
}
.select { |pixels, coloured| coloured }
.to_h
return true if pixels.empty?
cell, _ = pixels.first
discovered = {cell => true}
to_process = [cell]
until to_process.empty?
y, x = to_process.shift
[[y, x-1], [y-1, x], [y+1, x], [y, x+1]].each do |neighbour|
next unless pixels.key? neighbour
next if discovered.key? neighbour
discovered[neighbour] = true
to_process << neighbour
end
end
pixels.all? { |cell, _| discovered.key? cell }
end
def num_edges
pixels = @pixels.map { |row| row.map &:any? }
verticals = pixels.each_cons(2).flat_map do |top, bottom|
top.zip(bottom).map { |left, right| left != right }
end
horizontals = pixels.flat_map do |row|
row.each_cons(2).map { |left, right| left != right }
end
top_edge = pixels[0]
bottom_edge = pixels[-1]
left_edge = pixels.transpose[0]
right_edge = pixels.transpose[-1]
[verticals, horizontals, top_edge, bottom_edge, left_edge, right_edge].inject(0) { |sum, row| sum+row.count(&:itself) }
end
protected
attr_reader :pixels
private
def potential_additions(image)
(-image.height..height).flat_map do |yoff|
(-image.width..width).map do |xoff|
pixels = add_pixels image, xoff: xoff, yoff: yoff
Image.new "#{name}/#{image.name}(#{xoff},#{yoff})", pixels
end
end
end
def add_pixels(image, xoff:, yoff:)
height = image.pixels.length
width = image.pixels[0] ? image.pixels[0].length : 0
leftmost = [xoff, 0].min
topmost = [yoff, 0].min
rightmost = [self.width, width+xoff].max
bottommost = [self.height, height+yoff].max
base = Array.new (bottommost - topmost) do
Array.new (rightmost - leftmost), []
end
their_xoff = xoff < 0 ? 0 : xoff
their_yoff = yoff < 0 ? 0 : yoff
image.pixels.each_with_index do |row, y|
row.each_with_index do |colours, x|
base[y+their_yoff][x+their_xoff] += colours
end
end
my_xoff = xoff < 0 ? -xoff : 0
my_yoff = yoff < 0 ? -yoff : 0
self.pixels.each_with_index do |row, y|
row.each_with_index do |colours, x|
base[y+my_yoff][x+my_xoff] += colours
end
end
base
end
end
images = [
Image.box('tall-fat', colour: "\e[46m", w:2, h:3),
Image.box('tall-skinny', colour: "\e[41m", w:1, h:3),
Image.box('short1', colour: "\e[42m", w:2, h:1),
Image.box('short2', colour: "\e[43m", w:2, h:1),
Image.box('short3', colour: "\e[44m", w:2, h:1),
]
# images = [
# Image.box('1x1', colour: "\e[45m", w:1, h:1),
# Image.box('2x1', colour: "\e[41m", w:2, h:1),
# ]
# images = [
# Image.box('tall-fat', colour: "\e[45m", w:2, h:3),
# Image.box('tall-skinny', colour: "\e[41m", w:1, h:3),
# Image.box('short1', colour: "\e[42m", w:2, h:1),
# ]
images = 8.times.map do |i|
Image.box i.to_s, colour: "\e[4#{(i+1)%8}m", w:2+rand(5)*0, h: 1+rand(5)*0
end
collage = images.inject Image.box('base', colour: "", w:0, h:0) do |base, image|
base.add image
end
puts collage
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment