|
|
|
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
|
|
|
|
|
|
|
|
nexts = []
|
|
|
|
|
|
|
|
# turn left and right
|
|
|
|
if current.continued > 3
|
|
|
|
nexts.concat([current.dir.reverse, current.dir.reverse.map { -_1 }].map {|turn|
|
|
|
|
Node.new(current.pos.zip(turn).map { _1 + _2 }, turn, 1)
|
|
|
|
})
|
|
|
|
end
|
|
|
|
|
|
|
|
# keep going?
|
|
|
|
if current.continued < 10
|
|
|
|
nexts << Node.new(
|
|
|
|
current.pos.zip(current.dir).map { _1 + _2 },
|
|
|
|
current.dir,
|
|
|
|
current.continued + 1,
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
if found = nexts.find { _1.pos == dest && (4..10).cover?(_1.continued) }
|
|
|
|
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
|