[2016][ruby][11.0] elevators can hold two items
diff --git a/2016/ruby/day_11.rb b/2016/ruby/day_11.rb
index d0a187e..cc10bd0 100644
--- a/2016/ruby/day_11.rb
+++ b/2016/ruby/day_11.rb
@@ -12,6 +12,10 @@ State = Struct.new(:floors, :elevator) do
end
def ==(state)
+ eql?(state)
+ end
+
+ def eql?(state)
elevator == state.elevator && floors.zip(state.floors).all? {|a,b| a == b }
end
@@ -20,7 +24,8 @@ State = Struct.new(:floors, :elevator) do
next_floor = elevator + delta
next [] unless (0...floors.size).cover?(next_floor)
- current_floor.map {|item| move(item, elevator, next_floor) }
+ elevator_items = [1, 2].flat_map {|n| current_floor.to_a.combination(n).to_a }
+ elevator_items.map {|items| move(items, elevator, next_floor) }
}
end
@@ -28,15 +33,21 @@ State = Struct.new(:floors, :elevator) do
floors.any?(&:irradiated?)
end
+ def to_s
+ floors.map.with_index {|floor, index|
+ "#{elevator == index ??E:?.} #{floor.inspect}"
+ }.reverse.join("\n")
+ end
+
private
def current_floor
floors[elevator]
end
- def move(item, from, to)
- from_floor = floors[from] - [item]
- to_floor = floors[to] + [item]
+ def move(items, from, to)
+ from_floor = Floor.new(floors[from] - items)
+ to_floor = Floor.new(floors[to] + items)
floors = self.floors.clone
floors[from] = from_floor
@@ -50,7 +61,7 @@ class Floor < SimpleDelegator
attr_reader :source
def initialize(items)
- @source = super(items)
+ @source = super(Set.new(items))
end
def microchips
@@ -64,6 +75,44 @@ class Floor < SimpleDelegator
def irradiated?
!(generators.empty? || (microchips - generators).empty?)
end
+
+ def ==(floor)
+ source == floor.source
+ end
+end
+
+if __FILE__ == $0
+ INPUT = <<-INPUT
+F4 . . . . .
+F3 . . . LG .
+F2 . HG . . .
+F1 E . HM . LM
+ INPUT
+
+ Step = Struct.new(:state, :count)
+ seen = Set.new
+ steps = [Step.new(State.from_s(INPUT), 0)]
+
+ until steps.empty? do
+ step = steps.shift
+
+ puts
+ puts "Steps: #{step.count}"
+ puts step.state
+
+ if step.state.floors[0..-2].all?(&:empty?)
+ exit
+ end
+
+ step.state.candidates.each do |candidate|
+ next if seen.include?(candidate)
+
+ seen << candidate
+ next if candidate.irradiated?
+
+ steps << Step.new(candidate, step.count + 1)
+ end
+ end
end
require 'minitest/autorun'
@@ -93,21 +142,28 @@ F1 E . HM . LM
def test_equality
state = State.from_s(INPUT)
assert_equal @state, state
+ assert_equal @state.hash, state.hash
+ assert @state.eql?(state)
end
def test_candidates
candidates = @state.candidates
- assert_equal 2, candidates.size
+ assert_equal 3, candidates.size
candidate = candidates[0]
assert_equal 1, candidate.elevator
- assert_equal %W[ LM ], candidate.floors[0]
- assert_equal %W[ HG HM ], candidate.floors[1]
+ assert_equal %W[ LM ], candidate.floors[0].to_a
+ assert_equal %W[ HG HM ], candidate.floors[1].to_a
candidate = candidates[1]
assert_equal 1, candidate.elevator
- assert_equal %W[ HM ], candidate.floors[0]
- assert_equal %W[ HG LM ], candidate.floors[1]
+ assert_equal %W[ HM ], candidate.floors[0].to_a
+ assert_equal %W[ HG LM ], candidate.floors[1].to_a
+
+ candidate = candidates[2]
+ assert_equal 1, candidate.elevator
+ assert_empty candidate.floors[0]
+ assert_equal %W[ HG HM LM ], candidate.floors[1].to_a
end
def test_irradiated