#prepare the input which is a string containing new lines def parse(input) data = [] row = 0 symbols = {} numbers = [] input.each_line do |line| start_num = false num = "" num_cols = [] line.chomp.chars.each_with_index do |c,col| if c == "." if start_num # finish a number numbers << [num.to_i, row, num_cols] start_num = false num = "" num_cols = [] end elsif /\d/.match?(c) # a digit start_num = true num += c num_cols << col else # symbol if start_num # finish a number numbers << [num.to_i, row, num_cols] start_num = false num = "" num_cols = [] end # fill adjacents symbols[row] = {} if symbols[row].nil? symbols[row][col-1] = true symbols[row][col+1] = true symbols[row-1] = {} if symbols[row-1].nil? symbols[row-1][col] = true symbols[row-1][col-1] = true symbols[row-1][col+1] = true symbols[row+1] = {}if symbols[row+1].nil? symbols[row+1][col] = true symbols[row+1][col-1] = true symbols[row+1][col+1] = true end end if start_num # finish a number numbers << [num.to_i, row, num_cols] start_num = false num = "" num_cols = [] end row += 1 end data = [symbols,numbers] data end # result should a single string or integer def calculate(data) result = "" symbols, numbers = data selected_numbers = [] numbers.each do |number_set| number, row, cols = number_set cols.each do |col| if symbols.dig(row,col) selected_numbers << number puts "selected: #{selected_numbers}" break end end end result = selected_numbers.reduce(&:+) result end