[2016][ruby][24.0] works on sample, but too slow
diff --git a/2016/ruby/day_24.rb b/2016/ruby/day_24.rb
new file mode 100644
index 0000000..778e699
--- /dev/null
+++ b/2016/ruby/day_24.rb
@@ -0,0 +1,130 @@
+class Solver
+ def initialize(maze)
+ @maze = maze
+ end
+
+ def solve(from, to)
+ seen = Set.new(from)
+ queue = [[from, 0]]
+ current = queue.shift
+
+ loop do
+ location = current[0]
+ break if location == to
+
+ seen << location
+
+ neighbors = maze
+ .open_neighbors(location[0], location[1])
+ .reject {|location| seen.include?(location) }
+
+ queue.concat(neighbors.map {|location| [location, current[1] + 1] })
+
+ return nil if queue.empty?
+ current = queue.shift
+ end
+
+ current[1]
+ end
+
+ private
+
+ attr_reader :maze
+end
+
+class Maze
+ attr_reader :locations
+
+ def initialize(input)
+ @maze = Hash.new
+ @locations = Hash.new
+
+ x, y = 0, 0
+ input.chars.each do |char|
+ case char
+ when /\d/
+ @locations[char.to_i] = [x,y]
+ char = ?.
+ when "\n"
+ x = -1
+ y += 1
+ else
+ # no-op
+ end
+
+ @maze[[x,y]] = char
+ x += 1
+ end
+ end
+
+ def [](x,y)
+ maze[[x,y]]
+ end
+
+ def open_neighbors(x, y)
+ [[-1, 0],
+ [ 1, 0],
+ [ 0, -1],
+ [ 0, 1]].map {|dx,dy|
+ [x+dx, y+dy]
+ }.select {|x,y|
+ self[x,y] == ?.
+ }
+ end
+
+ private
+
+ attr_reader :maze
+end
+
+if __FILE__ == $0
+ maze = Maze.new(ARGF.read)
+ solver = Solver.new(maze)
+
+ hash = maze.locations.to_a.combination(2).each.with_object({}) {|(a, b), hash|
+ steps = solver.solve(a[1], b[1])
+ hash[[a[0],b[0]]] = steps
+ hash[[b[0],a[0]]] = steps
+ }
+
+ p maze
+ .locations
+ .map(&:first)
+ .permutation
+ .select {|route| route[0] == 0 }
+ .map {|route|
+ [route, route.each_cons(2).map {|a,b| hash[[a,b]] }.inject(:+)]
+ }.sort_by(&:last)
+end
+
+require 'minitest'
+# require 'minitest/autorun'
+
+class TestMaze < Minitest::Test
+ def test_maze
+ maze = Maze.new(<<-MAZE)
+###########
+#0.1.....2#
+#.#######.#
+#4.......3#
+###########
+MAZE
+ assert_equal [1,1], maze.locations[0]
+
+ assert_equal [[2,1], [1,2]], maze.open_neighbors(1,1)
+ end
+end
+
+class TestSolver < Minitest::Test
+ def test_solver
+ maze = Maze.new(<<-MAZE)
+###########
+#0.1.....2#
+#.#######.#
+#4.......3#
+###########
+MAZE
+ solver = Solver.new(maze)
+ assert_equal 2, solver.solve(maze.locations[0], maze.locations[4])
+ end
+end