map = DATA.readlines(chomp: true).flat_map.with_index {|row, y| row.chars.map.with_index {|height, x| [[y,x], height == ?. ? nil : height.to_i] } }.to_h trailheads = map.filter_map { _2 == 0 && _1} DELTAS = [[-1, 0], [1, 0], [0, -1], [0, 1]] def trails(map, head) active = [[head]] finished = [] until active.empty? current = active.shift steps = DELTAS .map {|d| current.last.zip(d).map { _1 + _2 } } .select { map.fetch(_1, nil) == map.fetch(current.last) + 1 } if steps.empty? finished << current else active.concat(steps.map { current + [_1] }) end end finished .select { map.fetch(_1.last) == 9 } .uniq end # part one pp trailheads.sum { trails(map, _1).map(&:last).uniq.length } # part two pp trailheads.sum { trails(map, _1).length } __END__ 89010123 78121874 87430965 96549874 45678903 32019012 01329801 10456732