DEV Community

Cover image for Claw Contraption
Robert Mion
Robert Mion

Posted on

Claw Contraption

Advent of Code 2024 Day 13

Part 1

Big gulp: every permutation?

Another dreaded shortest path challenge.

Thankfully, it sounds doable with brute force, thanks to the constraint specified:

  • No more than 100 button presses

That means if there is a solution, it exists within 1 of 10,000 permutations: 100 * 100 = 10,000

Each machine is represented as 3 lines (plus 1 empty line) in the input, totaling 4 lines.

My input is 1280 lines long.

Thus, the most computations my algorithm would make is:

 100 * 100 ------ 10000 * 1280 / 4 ------ 320 ====== 3200000 
Enter fullscreen mode Exit fullscreen mode

3.2M computations isn't bad at all.

Brute force may be an option for Part 1.

Worth a try!

Attempting to brute-force the solution

Turning strings into integers

First, I need to extract the six important numbers from each machine's input:

input .split('\n') .map(block => { let [AX, AY, BX, BY, PX, PY] = [ ...block.matchAll(/d+/g).map(el => +el[0]) ] }) 
Enter fullscreen mode Exit fullscreen mode

I wrote that here. Then I ran it in a code editor.

Then I debugged and fixed it until I saw the code I expected.

My working algorithm looks like this:

input .split('\n\n') .map(block => [ ...block.matchAll(/\d+/g) ].map(el => +el[0]) ) 
Enter fullscreen mode Exit fullscreen mode

I made some silly mistakes.

But I now see this in my console:

[ [ 94, 34, 22, 67, 8400, 5400 ], [ 26, 66, 67, 21, 12748, 12176 ], [ 17, 86, 84, 37, 7870, 6450 ], [ 69, 23, 27, 71, 18641, 10279 ] ] 
Enter fullscreen mode Exit fullscreen mode

Perfect!

Prepping for 10k permutations

Some tracking variables with starter amounts, and nested loops that count to 100, all inside a reduce that processes each machine:

let part1 = input.reduce( (total, machine) => { let [AX, AY, BX, BY, PX, PY] = machine let min = Infinity let minA = Infinity let minB = Infinity for (let A = 0; A <= 100; A++) { for (let B = 0; B <= 100; B++) { } } return total }) 
Enter fullscreen mode Exit fullscreen mode

Next, some condi-tions, addi-tions and multiplica-tions:

// inside the nested for loops if ((A * AX + B * BX == PX) && (A * AY + B * BY == PY)) { if (3 * A + B < min) { minA = 3 * A minB = B min = minA + minB } } 
Enter fullscreen mode Exit fullscreen mode

Again, I wrote that first here.

Then I copy-pasted it into my code editor and ran it.

And I saw the expected winning token amounts!

I got excited and wrote the rest of the algorithm.

After some clean-up and debugging, here's the final working code:

let part1 = input.reduce( (total, machine) => { let [AX, AY, BX, BY, PX, PY] = machine let min = Infinity for (let A = 0; A <= 100; A++) { for (let B = 0; B <= 100; B++) { if ((A * AX + B * BX == PX) && (A * AY + B * BY == PY)) { if (3 * A + B < min) { min = 3 * A + B } } } } if (min < Infinity) { total += min } return total }, 0) 
Enter fullscreen mode Exit fullscreen mode

Running it on the example input generates the correct answer.

What about on my puzzle input?

...

Well, it finished within a second.

And generated an answer in the 10's of thousands.

Is it correct?

...

It is!

Sweet!

I don't anticipate having the computer science knowledge to refactor my brute-force algorithm into something that can solve Part 2.

I'm still excited to see the twist, though!

Part 2

Yyyyuuupp. Just what I suspected.

1 trillion higher? Yikes!

Just like yesterday's Part 2, I'm stumped.

Bummer.

After a 10-day streak of 2-stars, I'm on a 3-day streak of 1-stars.

To be fair, this is usually the spot each year where I get 0 or 1 stars.

At least I got 1!

Onward to Day 14.

Top comments (0)