Day 12 Rain Risk
This is my attempt to solve Day 12.
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”.
split_instructions <- function(input) {
transpose(
list(
d = str_sub(input, 1, 1),
n = as.integer(str_sub(input, 2))
)
) %>%
map(function(.x) {
structure(.x$n, class = .x$d)
})
}
isample <- split_instructions(sample)
iactual <- split_instructions(actual)
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:
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.
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
inst_NESW_helper <- function(state, p) {
state$position <- state$position + p
state
}
inst.N <- function(n, state) inst_NESW_helper(state, c( n, 0))
inst.E <- function(n, state) inst_NESW_helper(state, c( 0, n))
inst.S <- function(n, state) inst_NESW_helper(state, c(-n, 0))
inst.W <- function(n, state) inst_NESW_helper(state, c( 0, -n))
The L/R functions are slightly more tricky, but, looking at the actual data there are only 3 different angles that are turned:
## [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.
inst_LR_helper <- function(state, r) {
directions <- c("N", "E", "S", "W")
current <- which(state$direction == directions) - 1
next_direction <- (current + r / 90) %% 4
state$direction = directions[[next_direction + 1]]
state
}
# L turns anti-clockwise, so we can turn it into a clockwise rotation
inst.L <- function(n, state) inst_LR_helper(state, 360 - n)
inst.R <- function(n, state) inst_LR_helper(state, n)
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
.
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.
solve <- function(input, state = initial_state) {
final_state <- reduce(
input,
.init = initial_state,
function (state, instruction) {
inst(instruction, state)
}
)
sum(abs(final_state$position))
}
Checking the sample data:
## [1] TRUE
We can now run with the actual data:
## [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.
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.
Likewise, we just need to update the L/R helper function. We can use matrix multiplication to rotate our waypoint.
inst_LR_helper <- function(state, r) {
# r is either 90, 180, 270, and it a clockwise rotation
rot_mat <- matrix(
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
)
state$waypoint <- (rot_mat %*% state$waypoint)[,1]
state
}
We now just need to update the F function.
inst.F <- function(n, state) {
w <- state$waypoint
s <- state$position
state$position <- w * n + s
state
}
We should now be in a position to run our solve
function again. Checking the sample:
## [1] TRUE
We can now run with the actual data:
## [1] 156735
Elapsed Time: 0.278s