diff --git a/2016/ruby/day_17.rb b/2016/ruby/day_17.rb
new file mode 100644
index 0000000..bfb6b38
--- /dev/null
+++ b/2016/ruby/day_17.rb
@@ -0,0 +1,44 @@
+require 'digest/md5'
+
+State = Struct.new(:location, :path)
+
+Maze = Struct.new(:passcode, :size) do
+ def walk
+ return enum_for(__method__) unless block_given?
+
+ states = [State.new([0,0], '')]
+ until states.empty?
+ state = states.shift
+ yield state
+
+ hash = Digest::MD5.hexdigest("#{passcode}#{state.path}")[0,4]
+ open_doors = %i[ U D L R ].select.with_index {|_, index|
+ 'bcdef'.include?(hash[index])
+ }
+
+ {
+ U: [ 0, -1],
+ D: [ 0, 1],
+ L: [-1, 0],
+ R: [ 1, 0],
+ }.select {|door, _|
+ open_doors.include?(door)
+ }.map {|door, (dx, dy)|
+ x = state.location[0] + dx
+ y = state.location[1] + dy
+
+ location = [x, y]
+ path = state.path + door.to_s
+ State.new(location, path)
+ }.select {|state|
+ state.location.all? {|i| (0...size).cover?(i) }
+ }.each do |state|
+ states << state
+ end
+ end
+ end
+end
+
+p Maze.new('yjjvjgan', 4).walk.find {|state|
+ state.location == [3, 3]
+}