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

Day 20

2022/elixir/day20.livemd

Day 20

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

Puzzle Input

area = Kino.Input.textarea("Puzzle Input")
puzzle_input = Kino.Input.read(area)
example_input = """
1
2
-3
3
-2
0
4
"""
input = puzzle_input

Common

list =
  input
  |> String.split("\n", trim: true)
  |> Stream.map(&(&1 |> Integer.parse() |> elem(0)))
  |> Enum.with_index()
defmodule Index do
  defstruct [:list, :size]

  def new(list) do
    %Index{
      list: list,
      size: Enum.count(list)
    }
  end

  def move(%Index{} = index, {offset, _} = pair) do
    current_index = find(index, pair)

    len = index.size - 1

    shift = current_index + offset

    new_index =
      case shift do
        val when val <= 0 ->
          val - len * floor(val / len)

        val when val > len ->
          rem(val, len)

        val ->
          val
      end

    list = index.list |> Enum.reject(&amp;(&amp;1 == pair)) |> List.insert_at(new_index, pair)
    %{index | list: list}
  end

  def at(%Index{} = index, i) do
    index.list |> Enum.at(rem(i, index.size)) |> elem(0)
  end

  def find(%Index{} = index, {_, _} = value) do
    index.list
    |> Stream.with_index()
    |> Enum.find(fn {element, _index} -> element == value end)
    |> then(&amp;elem(&amp;1, 1))
  end

  def find(%Index{} = index, value) do
    index.list
    |> Stream.with_index()
    |> Enum.find(fn {{element, _}, _index} -> element == value end)
    |> then(&amp;elem(&amp;1, 1))
  end

  def decryption_key(%Index{} = index) do
    offset = Index.find(index, 0)

    [1000, 2000, 3000]
    |> Enum.map(&amp;Index.at(index, &amp;1 + offset))
    |> Enum.sum()
  end
end

Part One

index = Index.new(list)
mixed = Enum.reduce(list, index, &amp;Index.move(&amp;2, &amp;1))
Index.decryption_key(mixed)

Part Two

key = 811_589_153

keyed_list = Enum.map(list, fn {elem, index} -> {elem * key, index} end)
mixed =
  Enum.reduce(1..10, Index.new(keyed_list), fn _, index ->
    Enum.reduce(keyed_list, index, &amp;Index.move(&amp;2, &amp;1))
  end)
Index.decryption_key(mixed)