Powered by AppSignal & Oban Pro

Aoc 2019 day 3

2019/elixir/day-3.livemd

Aoc 2019 day 3

Setup

Mix.install([{:kino, "~> 0.5.1"}])
input = Kino.Input.textarea("input")
[line1, line2] =
  input
  |> Kino.Input.read()
  |> String.split("\n", trim: true)
  |> Enum.map(&String.split(&1, ",", trim: true))

Part 1

list = [[1, 2, 3, 4], [10, 20, 30, 40]]

for i_list <- list,
    j <- i_list,
    i_list != [1, 2, 3, 4] do
end
defmodule Part1 do
  def mark_grid(line, grid, mark) do
    for path <- line, reduce: {grid, {0, 0}} do
      {grid, {x, y}} ->
        case path do
          "R" <> num ->
            num = String.to_integer(num)

            grid =
              1..num
              |> Enum.reduce(grid, &mark_one(&2, :x, {x, y}, mark, &1))

            {grid, {x + num, y}}

          "L" <> num ->
            num = String.to_integer(num)

            grid =
              1..num
              |> Enum.reduce(grid, &mark_one(&2, :x, {x, y}, mark, -&1))

            {grid, {x - num, y}}

          "U" <> num ->
            num = String.to_integer(num)

            grid =
              1..num
              |> Enum.reduce(grid, &mark_one(&2, :y, {x, y}, mark, &1))

            {grid, {x, y + num}}

          "D" <> num ->
            num = String.to_integer(num)

            grid =
              1..num
              |> Enum.reduce(grid, &mark_one(&2, :y, {x, y}, mark, -&1))

            {grid, {x, y - num}}
        end
    end
    |> elem(0)
  end

  defp mark_one(grid, :x, {x, y}, mark, n) do
    Map.update(grid, {x + n, y}, mark, fn v ->
      if v != mark, do: :intersect, else: mark
    end)
  end

  defp mark_one(grid, :y, {x, y}, mark, n) do
    Map.update(grid, {x, y + n}, mark, fn v ->
      if v != mark, do: :intersect, else: mark
    end)
  end
end
grid = Part1.mark_grid(line1, %{}, :mark1)
grid = Part1.mark_grid(line2, grid, :mark2)

grid
|> Enum.filter(fn {_, v} -> v == :intersect end)
|> Enum.map(fn {{x, y}, _} -> abs(x) + abs(y) end)
|> Enum.min()

Part 2

defmodule Part2 do
  def mark_grid(line, grid, mark) do
    for path <- line, reduce: {grid, {0, 0}, 0} do
      {grid, {x, y}, step} ->
        case path do
          "R" <> num ->
            num = String.to_integer(num)

            grid =
              1..num
              |> Enum.reduce(grid, &mark_one(&2, :x, {x, y}, mark, &1, step))

            {grid, {x + num, y}, step + num}

          "L" <> num ->
            num = String.to_integer(num)

            grid =
              1..num
              |> Enum.reduce(grid, &mark_one(&2, :x, {x, y}, mark, -&1, step))

            {grid, {x - num, y}, step + num}

          "U" <> num ->
            num = String.to_integer(num)

            grid =
              1..num
              |> Enum.reduce(grid, &mark_one(&2, :y, {x, y}, mark, &1, step))

            {grid, {x, y + num}, step + num}

          "D" <> num ->
            num = String.to_integer(num)

            grid =
              1..num
              |> Enum.reduce(grid, &mark_one(&2, :y, {x, y}, mark, -&1, step))

            {grid, {x, y - num}, step + num}
        end
    end
    |> elem(0)
  end

  defp mark_one(grid, :x, {x, y}, mark, n, step) do
    Map.update(grid, {x + n, y}, {mark, step + abs(n)}, fn {v, st} ->
      if v != mark and v != :intersect, do: {:intersect, st + step + abs(n)}, else: {v, st}
    end)
  end

  defp mark_one(grid, :y, {x, y}, mark, n, step) do
    Map.update(grid, {x, y + n}, {mark, step + abs(n)}, fn {v, st} ->
      if v != mark and v != :intersect, do: {:intersect, st + step + abs(n)}, else: {v, st}
    end)
  end
end
grid = Part2.mark_grid(line1, %{}, :mark1)
grid = Part2.mark_grid(line2, grid, :mark2)

grid
|> Enum.filter(fn {_, {v, step}} -> v == :intersect end)
|> Enum.map(fn {_, {v, step}} -> step end)
|> Enum.min()