75 lines
1.8 KiB
Ruby
75 lines
1.8 KiB
Ruby
require 'debug'
|
|
require 'prime'
|
|
|
|
class ValidIdFilter
|
|
def initialize(file_path, debug: false)
|
|
@file_path = file_path
|
|
@debug = debug
|
|
end
|
|
|
|
def sum_invalid_ids
|
|
ranges = parse_input(File.read(@file_path))
|
|
invalid_ids = ranges.flat_map {|range| get_invalid_ids_from_range(range)}
|
|
puts invalid_ids.inspect if @debug
|
|
invalid_ids.sum
|
|
end
|
|
|
|
private
|
|
|
|
# @param [Range] e.g., 11-22
|
|
# @return [<Integer>] array of invalid ids in range
|
|
def get_invalid_ids_from_range(range)
|
|
range.select do |element|
|
|
invalid_id?(element)
|
|
end
|
|
end
|
|
|
|
def invalid_id?(integer)
|
|
# ID is invalid if it is made only of some sequence of digits repeated AT LEAST twice
|
|
string = integer.to_s
|
|
num_digits = string.length
|
|
|
|
puts "is #{string} an invalid ID?" if @debug
|
|
|
|
(1...num_digits).each do |n|
|
|
next if num_digits % n != 0
|
|
|
|
slices = string.chars.each_slice(n).map(&:join)
|
|
puts "...trying divisior #{n}: #{slices} ..." if @debug
|
|
return true if slices.uniq.length == 1 && slices.length > 1
|
|
end
|
|
|
|
false
|
|
end
|
|
|
|
# @param [String] full input e.g., "11-22,33-604,..."
|
|
# @return [<Range>] e.g., [11..22, 33..604, ...]
|
|
def parse_input(input)
|
|
input.split(',').map {|range| to_range(range)}
|
|
end
|
|
|
|
# @param [String] e.g., "11-22"
|
|
# @return [Range] e.g., 11..22 (inclusive)
|
|
def to_range(string)
|
|
boundaries = string.split('-').map(&:to_i)
|
|
raise "Invalid boundaries for #{string}, got #{boundaries.inspect}" if boundaries.length != 2
|
|
Range.new(boundaries[0], boundaries[1])
|
|
end
|
|
end
|
|
|
|
if ARGV[0].nil? || ARGV[0].empty?
|
|
puts "Usage: ruby part2.rb <file_name> [debug]"
|
|
exit 1
|
|
end
|
|
|
|
debug = (ARGV[1] == "debug")
|
|
filter = ValidIdFilter.new(ARGV[0], debug:)
|
|
puts "The answer is: #{filter.sum_invalid_ids}"
|
|
|
|
# The answer is: 41662374059
|
|
|
|
# real 0m24,122s
|
|
# user 0m24,049s
|
|
# sys 0m0,070s
|
|
|