-
Notifications
You must be signed in to change notification settings - Fork 1
/
day18.Rmd
110 lines (100 loc) · 2.51 KB
/
day18.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
---
title: "--- Day 18: Operation Order ---"
author: Fleur Kelpin
date: Dec 18, 2020
output: github_document
---
```{r message=FALSE, warning=FALSE}
library(tidyverse)
library(Ramble)
input <- readLines("day18.txt") %>%
map_chr(~ str_remove_all(., "\\s"))
tibble(input)
```
# Part 1
Evaluate the expression on each line of the homework; what is the sum of the
resulting values?
Writing a grammar for this is trickier than I thought, because associativity
matters and it's easy to get circular references and infinite recursion.
```
expr: block (plusOrTimes block)*
block: number | '(' expr ')'
```
Then when resolving the expressions, we'll get a list of integers and operators.
```{r}
resolve <- function(x) {
result <- as.numeric(x[[1]])
if (length(x) <= 2) {
return(result)
}
for (i in seq(from = 2, to = length(x), by = 2)) {
result <- switch(x[[i]],
"+" = result + as.numeric(x[[i + 1]]),
"*" = result * as.numeric(x[[i + 1]])
)
}
result
}
resolve(c("2", "+", "4", "*", "4"))
```
Now we can use this resolve function in a parser combinator:
```{r}
library(Ramble)
pPlusOrTimes <- symbol("+") %alt% symbol("*")
pExpr <- (pBlock %then% many(pPlusOrTimes %then% pBlock)) %using%
function(x) {
resolve(unlist(c(x)))
}
pBlock <- (natural() %using% function(x) {
as.numeric(unlist(c(x)))
}) %alt%
((symbol("(") %then%
pExpr %then%
symbol(")")) %using% function(x) {
unlist(c(x))[[2]]
})
pExpr("1+(2+4*4)")
```
And finally compute the answer
```{r}
input %>%
map_dbl(~ pExpr(.)$result) %>%
sum() %>%
format(scientific = F)
```
# Part 2
Now, addition and multiplication have different precedence levels, but they're
not the ones you're familiar with. Instead, addition is evaluated before
multiplication.
That should actually be easier cause associativity no longer matters and we can
evaluate everything eagerly.
```
expr :: = factor * expr | factor
factor :: = term + expr | term
term :: = (expr) | digit+
```
```{r}
pExpr <- ((pFactor %then%
symbol("*") %then%
pExpr %using% function(x) {
prod(as.numeric(unlist(c(x))[c(1, 3)]))
}) %alt% pFactor)
pFactor <- ((pTerm %then%
symbol("+") %then%
pFactor %using% function(x) {
sum(as.numeric(unlist(c(x))[c(1, 3)]))
}) %alt% pTerm)
pTerm <- ((symbol("(") %then%
pExpr %then%
symbol(")") %using% function(x) {
return(as.numeric(unlist(c(x))[2]))
}) %alt% natural())
pExpr("4*4*(8+4*2*3+(6+6*7+6)+(7+4*9*7+2))")
```
And the answer
```{r}
input %>%
map_dbl(~ pExpr(.)$result) %>%
sum() %>%
format(scientific = F)
```