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

Day 20

day20.livemd

Day 20

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

Section

input = """
1
2
-3
3
-2
0
4
"""
input = Kino.Input.textarea("paste input here:")
input = Kino.Input.read(input)
defmodule Grove do
  def insert_pos(j, offset, size) do
    val = Integer.mod(j + offset, size - 1)

    if val != 0 or offset == 0 do
      val
    else
      -1
    end
  end

  def read_input(input) do
    input
    |> String.split()
    |> Enum.map(&String.to_integer/1)
    |> Enum.with_index(fn element, index -> {index, element} end)
    |> Map.new()
  end

  def mix(list, mapping, size) do
    Enum.to_list(0..(size - 1))
    |> Enum.reduce(list, fn i, acc ->
      # IO.inspect(Enum.map(acc, &mapping[&1]))
      j = Enum.find_index(acc, &(&1 == i))
      # IO.inspect(j)
      # IO.inspect(insert_pos(j, mapping[i], size))
      acc
      |> List.delete_at(j)
      |> List.insert_at(insert_pos(j, mapping[i], size), i)
    end)
  end

  def get_answer(mixed, size) do
    zero_index = Enum.find_index(mixed, &(&1 == 0))

    [1000, 2000, 3000]
    |> Enum.map(&Enum.at(mixed, rem(&1 + zero_index, size)))
    |> Enum.sum()
  end

  def part1(input) do
    mapping = read_input(input)

    size = map_size(mapping)

    mixed =
      mix(Enum.to_list(0..(size - 1)), mapping, size)
      |> Enum.map(&mapping[&1])

    # IO.inspect(mixed)
    get_answer(mixed, size)
  end

  def part2(input) do
    mapping = read_input(input) |> Map.new(fn {k, v} -> {k, v * 811_589_153} end)
    size = map_size(mapping)

    mixed =
      1..10
      |> Enum.reduce(Enum.to_list(0..(size - 1)), fn _, list ->
        # IO.puts("new round")
        mix(list, mapping, size)
      end)
      |> Enum.map(&mapping[&1])

    get_answer(mixed, size)
  end
end
Grove.part1(input)
Grove.part2(input)