Powered by AppSignal & Oban Pro

Untitled notebook

2025/day7/day7.livemd

Untitled notebook

Section

Mix.install([
  {:kino, "~> 0.14.2"}
])
input = Kino.Input.textarea("Please paste your input file")
defmodule Griddy do
  def enum_to_map(enum) do
    Stream.iterate(0, &(&1 + 1)) |> Enum.zip(enum) |> Map.new()
  end

  def new_from_string(string) do
    Griddy.enum_to_map(
      string
      |> String.split("\n")
      |> Enum.map(&String.graphemes/1)
      |> Enum.map(&Griddy.enum_to_map/1)
    )
  end

  def reduce(grid, initial, func) do
    grid
    |> Enum.reduce(initial, fn {y, sub_map}, acc ->
      sub_map
      |> Enum.reduce(acc, fn {x, value}, acc ->
        func.(value, acc, x, y)
      end)
    end)
  end

  def map(grid, func) do
  grid
  |> Enum.map(fn {y, sub_map} ->
    new_sub_map =
      sub_map
      |> Enum.map(fn {x, value} ->
        {x, func.(value, x, y)}
      end)
      |> Map.new()

    {y, new_sub_map}
  end)
  |> Map.new()
end


  def get_nearby_cells(grid, x, y) do
    above_below_range = -1..1//1

    above_below_range
    |> Enum.map(fn dy ->
      -1..1//1
      |> Enum.map(fn dx ->
        if dx == 0 && dy == 0 do
          nil
        else
          grid |> Griddy.get(x + dx, y + dy)
        end
      end)
    end)
    |> Enum.flat_map(fn a -> a end)
    |> Enum.filter(fn a -> a end)
  end

  def get(grid, x, y) do
    grid[y][x]
  end

  def put(grid, x, y, value) do
    grid |> Map.update(y, nil, fn sub_map -> sub_map |> Map.put(x, value) end)
  end

  def update(grid, x, y, default, func) do
    grid |> Map.update(y, nil, fn sub_map -> sub_map |> Map.update(x, default, func) end)
  end

  def find(map, value) do
    map
    |> Enum.reduce({0, 0}, fn {y, sub_map}, acc ->
      sub_map
      |> Enum.reduce(acc, fn {x, _}, acc ->
        if map[y][x] == value, do: {x, y}, else: acc
      end)
    end)
  end

  def to_string(grid) do
    {string, _} =
      grid
      |> Griddy.reduce({"", nil}, fn value, {acc, prev_y}, _, y ->
        if y != prev_y do
          {acc <> "\n" <> value, y}
        else
          {acc <> value, y}
        end
      end)

    string
  end

  def print(grid) do
    grid |> Griddy.to_string() |> IO.puts()

    grid
  end
end
defmodule Main do
  def handle_split(grid, x, y, just_split) do
    value = grid |> Griddy.get(x, y)

    case value do
      nil ->
        [0, grid]

      "." ->
        update_grid = grid |> Griddy.put(x, y, "|")

        if just_split do
          [value, final_grid] = Main.handle_split(update_grid, x, y + 1, false)
          [value, final_grid]
        else
          Main.handle_split(update_grid, x, y + 1, false)
        end

      "^" ->
        [first_split, update_grid] = Main.handle_split(grid, x + 1, y, true)
        [second_split, final_grid] = Main.handle_split(update_grid, x - 1, y, true)
        [first_split + second_split + 1, final_grid]

      "|" ->
        [0, grid]
    end
  end
end
grid =
  input
  |> Kino.Input.read()
  |> String.split("\n", trim: true)
  |> Enum.map(&amp;String.trim/1)
  |> Enum.join("\n")
  |> Griddy.new_from_string()

{s_x, s_y} = grid |> Griddy.find("S")

[answer, grid] = Main.handle_split(grid, s_x, s_y + 1, false)
answer
defmodule Test do
  def handle_quantum_split(grid, x, y, just_split) do
    {value, _memo} = do_split(grid, x, y, just_split, %{})
    value
  end

  defp do_split(grid, x, y, just_split, memo) do
    key = {x, y, just_split}

    case memo do
      %{^key => count} ->
        {count, memo}

      _ ->
        value = Griddy.get(grid, x, y)

        {count, memo} =
          case value do
            nil ->
              {1, memo}

            "." ->
              if just_split do
                do_split(grid, x, y + 1, false, memo)
              else
                do_split(grid, x, y + 1, false, memo)
              end

            "^" ->
              {v1, memo} = do_split(grid, x + 1, y, true, memo)
              {v2, memo} = do_split(grid, x - 1, y, true, memo)
              {v1 + v2, memo}

            "|" ->
              do_split(grid, x, y + 1, false, memo)
          end

        memo = Map.put(memo, key, count)
        {count, memo}
    end
  end
end
grid =
  input
  |> Kino.Input.read()
  |> String.split("\n", trim: true)
  |> Enum.map(&amp;String.trim/1)
  |> Enum.join("\n")
  |> Griddy.new_from_string()

{s_x, s_y} = grid |> Griddy.find("S")

Test.handle_quantum_split(grid, s_x, s_y + 1, false)