diff --git a/2021/ruby/day_10.rb b/2021/ruby/day_10.rb index bd1e075..bd64e02 100644 --- a/2021/ruby/day_10.rb +++ b/2021/ruby/day_10.rb @@ -1,5 +1,3 @@ -require "strscan" - input = ARGF.read.split("\n") class IllegalCharacter < StandardError @@ -9,30 +7,19 @@ class IllegalCharacter < StandardError end end +COMPLEMENTS = %w[ () [] {} <> ].map(&:chars).to_h +OPENING_REGEXP = Regexp.new("[#{Regexp.escape(COMPLEMENTS.keys.join)}]") +CLOSING_REGEXP = Regexp.new("[#{Regexp.escape(COMPLEMENTS.values.join)}]") def parse(line) - ss = StringScanner.new(line) stack = [] - until ss.eos? - case - when ss.scan(/\(/) - stack << ?( - when ss.scan(/\[/) - stack << ?[ - when ss.scan(/\{/) - stack << ?{ - when ss.scan(//) - raise IllegalCharacter.new(?>) unless stack.pop == ?< - else - fail + s = line.chars + until s.empty? + case char = s.shift + when OPENING_REGEXP + stack << char + when CLOSING_REGEXP + raise IllegalCharacter.new(char) unless stack.pop == COMPLEMENTS.invert.fetch(char) end end @@ -55,20 +42,12 @@ end # end # } -POINTS = ")]}>".chars.map.with_index.to_h.transform_values { _1 + 1 } -def score(closing) - total = 0 - closing.each do |char| - total *= 5 - total += POINTS.fetch(char) - end - total -end +def score(closing) = closing + .map { COMPLEMENTS.values.index(_1) + 1 } + .inject(0) {|n,i| n*5 + i } -complements = "() [] {} <>".split(" ").map(&:chars).to_h scores = input - .map { parse(_1) rescue [] } - .reject(&:empty?) - .map {|remaining| remaining.reverse.map { complements.fetch(_1) }} + .filter_map { parse(_1) rescue nil } + .map {|remaining| remaining.reverse.map { COMPLEMENTS.fetch(_1) }} .map { score(_1) } p scores.sort.fetch(scores.length / 2)