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

Day 15

live/day15.livemd

Day 15

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

Input

input = Kino.Input.textarea("In put here:")
grid =
  for {line, row} <-
        input |> Kino.Input.read() |> String.split("\n", strip: true) |> Enum.with_index(),
      {val, col} <- String.to_charlist(line) |> Enum.with_index(),
      into: %{} do
    {{row, col}, val - ?0}
  end
defmodule PQ do
  def new() do
    []
  end

  def add([{cur_weight, _} | _] = list, value, weight)
      when weight <= cur_weight,
      do: [{weight, value} | list]

  def add([head | tail], value, weight),
    do: [head | add(tail, value, weight)]

  def add([], value, weight),
    do: [{weight, value}]
end

defmodule Lab do
  def in_grid({x, y}, {maxx, maxy}, n),
    do:
      x < n * (maxx + 1) and x >= 0 and
        y < n * (maxy + 1) and y >= 0

  def score_at(map, {x, y}, {maxx, maxy}) do
    nx = rem(x, maxx + 1)
    ny = rem(y, maxy + 1)

    rem(
      Map.get(map, {nx, ny}) - 1 + Integer.floor_div(x, maxx + 1) +
        Integer.floor_div(y, maxy + 1),
      9
    ) + 1
  end

  def neighbors({x, y}, n, {maxx, maxy}) do
    [{1, 0}, {0, 1}, {0, -1}, {-1, 0}]
    |> Enum.map(fn {dx, dy} ->
      x = x + dx
      y = y + dy

      if(in_grid({x, y}, {maxx, maxy}, n),
        do: {x, y},
        else: nil
      )
    end)
    |> Enum.filter(&amp; &amp;1)
  end

  def search(map, n) do
    distances = %{{0, 0} => 0}
    queue = PQ.add(PQ.new(), {0, 0}, 0)
    {maxx, maxy} = Map.keys(map) |> Enum.max() |> IO.inspect(label: "maxx, maxy")

    {targx, targy} = {n * (maxx + 1) - 1, n * (maxy + 1) - 1} |> IO.inspect(label: "target")
    search(map, distances, queue, {targx, targy}, n, {maxx, maxy})
  end

  def search(
        map,
        distances,
        queue,
        goal,
        n,
        {maxx, maxy}
      ) do
    [{_, u} | queue] = queue

    if u == goal do
      {:found, u, Map.get(distances, u)}
    else
      {distances, queue} =
        for v <- neighbors(u, n, {maxx, maxy}),
            in_grid(v, {maxx, maxy}, n),
            dist_from_source = distances[u] + score_at(map, v, {maxx, maxy}),
            dist_from_source < Map.get(distances, v, :infinity),
            reduce: {distances, queue} do
          {distances, queue} ->
            distances = Map.put(distances, v, dist_from_source)
            queue = PQ.add(queue, v, dist_from_source)
            {distances, queue}
        end

      search(map, distances, queue, goal, n, {maxx, maxy})
    end
  end
end
Lab.score_at(grid, {9, 8}, {9, 9})

Part 1

Lab.search(grid, 1)

Part 2

Lab.search(grid, 5)