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

Advent of Code 2024/7

2024/7.livemd

Advent of Code 2024/7

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

Section

input = Kino.Input.textarea("input")
defmodule AoC2024_7 do
  def parse(input) do
    Kino.Input.read(input)
    |> String.split("\n\n", trim: true)
    |> Enum.map(fn part -> String.split(part, "\n", trim: true) |> Enum.map(fn row -> row_parser(row) end) end)
    |> Enum.at(0)
  end

  def row_parser(row) do
    [result, parts] = String.split(row, ":", trim: true)
    {String.split(parts, " ", trim: true) |> Enum.map(fn part -> String.to_integer(part) end), String.to_integer(result)}
  end

  def step(list, operators \\ ["+", "*"])
  def step([element | []], _operators), do: [[element]]
  def step([element | rest], operators) do
    step(rest, operators)
    |> Enum.flat_map(fn path -> Enum.map(operators, fn operator -> [element, operator] ++ path end) end)
  end

  def split_by_cocatenation(list) do
    list
    |> Enum.chunk_by(fn x -> x == "||" end)
    |> Enum.reject(fn x -> x == ["||"] end)
  end

  def calculate_position(item, acc, "+"), do: acc + item
  def calculate_position(item, acc, "*"), do: acc * item
  def calculate_position(item, acc, "||"), do: String.to_integer(Enum.join([acc, item]))

  def calculate(list) do
    tl(list)
    |> Enum.chunk_every(2)
    |> Enum.reduce(hd(list), fn [op, item], acc -> calculate_position(item, acc, op) end)
  end

  def check_row({parts, result}, operators \\ ["+", "*"]) do
    Enum.any?(step(parts, operators), fn el -> calculate(el) == result end)
  end

  def part_1(input) do
    input
    |> parse
    |> Enum.filter(fn row -> check_row(row) end)
    |> Enum.map(fn row -> elem(row, 1) end)
    |> Enum.sum
  end

  def part_2(input) do
    input
    |> parse
    |> Enum.filter(fn row -> check_row(row, ["+", "*", "||"]) end)
    |> Enum.map(fn row -> elem(row, 1) end)
    |> Enum.sum
  end
end
AoC2024_7.part_1(input)
AoC2024_7.part_2(input)