Day 12 Rain Risk
This is my attempt to solve Day 12.
read_lines("samples/day_12_sample.txt")
sample <- read_lines("inputs/day_12_input.txt") actual <-
12.1 Part 1
Today’s task could be a tedious series of if else statements. Instead I will use Object-Orientated Programming and the s3 class system. I will strip the initial input to just be the number, but I will give each of the inputs a class of “N”, “E”, “W”, “S”, “F”, “R”, or “L”.
function(input) {
split_instructions <-transpose(
list(
d = str_sub(input, 1, 1),
n = as.integer(str_sub(input, 2))
)%>%
) map(function(.x) {
structure(.x$n, class = .x$d)
})
}
split_instructions(sample)
isample <- split_instructions(actual)
iactual <- isample
## [[1]]
## [1] 10
## attr(,"class")
## [1] "F"
##
## [[2]]
## [1] 3
## attr(,"class")
## [1] "N"
##
## [[3]]
## [1] 7
## attr(,"class")
## [1] "F"
##
## [[4]]
## [1] 90
## attr(,"class")
## [1] "R"
##
## [[5]]
## [1] 11
## attr(,"class")
## [1] "F"
First, let’s define the initial state:
list(direction = "E", position = c(0, 0)) initial_state <-
We now need to create a function called that will run an instruction: I will call this function inst
. It will take as
argument the object itself (n
), this will contain the number from the input. It will also take the current state.
function(n, state) {
inst <-UseMethod("inst")
}
Now we need to implement a method for each of the classes. Let’s start with the N/E/S/W classes. These methods are
pretty simple, we just need to add on n
to the current position.
# create a helper function that the other functions use
function(state, p) {
inst_NESW_helper <-$position <- state$position + p
state
state
}
function(n, state) inst_NESW_helper(state, c( n, 0))
inst.N <- function(n, state) inst_NESW_helper(state, c( 0, n))
inst.E <- function(n, state) inst_NESW_helper(state, c(-n, 0))
inst.S <- function(n, state) inst_NESW_helper(state, c( 0, -n)) inst.W <-
The L/R functions are slightly more tricky, but, looking at the actual data there are only 3 different angles that are turned:
%>% str_subset("L|R") %>% str_remove("L|R") %>% unique() actual
## [1] "90" "180" "270"
We can create our function now. This time, we our helper function will just rotate the direction that we are facing.
function(state, r) {
inst_LR_helper <- c("N", "E", "S", "W")
directions <- which(state$direction == directions) - 1
current <- (current + r / 90) %% 4
next_direction <-
$direction = directions[[next_direction + 1]]
state
state
}
# L turns anti-clockwise, so we can turn it into a clockwise rotation
function(n, state) inst_LR_helper(state, 360 - n)
inst.L <- function(n, state) inst_LR_helper(state, n) inst.R <-
Finally we can create our function for moving forward. In this case we will take the value from n
, but update the
class to be that of the current direction from state
.
function(n, state) {
inst.F <- structure(n, class = state$direction)
nn <-inst(nn, state)
}
Now we have all the parts we can build our function to solve part 1. We start with an initial state, and keep calling a function on each successive value in the input with the current state. To do this we can use the reduce function.
function(input, state = initial_state) {
solve <- reduce(
final_state <-
input,.init = initial_state,
function (state, instruction) {
inst(instruction, state)
}
)
sum(abs(final_state$position))
}
Checking the sample data:
solve(isample) == 25
## [1] TRUE
We can now run with the actual data:
solve(iactual)
## [1] 1032
12.2 Part 2
We can now update our instruction functions, our solver should still work.
First we need to update our initial state.
list(waypoint = c(1, 10), position = c(0, 0)) initial_state <-
We can cheat a bit on the N/E/S/W functions: we can just change the update position helper function to instead update the waypoint.
function(state, p) {
inst_NESW_helper <-$waypoint <- state$waypoint + p
state
state }
Likewise, we just need to update the L/R helper function. We can use matrix multiplication to rotate our waypoint.
function(state, r) {
inst_LR_helper <-# r is either 90, 180, 270, and it a clockwise rotation
matrix(
rot_mat <-if (r == 90) {
c(0, 1, -1, 0)
else if (r == 180) {
} c(-1, 0, 0, -1)
else {
} c(0, -1, 1, 0)
},nrow = 2
)
$waypoint <- (rot_mat %*% state$waypoint)[,1]
state
state }
We now just need to update the F function.
function(n, state) {
inst.F <- state$waypoint
w <- state$position
s <-
$position <- w * n + s
state
state }
We should now be in a position to run our solve
function again. Checking the sample:
solve(isample) == 286
## [1] TRUE
We can now run with the actual data:
solve(iactual)
## [1] 156735
Elapsed Time: 0.278s