input = DATA.readlines(chomp: true) .flat_map.with_index {|line, j| line.chars.map.with_index {|x, i| [[j,i], x] } }.to_h TURNS = { [-1,0] => [0,1], [0,1] => [1,0], [1,0] => [0,-1], [0,-1] => [-1,0], } Loop = Class.new(Exception) def patrol(lab) start = lab.find { _2 == ?^ }.first path = [[start, [-1,0]]] seen = path.to_set loop do pos, dir = path.last peek = pos.zip(dir).map {|i,di| i + di } return path unless lab.has_key?(peek) raise Loop if seen.include?([peek, dir]) seen << [peek, dir] case lab.fetch(peek) when ?., ?^ path << [peek, dir] when ?# path.last[1] = TURNS.fetch(dir) when nil return path else fail end end end def loop?(lab) patrol(lab) false rescue Loop true end path = patrol(input).map(&:first).to_set pp path.length pp input .select { path.include?(_1) && _2 != ?^ } .select {|xy, _| # pp xy input[xy] = ?# res = loop?(input) input[xy] = ?. res }.size __END__ ....#..... .........# .......... ..#....... .......#.. .......... .#..^..... ........#. #......... ......#...