2019: Day 11 Part 2
This commit is contained in:
parent
a2208a8f5f
commit
2f0130cda7
2 changed files with 173 additions and 0 deletions
|
|
@ -137,6 +137,7 @@ module Intcode
|
||||||
nil
|
nil
|
||||||
when 9
|
when 9
|
||||||
move_relative_base!
|
move_relative_base!
|
||||||
|
nil
|
||||||
when 99
|
when 99
|
||||||
:done_executing
|
:done_executing
|
||||||
else
|
else
|
||||||
|
|
|
||||||
172
2019/day11/part2.rb
Normal file
172
2019/day11/part2.rb
Normal file
|
|
@ -0,0 +1,172 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'set'
|
||||||
|
require_relative 'intcode'
|
||||||
|
|
||||||
|
Point = Struct.new(:x, :y) do
|
||||||
|
def to_s
|
||||||
|
"(#{x}, #{y})"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Hull
|
||||||
|
def initialize
|
||||||
|
@panels = Hash.new { |hash, key| hash[key] = :black }
|
||||||
|
@painted = Set.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def color_at(point)
|
||||||
|
@panels[point]
|
||||||
|
end
|
||||||
|
|
||||||
|
def paint(point, color)
|
||||||
|
@painted << point
|
||||||
|
@panels[point] = color
|
||||||
|
end
|
||||||
|
|
||||||
|
def painted
|
||||||
|
@painted.count
|
||||||
|
end
|
||||||
|
|
||||||
|
def corners
|
||||||
|
min_x = +Float::INFINITY
|
||||||
|
min_y = +Float::INFINITY
|
||||||
|
max_x = -Float::INFINITY
|
||||||
|
max_y = -Float::INFINITY
|
||||||
|
|
||||||
|
@panels.keys.each do |p|
|
||||||
|
min_x = [min_x, p.x].min
|
||||||
|
min_y = [min_y, p.y].min
|
||||||
|
max_x = [max_x, p.x].max
|
||||||
|
max_y = [max_y, p.y].max
|
||||||
|
end
|
||||||
|
|
||||||
|
upper_left = Point.new(min_x, min_y)
|
||||||
|
lower_right = Point.new(max_x, max_y)
|
||||||
|
[upper_left, lower_right]
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
tl, br = corners
|
||||||
|
|
||||||
|
s = String.new
|
||||||
|
(tl.y..br.y).each do |y|
|
||||||
|
(tl.x..br.x).each do |x|
|
||||||
|
s << char(color_at(Point.new(x, y)))
|
||||||
|
end
|
||||||
|
s << "\n"
|
||||||
|
end
|
||||||
|
s
|
||||||
|
end
|
||||||
|
|
||||||
|
def char(code)
|
||||||
|
case code
|
||||||
|
when :black
|
||||||
|
' '
|
||||||
|
when :white
|
||||||
|
# Unicode full block
|
||||||
|
"\u2588"
|
||||||
|
else
|
||||||
|
raise ArgumentError, "unexpected color code: #{code}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class DoneExecuting < StandardError; end
|
||||||
|
|
||||||
|
class Robot
|
||||||
|
def initialize(program, hull)
|
||||||
|
@computer = Intcode::Computer.new(program.as_memory) { on_input }
|
||||||
|
@hull = hull
|
||||||
|
@facing = :up
|
||||||
|
@position = Point.new(0, 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
def step
|
||||||
|
color_output = nil
|
||||||
|
direction_output = nil
|
||||||
|
|
||||||
|
color_output = tick until color_output
|
||||||
|
direction_output = tick until direction_output
|
||||||
|
|
||||||
|
@hull.paint(@position, color(color_output))
|
||||||
|
@facing = turn(@facing, direction_output)
|
||||||
|
@position = move(@position, @facing)
|
||||||
|
end
|
||||||
|
|
||||||
|
def tick
|
||||||
|
ret = @computer.tick
|
||||||
|
raise DoneExecuting if ret == :done_executing
|
||||||
|
|
||||||
|
ret
|
||||||
|
end
|
||||||
|
|
||||||
|
def on_input
|
||||||
|
color = @hull.color_at(@position)
|
||||||
|
case color
|
||||||
|
when :black
|
||||||
|
0
|
||||||
|
when :white
|
||||||
|
1
|
||||||
|
else
|
||||||
|
raise ArgumentError, "unexpected color: #{color}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def color(code)
|
||||||
|
case code
|
||||||
|
when 0
|
||||||
|
:black
|
||||||
|
when 1
|
||||||
|
:white
|
||||||
|
else
|
||||||
|
raise ArgumentError, "unexpected color code: #{code}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
DIRECTIONS = %i[up right down left].freeze
|
||||||
|
|
||||||
|
def turn(facing, direction_code)
|
||||||
|
idx = DIRECTIONS.index(facing)
|
||||||
|
case direction_code
|
||||||
|
when 0
|
||||||
|
# left 90 degrees (ccw)
|
||||||
|
next_idx = (idx - 1) % DIRECTIONS.length
|
||||||
|
when 1
|
||||||
|
# right 90 degrees (cw)
|
||||||
|
next_idx = (idx + 1) % DIRECTIONS.length
|
||||||
|
else
|
||||||
|
raise ArgumentError, "unexpected direction code: #{direction_code}"
|
||||||
|
end
|
||||||
|
DIRECTIONS.fetch(next_idx)
|
||||||
|
end
|
||||||
|
|
||||||
|
def move(pos, direction)
|
||||||
|
case direction
|
||||||
|
when :up
|
||||||
|
Point.new(pos.x, pos.y - 1)
|
||||||
|
when :down
|
||||||
|
Point.new(pos.x, pos.y + 1)
|
||||||
|
when :left
|
||||||
|
Point.new(pos.x - 1, pos.y)
|
||||||
|
when :right
|
||||||
|
Point.new(pos.x + 1, pos.y)
|
||||||
|
else
|
||||||
|
raise ArgumentError, "unexpected direction: #{direction}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
hull = Hull.new
|
||||||
|
hull.paint(Point.new(0, 0), :white)
|
||||||
|
|
||||||
|
program = Intcode.read(File.join(__dir__, 'input'))
|
||||||
|
robot = Robot.new(program, hull)
|
||||||
|
|
||||||
|
loop do
|
||||||
|
robot.step
|
||||||
|
rescue DoneExecuting
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
puts hull
|
||||||
Loading…
Reference in a new issue