Advent of Code 2023 - Day 10

Hey there, amazing community! Ukrainian Erlanger is here :metal:, and it’s a beautiful Sunday. Today unfolds as Day 10 in the exhilarating adventure of Advent of Code, bringing with it a brand-new puzzle to unravel. As you embark on this coding escapade, feel free to share your ingenious solutions in the comments below. Let’s celebrate the spirit of learning and collaboration. Wishing you all a relaxing Sunday filled with coding delights. Happy coding, folks! :blush:

3 Likes

I had to take a hint for part 2.

2 Likes

My day 10 solution, definitely spent too much time on that one, I’m sure there are much more elegant solutions:

defmodule Aoc.Ten do
  def parse(string) do
    string
    |> String.split("\n", trim: true)
    |> Enum.map(&String.to_charlist/1)
    |> load()
  end

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

  def part_one(map) do
    map
    |> walk_loop()
    |> Map.values()
    |> Enum.max()
  end

  def part_two(map) do
    loop =
      map
      |> walk_loop()
      |> Map.keys()
      |> MapSet.new()

    map
    |> inside_loop(loop)
    |> Enum.count()
  end

  def walk_loop(map) do
    map
    |> Enum.find(map, fn {_, v} -> v == ?S end)
    |> walk_loop(map)
  end

  def walk_loop({c, _}, map) do
    walk_loop([c], map, 1, %{c => 0})
  end

  def walk_loop([], _, _, seen), do: seen

  def walk_loop(coords, map, n, seen) do
    directions =
      for c <- coords,
          {dir, x} <- around(c),
          Map.has_key?(map, x),
          not Map.has_key?(seen, x),
          is_connected(map[c], {dir, x}, map) do
        x
      end

    new_seen = Enum.reduce(directions, seen, fn x, acc -> Map.put(acc, x, n) end)
    walk_loop(directions, map, n + 1, new_seen)
  end

  @nav %{
    up: ~c"S|7F",
    down: ~c"S|LJ",
    left: ~c"S-LF",
    right: ~c"S-7J"
  }

  @dirs %{
    ?| => [:up, :down],
    ?- => [:left, :right],
    ?L => [:up, :right],
    ?J => [:up, :left],
    ?7 => [:down, :left],
    ?F => [:down, :right],
    ?S => [:up, :down, :left, :right]
  }

  def is_connected(v0, {dir, c}, map) do
    v = Map.get(map, c)
    Enum.any?(@dirs[v0], fn d -> d == dir and v in @nav[dir] end)
  end

  def around({y, x}) do
    [{:up, {y - 1, x}}, {:down, {y + 1, x}}, {:left, {y, x - 1}}, {:right, {y, x + 1}}]
  end

  def inside_loop(map, loop) do
    {ys, xs} = map |> Map.keys() |> Enum.max()

    for y <- 0..ys, x <- 0..xs, {y, x} not in loop, is_inside_loop({y, x}, map, loop) do
      {y, x}
    end
  end

  def is_inside_loop({y, x}, map, loop) do
    Enum.reduce((y - 1)..0, false, fn y, acc ->
      if {y, x} in loop and map[{y, x}] in ~c"-LF" do
        not acc
      else
        acc
      end
    end)
  end
end

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

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

1 Like