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

AoC2022/01

Aoc2022.livemd

AoC2022/01

Mix.install([
  {:memoize, "~> 1.4"},
  {:tesla, "~> 1.4"}
])

defmodule Api do
  use Tesla
  use Memoize

  @session System.fetch_env!("AOC_SESSION_COOKIE")

  plug(Tesla.Middleware.BaseUrl, "https://adventofcode.com/2022/day/")

  plug(Tesla.Middleware.Headers, [
    {"cookie", "session=#{@session}"}
  ])

  defmemo get_input(day) do
    {:ok, response} = get("#{day}/input")
    response.body
  end
end

Day 1

calories_per_elf =
  Api.get_input(1)
  |> String.split("\n\n")
  |> Enum.map(fn inventory ->
    inventory
    |> String.split("\n", trim: true)
    |> Enum.map(fn item ->
      String.to_integer(item)
    end)
    |> Enum.sum()
  end)

p1 = calories_per_elf |> Enum.max()

p2 = calories_per_elf |> Enum.sort(:desc) |> Enum.take(3) |> Enum.sum()

{p1, p2}

Day 2

require Integer

# Replace rock(A|X), paper(B|Y) and scissors(C|Z) with corresponding points
# rock = 1, paper = 2, scissors = 3
processed_input =
  Api.get_input(2)
  |> String.split("\n", trim: true)
  |> Enum.map(fn fight ->
    String.replace(fight, ~r/(A|X)/, "1")
    |> String.replace(~r/(B|Y)/, "2")
    |> String.replace(~r/(C|Z)/, "3")
    |> String.split(" ", trim: true)
    |> Enum.map(fn x -> String.to_integer(x) end)
  end)

p1 =
  processed_input
  |> Enum.map(fn [x, y] ->
    v = x - y
    isEven = Integer.is_even(v)

    case v do
      0 -> y + 3
      v when v > 0 -> if isEven, do: y + 6, else: y
      v when v < 0 -> if !isEven, do: y + 6, else: y
    end
  end)
  |> Enum.sum()

# [rock, paper, scissors]
status = [1, 2, 3]

# Next element loses with the previous one:
# rock < paper < scissors < rock
#   1  <   2   <    3     <   1
p2 =
  processed_input
  |> Enum.map(fn [x, y] ->
    case y do
      1 -> Enum.at(status, rem(x + 1, 3))
      2 -> x + 3
      3 -> Enum.at(status, rem(x, 3)) + 6
    end
  end)
  |> Enum.sum()

{p1, p2}

Day 3

# Starts with 0 so priority list index correspond to item priority
priority = "0abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
input = Api.get_input(3)

p1 =
  input
  |> String.split("\n", trim: true)
  |> Enum.map(fn rucksack ->
    {compartment1, compartment2} =
      rucksack
      |> String.split_at(div(String.length(rucksack), 2))

    Enum.find(String.codepoints(compartment1), fn itemInCompartment1 ->
      Enum.find(String.codepoints(compartment2), fn itemInCompartment2 ->
        itemInCompartment1 == itemInCompartment2
      end)
    end)
  end)
  |> Enum.map(fn item ->
    String.codepoints(priority)
    |> Enum.find_index(fn p -> p == item end)
  end)
  |> Enum.sum()

p2 =
  input
  |> String.split("\n", trim: true)
  |> Enum.chunk_every(3)
  |> Enum.map(fn [rucksack1, rucksack2, rucksack3] ->
    Enum.find(String.codepoints(rucksack1), fn itemInRucksack1 ->
      Enum.find(String.codepoints(rucksack2), fn itemInRucksack2 ->
        Enum.find(String.codepoints(rucksack3), fn itemInRucksack3 ->
          itemInRucksack1 == itemInRucksack2 and
            itemInRucksack2 == itemInRucksack3
        end)
      end)
    end)
  end)
  |> Enum.map(fn item ->
    String.codepoints(priority)
    |> Enum.find_index(fn p -> p == item end)
  end)
  |> Enum.sum()

{p1, p2}

Day 4

test_input = "2-4,6-8
2-3,4-5
5-7,7-9
2-8,3-7
6-6,4-6
2-6,4-8"

input = Api.get_input(4)

p1 =
  input
  |> String.split("\n", trim: true)
  |> Enum.map(fn pair -> String.split(pair, ",") end)
  |> Enum.map(fn [d1, d2] ->
    [x1, x2] = String.split(d1, "-") |> Enum.map(&amp;String.to_integer(&amp;1))
    [y1, y2] = String.split(d2, "-") |> Enum.map(&amp;String.to_integer(&amp;1))

    (x1 <= y1 and x2 >= y2) or
      (x1 >= y1 and x2 <= y2)
  end)
  |> Enum.map(fn dup -> if dup, do: 1, else: 0 end)
  |> Enum.sum()

p2 =
  input
  |> String.split("\n", trim: true)
  |> Enum.map(fn pair -> String.split(pair, ",") end)
  |> Enum.map(fn [d1, d2] ->
    [x1, x2] = String.split(d1, "-") |> Enum.map(&amp;String.to_integer(&amp;1))
    [y1, y2] = String.split(d2, "-") |> Enum.map(&amp;String.to_integer(&amp;1))

    (x1 <= y1 and x2 >= y1) or
      (x1 >= y1 and x1 <= y2)
  end)
  |> Enum.map(fn dup -> if dup, do: 1, else: 0 end)
  |> Enum.sum()

{p1, p2}