diff --git a/2015/README.md b/2015/README.md index a2b28cf..643eb3d 100644 --- a/2015/README.md +++ b/2015/README.md @@ -12,7 +12,7 @@ | ✓ | 08 | Ruby | ✓ | 09 | Rust | ✓ | 10 | Ruby -| | 11 | +| ✓ | 11 | Ruby | ✓ | 12 | Ruby | | 13 | | | 14 | diff --git a/2015/day-11/inputs/puzzle.txt b/2015/day-11/inputs/puzzle.txt new file mode 100644 index 0000000..5915be7 --- /dev/null +++ b/2015/day-11/inputs/puzzle.txt @@ -0,0 +1 @@ +cqjxjnds diff --git a/2015/day-11/inputs/test.txt b/2015/day-11/inputs/test.txt new file mode 100644 index 0000000..7a31c56 --- /dev/null +++ b/2015/day-11/inputs/test.txt @@ -0,0 +1,5 @@ +hijklmmn +abbceffg +abbcegjk +abcdffaa +ghjaabcc diff --git a/2015/day-11/main.rb b/2015/day-11/main.rb new file mode 100755 index 0000000..3221c53 --- /dev/null +++ b/2015/day-11/main.rb @@ -0,0 +1,71 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require "pathname" +require "set" + +ValidationFailed = Class.new(StandardError) + +class LengthInvalid < ValidationFailed + def initialize(pwd) = super("#{pwd} length is not 8") +end + +class NoStraightFound < ValidationFailed + def initialize(pwd) = super("#{pwd} doesn't include an increasing straight") +end + +class ForbiddenLetter < ValidationFailed + def initialize(pwd) = super("#{pwd} has forbidden letters 'i', 'o', or 'l'") +end + +class NotEnoughPairs < ValidationFailed + def initialize(pwd) = super("#{pwd} doesn't include at least two different pairs") +end + +def validate(input) + raise LengthInvalid, input unless input.size == 8 + + result = input + .each_char + .chain([nil]) + .each_cons(3) + .each_with_object(straight: false, pairs: Set.new) do |(a, b, c), res| + raise ForbiddenLetter, input unless ([a, b, c] & %w[i o l]).empty? + res[:straight] ||= (b == a.succ && c == b.succ) + res[:pairs].add(a) if (a == b && b != c) + end + + raise NoStraightFound, input unless result[:straight] + raise NotEnoughPairs, input unless result[:pairs].size >= 2 + + input +end + +def next_valid_password(input) + validate(input) +rescue LengthInvalid + nil +rescue ForbiddenLetter => e + idx = input.index(/[iol]/) + input = input[0..idx].succ + input[(idx+1)..] + retry +rescue ValidationFailed + input = input.succ + retry +end + +def main(file_paths) + file_paths.each do |file_path| + puts "File: #{file_path}" + + file_path.each_line do |line| + line = line.chomp + solution1 = next_valid_password(line) + puts "solution 1: #{line} -> #{solution1}" + solution2 = next_valid_password(solution1.succ) + puts "solution 2: #{solution1} -> #{solution2}" + end + end +end + +main(ARGV.map { |x| Pathname(x) })