#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 elsif c == "*" # 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,col] else # other symbol if start_num # finish a number numbers << [num.to_i, row, num_cols] start_num = false num = "" num_cols = [] end 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 def find_adjacent_numbers(row,col,numbers) adjacents = [] matches = [ [row-1,col-1], [row-1,col,], [row-1,col+1], [row,col-1], [row,col+1], [row+1,col-1], [row+1,col], [row+1,col+1] ] numbers.each do |number| num, row, cols = number cols.each do |col| if matches.include? [row,col] adjacents << num break end end end adjacents end # result should a single string or integer def calculate(data) result = "" symbols, numbers = data selected_numbers = [] symbols.each do |symbol| row,col = symbol adj = find_adjacent_numbers(row,col,numbers) if adj.length == 2 selected_numbers << adj.first * adj.last end end result = selected_numbers.reduce(&:+) result end