Advent of Code 2024, Day 13
Day 13 brings us LaTeX, high school math, coordinate systems, graphing, vectors, equation sets, and variable types for memory layout.
Part of the AoC 2024 series
Claw machines and lots of irrelevant details for part 1 make this somewhat of a cute problem that takes me back to my high school math classes.
Spoilers
Part 1
So much unnecessary information! So each button will move a certain distance in the X and Y coordinates. That makes them vectors. Because they move the set distance per push of a button, you can only have integer (whole number) number of vectors each.
I am starting to notice a bunch of patterns that Iām falling into. For example previously I would parse the input in a setup code, and only once I have pristine and correctly parsed values do I instantiate structs.
I have now since figured out that the .try_from() -> Option<t>
associated functions encapsulate that parsing and maybe creating a thing out of whatever I pass in.
So instead of breaking up the following input into individual lines, stripping the front, splitting the numbers by the ,
, stripping the X=
, X+
, Y=
, and Y+
prefixes and then parsing the numbersāasāstrings into i32
, I just chuck the entire block at the Vector::try_from(input &str) -> Result<Vector, Error>
associated function. It makes code so much cleaner and actually moves work to places where they make more sense.
I also learned what the difference between an associated function and a method is.
An associated function is in an impl
block for a struct, but it does not take &self
as an argument, which means I can call Vector::try_from
, but I canāt call Vector::new(0, 1).try_from()
. A method takes the &self
as argument, which means I canāt call Vector::least_tokens()
, because that needs an already instantiated object (wrong word, but itāll do) of Vector type.
Back to the coding bit. Itās essentially just math. Iām going to use the first example to illustrate what I do:
Button A: X+94, Y+34
Button B: X+22, Y+67
Prize: X=8400, Y=5400
The two vectors are \( \vec{(94, 34)} \) and \( \vec{(22, 67)} \). We need some combination of these to get to point \( (8400, 5400) \). The following two equations need to hold true at the same time:
\[ \begin{align*} \begin{cases} A * 94 + B * 22 & = 8400 \\ A * 34 + B * 67 & = 5400 \end{cases} \end{align*} \]Letās subtract the top one from the bottom one after normalizing them around \( A \):
\[ \begin{align*} \begin{cases} 34 * ( A * 94 + B * 22 )&= 34 * 8400\\ 94 * ( A * 34 + B * 67 )&= 94 * 5400 \end{cases} \\ \begin{cases} A * 3196 + B * 748 &= 285600 \\ A * 3196 + B * 6298 &= 507600 \end{cases}\\ A * 3196 + B * 6298 - A * 3196 - B * 748 &= 507600 - 285600 \\ A * (3196 - 3196) + B * (6298 - 748) &= 222000 \\ A * 0 + B * 5550 &= 222000 \\ B * 5550 &= 222000 \\ B &= \frac {222000} {5550} \\ B &= 40 \end{align*} \]Now that we have \( B \), we can plug that back into one of the starter equations:
\[ \begin{align*} A * 94 + \bold{B} * 22 & = 8400 \\ A * 94 + \bold{40} * 22 & = 8400 \\ A * 94 + 880 & = 8400 \\ A * 94 &= 8400 - 880 \\ A * 94 &= 7520 \\ A &= \frac {7520} {94} \\ A &= 80 \end{align*} \]And voilĆ”, we have our \( A \) and \( B \) values. We can price it up, and get the correct score for that machine. All I had to do is take the input, run it through my code, and now I have my solution of 40069. Nice!
Part 2
Whoops, the coordinates of the target are so much farther away. However because I already used math and algorithms to solve part 1, part 2 was a relatively minor adjustment where I had to change the visibility of the Coordinate
and ClawMachine
structs to be pub(crate)
, some of their associated functions, and create two new versions of try_from
for both of them.
On the Coordinate
itās mostly the same, but adds the new extra number to the parsed numbers, as the input doesnāt change, and in ClawMachine
it calls the new try_from
for the Coordinate
.
The other issue was that \( 10,000,000,000,000 \) did not fit into i32
neatly, and using u64
resulted in a negative number at some point, which is kind of a big noāno for an unsigned number, so turned everything into i64
and f64
. Thankfully both of those could take all values without further changes.
Got my two āļøāļøs, onwards to day 14!