[2023][ruby][17.1]
change qlotvnlmkztosrttxzwslrwklnnwqwvk
commit 3ede517cb9f67df52bddd1ab20105fcedc77b00b
author Alpha Chen <alpha@kejadlen.dev>
date
parent kmzrlqsp
diff --git a/2023/ruby/day_17.rb b/2023/ruby/day_17.rb
new file mode 100644
index 0000000..e09ef49
--- /dev/null
+++ b/2023/ruby/day_17.rb
@@ -0,0 +1,61 @@
+def succ(coord, delta)
+  coord.zip(delta).map { _1 + _2 }
+end
+
+map = ARGF.readlines(chomp: true)
+  .flat_map.with_index {|row, y|
+    row.chars.map.with_index {|elem, x|
+      [[y,x], elem.to_i]
+    }
+  }.to_h
+
+max_y = map.keys.map(&:first).max
+max_x = map.keys.map(&:last).max
+dest = [max_y,max_x]
+
+Node = Data.define(:pos, :dir, :continued)
+
+frontier = []
+visited = {}
+
+# seed initial directions
+[
+  [1,0], # down
+  [0,1], # right
+].each do |dir|
+  node = Node.new(dir, dir, 1)
+  frontier << node
+  visited[node] = map.fetch(dir)
+end
+
+loop do
+  frontier.sort_by! { visited.fetch(_1) }
+  current = frontier.shift
+
+  # turn left and right
+  nexts = [current.dir.reverse, current.dir.reverse.map { -_1 }].map {|turn|
+    Node.new(current.pos.zip(turn).map { _1 + _2 }, turn, 1)
+  }
+
+  # keep going?
+  if current.continued < 3
+    nexts << Node.new(
+      current.pos.zip(current.dir).map { _1 + _2 },
+      current.dir,
+      current.continued + 1,
+    )
+  end
+
+  if found = nexts.find { _1.pos == dest }
+    p visited.fetch(current) + map.fetch(dest)
+    exit
+  end
+
+  nexts
+    .select { map.has_key?(_1.pos) }
+    .reject { visited.has_key?(_1) }
+    .each do |node|
+      frontier << node
+      visited[node] = visited.fetch(current) + map.fetch(node.pos)
+    end
+end