Advent of Code 2023 - Day 16

Hey, coding wizards! Ukrainian Erlanger checking in on this splendid Saturday :metal:. It’s Day 16 in our captivating exploration of Advent of Code, and a fresh puzzle beckons your coding ingenuity. Dive into the challenge, conquer the complexities, and, as always, share your brilliant solutions in the comments below. Let’s make this Saturday a coding triumph and keep the collaborative spirit alive! Happy coding, everyone! :blush:

2 Likes
2 Likes

My day 16 solution:

defmodule Aoc.Sixteen do
  def parse(string) do
    string
    |> String.split("\n", trim: true)
    |> Enum.map(fn line ->
      line
      |> String.graphemes()
    end)
    |> load()
  end

  def load(data) do
    for {line, y} <- Enum.with_index(data, 1), {i, x} <- Enum.with_index(line, 1), into: %{} do
      {{x, y}, i}
    end
  end

  def part_one(input) do
    input
    |> walk({{0, 1}, :r})
  end

  def part_two(input) do
    {max_x, max_y} = input |> Map.keys() |> Enum.max()

    vert = for x <- 1..100, do: [{{x, 0}, :d}, {{x, max_x}, :u}]
    horz = for y <- 1..100, do: [{{0, y}, :r}, {{max_y, y}, :l}]

    (vert ++ horz)
    |> Enum.concat()
    |> Enum.map(&walk(input, &1))
    |> Enum.max()
  end

  defp walk(map, start) do
    start
    |> next_directions(map)
    |> walk(map, MapSet.new())
  end

  defp walk([], _map, seen) do
    seen |> Enum.unzip() |> elem(0) |> Enum.uniq() |> Enum.count()
  end

  defp walk([next | rest], map, seen) do
    {new_seen, new_directions} =
      if MapSet.member?(seen, next) do
        {seen, rest}
      else
        new_seen = MapSet.put(seen, next)
        {new_seen, next_directions(next, map) ++ rest}
      end
    walk(new_directions, map, new_seen)
  end

  defp next_directions({{x, y}, dir}, map) do
    nc =
      case dir do
        :u -> {x, y - 1}
        :d -> {x, y + 1}
        :l -> {x - 1, y}
        :r -> {x + 1, y}
      end

    case Map.get(map, nc) do
      nil ->
        []

      "." ->
        [{nc, dir}]

      "/" ->
        case dir do
          :u -> [{nc, :r}]
          :d -> [{nc, :l}]
          :l -> [{nc, :d}]
          :r -> [{nc, :u}]
        end

      "\\" ->
        case dir do
          :u -> [{nc, :l}]
          :d -> [{nc, :r}]
          :l -> [{nc, :u}]
          :r -> [{nc, :d}]
        end

      "|" ->
        case dir do
          :u -> [{nc, :u}]
          :d -> [{nc, :d}]
          :l -> [{nc, :u}, {nc, :d}]
          :r -> [{nc, :u}, {nc, :d}]
        end

      "-" ->
        case dir do
          :u -> [{nc, :l}, {nc, :r}]
          :d -> [{nc, :l}, {nc, :r}]
          :l -> [{nc, :l}]
          :r -> [{nc, :r}]
        end
    end
  end
end

input = File.read!("priv/16.txt") |> Aoc.Sixteen.parse()

input |> Aoc.Sixteen.part_one() |> IO.inspect(label: "part 1")
input |> Aoc.Sixteen.part_two() |> IO.inspect(label: "part 2")
1 Like