01020304050607080910111213141516171819202122232425

Advent of Code

2024/13

Claw Contraption

in C#

by encse

Next up: the lobby of a resort on a tropical island. The Historians take a moment to admire the hexagonal floor tiles before spreading out.

Fortunately, it looks like the resort has a new arcade! Maybe you can win some prizes from the claw machines?

Visit the website for the full story and puzzle description.

We got a math problem today. The movements triggered by buttons A, B and the target position P form a linear equation that we can solve for the two unknowns: the number of button presses. Using math terms, if i and j marks the number of button presses, we are to solve A * i + B * j = P. This is simple enough to do using Cramer's rule, especially with two dimensional vectors. In this case the determinats can be computed with a simple cross product. We should not forget about the special cases: A and B can be parallel (didn't occur in my input), and the solution needs to be non negative integer for i and j.

namespace AdventOfCode.Y2024.Day13;

using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Machine = (Vec2 a, Vec2 b, Vec2 p);

record struct Vec2(long x, long y);

[ProblemName("Claw Contraption")]
class Solution : Solver {

    public object PartOne(string input) => Parse(input).Sum(GetPrize);
    public object PartTwo(string input) => Parse(input, shift: 10000000000000).Sum(GetPrize);

    long GetPrize(Machine m) {
        var (a, b, p) = m;

        // solve a * i + b * j = p for i and j using Cramer's rule
        var i = Det(p, b) / Det(a, b);
        var j = Det(a, p) / Det(a, b);

        // return the prize when a non negative _integer_ solution is found
        if (i >= 0 && j >= 0 && a.x * i + b.x * j == p.x && a.y * i + b.y * j == p.y) {
            return 3 * i + j;
        } else {
            return 0;
        }
    }

    long Det(Vec2 a, Vec2 b) => a.x * b.y - a.y * b.x;

    IEnumerable<Machine> Parse(string input, long shift=0) {
        var blocks = input.Split("\n\n");
        foreach (var block in blocks) {
            var nums =
                Regex.Matches(block, @"\d+", RegexOptions.Multiline)
                    .Select(m => int.Parse(m.Value))
                    .Chunk(2).Select(p => new Vec2(p[0], p[1]))
                    .ToArray();

            nums[2] = new Vec2(nums[2].x + shift, nums[2].y + shift);
            yield return (nums[0], nums[1], nums[2]);
        }
    }
}

Please ☆ my repo if you like it!

© 2025 Advent of Code is a registered trademark in the US Images provided by Bing image creator