From 034cae395f2a973ea6705e00bb5d17f27614b891 Mon Sep 17 00:00:00 2001 From: Anna Wiggins Date: Fri, 18 Dec 2020 11:46:20 +0000 Subject: [PATCH] Day 18 solved. --- 2020/day18.go | 151 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 2020/day18.go diff --git a/2020/day18.go b/2020/day18.go new file mode 100644 index 0000000..22712d8 --- /dev/null +++ b/2020/day18.go @@ -0,0 +1,151 @@ +package main + +import ( + "fmt" + "log" + "os" + "strconv" + + "git.annabunch.es/annabunches/adventofcode/2020/lib/util" +) + +// operators +const ( + ADD = -1 + MUL = -2 + GRP = -3 +) + +type Stack struct { + data []int +} + +func NewStack() *Stack { + return &Stack{ + data: make([]int, 0), + } +} + +func (s *Stack) Push(value int) { + s.data = append(s.data, value) +} + +func (s *Stack) Pop() int { + if s.Empty() { + log.Panicf("Tried to pop from empty stack") + } + ret := s.Top() + s.data = s.data[:len(s.data)-1] + return ret +} + +func (s *Stack) Top() int { + if s.Empty() { + return -3 + } + return s.data[len(s.data)-1] +} + +func (s *Stack) Empty() bool { + return len(s.data) == 0 +} + +// This only works when the starting expression is all positive, single-digit integers +// and where all operators are additive (i.e. we rely on being able to use negative numbers +// as sentinel values. +func convertRPN(exp string, precedence map[int]int) []int { + rpn := make([]int, 0) + ops := NewStack() + for _, i := range exp { + e := string(i) + x, err := strconv.Atoi(e) + if err == nil { + rpn = append(rpn, x) + continue + } + + var opcode int + switch e { + case "+": + opcode = ADD + case "*": + opcode = MUL + case "(": + ops.Push(GRP) + continue + case ")": + for ops.Top() != GRP { + rpn = append(rpn, ops.Pop()) + } + ops.Pop() + continue + default: + continue + } + + if ops.Empty() { + ops.Push(opcode) + continue + } + if precedence[ops.Top()] >= precedence[opcode] { + rpn = append(rpn, ops.Pop()) + } + ops.Push(opcode) + } + for !ops.Empty() { + rpn = append(rpn, ops.Pop()) + } + + return rpn +} + +func evaluateExpression(rpn []int) int { + output := NewStack() + for _, value := range rpn { + if value >= 0 { + output.Push(value) + continue + } + switch value { + case ADD: + x := output.Pop() + y := output.Pop() + output.Push(x + y) + case MUL: + x := output.Pop() + y := output.Pop() + output.Push(x * y) + } + } + + return output.Pop() +} + +func main() { + step := os.Args[1] + values := util.InputParserStrings(os.Args[2]) + + total := 0 + precedence := make(map[int]int) + switch step { + case "1": + precedence[ADD] = 0 + precedence[MUL] = 0 + precedence[GRP] = -1 + case "2": + precedence[ADD] = 1 + precedence[MUL] = 0 + precedence[GRP] = -1 + } + + exps := make([][]int, 0) + for _, line := range values { + // parse the expression into RPN + exps = append(exps, convertRPN(line, precedence)) + } + + for _, exp := range exps { + total += evaluateExpression(exp) + } + fmt.Println(total) +}