tobotras

advent-2020-18-2-ruby

Dec 23rd, 2020 (edited)
408
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Ruby 1.34 KB | None | 0 0
  1. class Advent18
  2.   def perform
  3.     ARGF.map { |line| eat_expr(line.delete!(" \t\n"), false) }.reduce(&:+)
  4.   end
  5.  
  6.   def eat_expr(line, eagier)
  7.     op1 = looking_at(line, '(') ?  eat_expr(eat_till_closing_paren(line), false) : eat_digit(line)
  8.     continuation(line, op1, eagier)
  9.   end
  10.  
  11.   def continuation(line, op1, eagier)
  12.     (line.empty? || eagier) ? op1 : eat_operation(line, op1, eagier)
  13.   end
  14.  
  15.   def eat_operation(line, op1, eagier)
  16.     raise "Unknown operation: #{line[0]}" unless %w[+ *].include? line[0]
  17.     op = eat_char(line).to_sym
  18.     partial = op1.send(op, eat_expr(line, op == :+))
  19.     continuation(line, partial, eagier)
  20.   end
  21.  
  22.   def looking_at(line, ch)
  23.     eat_char(line) if result = (line[0] == ch)
  24.     result
  25.   end
  26.  
  27.   def eat_char(line)
  28.     ch = line[0]
  29.     line[0] = ''
  30.     ch
  31.   end
  32.  
  33.   def eat_digit(line)
  34.     raise "Digit expected" unless line[0] =~ /\d/
  35.     eat_char(line).to_i
  36.   end
  37.  
  38.   def eat_till_closing_paren(line)
  39.     expr = ''
  40.     level = 0
  41.     while !line.empty?
  42.       if line[0] == ')'
  43.         if level == 0
  44.           eat_char(line)
  45.           return expr
  46.         end
  47.         expr << eat_char(line)
  48.         next level-= 1
  49.       end
  50.       level += 1 if line[0] == '('
  51.       expr << eat_char(line)
  52.     end
  53.     raise "Unbalanced parens"
  54.   end
  55. end
  56.  
  57. puts "Total sum is #{Advent18.new.perform}"
  58.  
Add Comment
Please, Sign In to add comment