2
|
1 #! /usr/bin/env ruby
|
|
2
|
|
3 if ARGV.length != 1
|
|
4 abort("Incorrect arguments - needs input file")
|
|
5 elsif not File.exist? (ARGV[0])
|
|
6 abort("File #{ARGV[0]} did not exist")
|
|
7 end
|
|
8
|
|
9 file = ARGV[0]
|
|
10
|
|
11 number_chars = *('0'..'9')
|
|
12 skip_chars = ['.']
|
|
13
|
|
14 numbers = Hash.new
|
|
15 symbols = Array.new
|
|
16 Position = Struct.new(:x, :y)
|
|
17 NumberValue = Struct.new(:value, :positions)
|
|
18 SymbolValue = Struct.new(:position)
|
|
19
|
|
20 def create_number_position(vals)
|
|
21 number = vals.reduce("") {|m, v| m + v[0]}.to_i
|
|
22 positions = vals.map {|v| Position.new(v[1], v[2])}
|
|
23 NumberValue.new(number, positions)
|
|
24 end
|
|
25
|
|
26 def adjacent(a, b)
|
|
27 (a.x - b.x).abs <= 1 and (a.y - b.y).abs <= 1
|
|
28 end
|
|
29
|
|
30 sum = 0
|
|
31 positions = File.open(file, "r").each_line(chomp: true).with_index.map do |line, index|
|
|
32 numbers = line.each_char.with_index.map {|c, i| if number_chars.include? c or !skip_chars.include? c then [c, index, i] end }\
|
|
33 .filter {|v| v != nil }\
|
|
34 .reduce([[], []]) do |memo, val|
|
|
35 if number_chars.include? val[0] then
|
|
36 if memo[1].last and memo[1].last[2] + 1 != val[2] then
|
|
37 memo[0] << create_number_position(memo[1])
|
|
38 memo[1] = []
|
|
39 end
|
|
40 memo[1] << val
|
|
41 else
|
|
42 if memo[1] != [] then
|
|
43 memo[0] << create_number_position(memo[1])
|
|
44 memo[1] = []
|
|
45 end
|
|
46 memo[0] << SymbolValue.new(Position.new(val[1], val[2]))
|
|
47 end
|
|
48 memo
|
|
49 end
|
|
50 if numbers[1] != [] then
|
|
51 numbers[0] << create_number_position(numbers[1])
|
|
52 end
|
|
53 numbers[0]
|
|
54 end.flatten.group_by {|elem| elem.class}
|
|
55
|
|
56 symbol_pos = positions[SymbolValue]
|
|
57 number_pos = positions[NumberValue]
|
|
58
|
|
59 puts number_pos.filter {|num| num.positions.any? {|num_pos| symbol_pos.any? { |sym_pos| adjacent(num_pos, sym_pos.position) } } }.sum {|v|v.value}
|