aoc2023/day_3/impl_2.rb

106 lines
2.0 KiB
Ruby

#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