library(tidyverse)
library(ggdark)
library(khroma)
library(showtext)
library(scales)
font_add_google(name = "Mountains of Christmas", family = "christmas")
font_add(family = "Noto Emoji", regular = file.path(font_paths()[2], "NotoEmoji-VariableFont_wght.ttf"))
showtext_auto()
theme_set(dark_theme_gray() +
theme(title = element_text(family = "christmas", size = 20)))
::knit_hooks$set(crop = knitr::hook_pdfcrop) knitr
Day 9
list()
Part 1
Ok… step 1 I think is a function for calculating the distance between H and T.
<- c(2,2)
Head <- c(1,1)
Tail <- (Head - Tail)^2
x max(x)
[1] 1
Ok, I think if \(\max((H-T)^2) <=1\) then we don’t update, otherwise, update.
<- function(Head, Tail){
move_decision <- (Head-Tail) ^2
distance return(max(distance) > 1)
}
move_decision(c(0,0), c(0,1))
[1] FALSE
move_decision(c(0,0), c(1,0))
[1] FALSE
move_decision(c(0,0), c(1,1))
[1] FALSE
move_decision(c(0,0), c(0,2))
[1] TRUE
move_decision(c(0,0), c(1,2))
[1] TRUE
Now, decide which way to move.
## 1 Dim
<- c(0,0)
Head <- c(0,2)
Tail - Tail Head
[1] 0 -2
Can’t just do \(\frac{H-T}{2}\) because of the diagonal case
## 2 dim
<- c(0,0)
Head <- c(1,2)
Tail - Tail Head
[1] -1 -2
I think I can just use their sign though!
## 1 dim
<- c(0,0)
Head <- c(0,2)
Tail sign(Head - Tail)
[1] 0 -1
## 2 dim
<- c(0,0)
Head <- c(1,2)
Tail sign(Head - Tail)
[1] -1 -1
<- function(Head, Tail){
move_vector sign(Head-Tail)
}
Ok, let’s load up the data and plan our history management.
<- read_table("2022-12-9_assets/input.txt", col_names = FALSE) route
── Column specification ────────────────────────────────────────────────────────
cols(
X1 = col_character(),
X2 = col_double()
)
|> head() route
# A tibble: 6 × 2
X1 X2
<chr> <dbl>
1 U 1
2 L 1
3 D 2
4 U 2
5 R 2
6 D 1
I’ll make all steps explicit by multiplying out X1
by X2
times
<-
full_route |>
route mutate(all_steps = map2(X1, X2, ~tibble(step = rep(.x, .y)))) |>
select(all_steps) |>
unnest(cols = all_steps) |>
mutate(step_num = (1:n()) + 1)
I think I’ll pre-compile an empty list to store head and tail states.
<- vector(mode = "list", length = max(full_route$step_num))
Head_list <- vector(mode = "list", length = max(full_route$step_num)) Tail_list
Initial state
1]] <- c(0,0)
Head_list[[1]] <- c(0,0) Tail_list[[
Now, a function to return update move for the Head given U
, D
, L
, R
. I’ll make it a function but it could just be a named list
<- function(dir){
Head_move <- list(
move_list U = c(0,1),
D = c(0,-1),
L = c(-1,0),
R = c(1,0)
)return(move_list[[dir]])
}
Now, a function that takes:
Head move direction
step number
the Head states
the Tail states
And updates the Head and Tail states.
Ok, I hate this… but I’m going to use the global variables.
<- function(dir, step){
Head_Tail_update <- Head_list[[step-1]]
Head_prev <- Tail_list[[step-1]]
Tail_prev <- Head_move(dir)
head_movement
<- Head_prev + head_movement
Head_now if(move_decision(Head_now, Tail_prev)){
<- move_vector(Head_now, Tail_prev)
tail_movement <- Tail_prev + tail_movement
Tail_now else {
} <- Tail_prev
Tail_now
}<<- Head_now
Head_list[[step]] <<- Tail_now
Tail_list[[step]] return()
}
<- map2(full_route$step, full_route$step_num, Head_Tail_update) x
The answer
|>
Tail_list reduce(rbind) |>
unique() |>
nrow()
[1] 6271
<-
tail_pos_df |>
Tail_list reduce(rbind) |>
data.frame() |>
mutate(part = "tail",
step = 1:n())
<-
head_pos_df |>
Head_list reduce(rbind) |>
data.frame() |>
mutate(part = "head",
step = 1:n())
<- bind_rows(tail_pos_df, head_pos_df) all_pos
|>
all_pos ggplot(aes(X1, X2, color = step)) +
geom_point(size = 0.2, alpha = 0.2) +
coord_fixed()+
scale_color_hawaii()+
labs(x = "x",
y = "y",
title = "path of head and tail")+
facet_wrap(~part)
Part 2
Ok, I think I can keep a lot of my functions the same, just the Tail state is now a list of 9 vectors, and every head movement involves updating the tail state 9 times.
<- rep(list(c(0,0)), max(full_route$step_num))
Head_list <- map(1:max(full_route$step_num), ~rep(list(c(0,0)), 9)) Tail_list
<- function(dir, step){
Head_Tail_update2 <- Head_list[[step-1]]
Head_prev
<- Head_move(dir)
head_movement
<- Head_prev + head_movement
Head_now <<- Head_now
Head_list[[step]]
<- Head_now
reference <<- Tail_list[[step-1]]
Tail_list[[step]]
for(i in 1:9){
<- Tail_list[[step-1]][[i]]
Tail_prev if(move_decision(reference, Tail_prev)){
<- move_vector(reference, Tail_prev)
tail_movement <- Tail_prev + tail_movement
Tail_now <<- Tail_now
Tail_list[[step]][[i]] <- Tail_now
reference else {
} # I've already copied the previous tail states
# If this tail didn't move, none of the rest will either
break
}
}return()
}
<- map2(full_route$step, full_route$step_num, Head_Tail_update2) x
map(Tail_list, ~.x[[9]]) |>
reduce(rbind) |>
unique() |>
nrow()
[1] 2458
<-
tail_pos_df map(Tail_list, ~.x[[9]]) |>
reduce(rbind) |>
data.frame() |>
mutate(part = "tail",
step = 1:n())
## head_pos_df the same
<- bind_rows(tail_pos_df, head_pos_df) all_pos
|>
all_pos ggplot(aes(X1, X2, color = step)) +
geom_point(size = 0.2, alpha = 0.2) +
coord_fixed()+
scale_color_hawaii()+
labs(x = "x",
y = "y",
title = "path of head and tail")+
facet_wrap(~part)