From 3c1f21c49070dbba3aa15f4831c857e031df7781 Mon Sep 17 00:00:00 2001 From: Alpha Chen Date: Sun, 11 Dec 2016 12:28:32 -0500 Subject: [PATCH] [2016][ruby][11.0] elevators can hold two items --- 2016/ruby/day_11.rb | 76 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 66 insertions(+), 10 deletions(-) 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