Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Advent of Code 2024

2024/day13.livemd

Advent of Code 2024

Mix.install([
  {:req, "~> 0.5.8"},
  {:kino, "~> 0.14.2"}
])

Day 13

Kino.configure(inspect: [charlists: :as_lists])
input =
  "https://adventofcode.com/2024/day/13/input"
  |> Req.get!(headers: [cookie: "session=#{System.get_env("AOC_COOKIE")}"])
  |> Map.get(:body)
sample =
  """
  Button A: X+94, Y+34
  Button B: X+22, Y+67
  Prize: X=8400, Y=5400

  Button A: X+26, Y+66
  Button B: X+67, Y+21
  Prize: X=12748, Y=12176

  Button A: X+17, Y+86
  Button B: X+84, Y+37
  Prize: X=7870, Y=6450

  Button A: X+69, Y+23
  Button B: X+27, Y+71
  Prize: X=18641, Y=10279
  """
defmodule Day13 do
  def parse(input) do
    input
    |> String.split("\n\n", trim: true)
    |> Enum.map(fn lines ->
      lines
      |> String.split("\n", trim: true)
      |> Enum.map(fn s ->
        [_, _, a, _, b] = Regex.run(~r/X(\+|=)(\d+), Y(\+|=)(\d+)/, s)

        [a, b]
        |> Enum.map(&String.to_integer/1)
        |> List.to_tuple()
      end)
    end)
  end

  def cheapest_prize({ax, ay}, {bx, by}, {gx, gy}) do
    # n * ax + m * bx = gx
    # n * ay + m * by = gy

    # use maths to eliminate one of the variables (n or m)
    #
    # let's remove m
    # multiply by by: by * n * ax + m * bx * by = gx * by
    # multiply by bx: bx * n * ay + m * bx * by = gy * bx
    #
    # then subtract the equations
    # by * n * ax - bx * n * ay = gx * by - gy * bx
    # 
    # extract n
    # n * (by * ax - bx * ay) = gx * by - gy * bx
    #
    # solve for n
    # n = (gx * by - gy * bx) / (by * ax - bx * ay)
    a = (gx * by - gy * bx) / (by * ax - bx * ay)

    # solve for m by substituting n
    # m = (gx - n * ax) / bx
    b = (gx - a * ax) / bx

    # if we have integers, we have a solution
    if trunc(a) == a && trunc(b) == b do
      3 * trunc(a) + trunc(b)
    else
      0
    end
  end

  def fewest_tokens(machines, addend \\ 0) do
    machines
    |> Enum.map(fn [{ax, ay}, {bx, by}, {gx, gy}] ->
      cheapest_prize({ax, ay}, {bx, by}, {gx + addend, gy + addend})
    end)
    |> Enum.sum()
  end
end
import Day13

Part 1

input
|> parse()
|> fewest_tokens()

Part 2

input
|> parse()
|> fewest_tokens(10000000000000)