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 [] 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 [] 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 [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