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

Day 6

06.livemd

Day 6

Section

example = """
....#.....
.........#
..........
..#.......
.......#..
..........
.#..^.....
........#.
#.........
......#...
"""
defmodule Day06 do
  def part1(input) do
    {start, map} = parse_input(input)

    move(start, map, {0, -1}, [start])
    |> Enum.uniq()
    |> length()
  end

  def move(_, _map, :out, breads), do: breads
  def move({x, y}, map, {xmove, ymove} = dir, breads) do
    next = {x + xmove, y + ymove}

    {next, dir, breads} =
      case Map.get(map, next) do
        "." -> {next, dir, [next | breads]}
        "#" -> {{x, y}, next_dir(dir), breads}
        nil -> {next, :out, breads}
      end

    move(next, map, dir, breads)
  end

  def parse_input(input) do
    for {row, y} <- input |> String.split("\n", trim: true) |> Enum.with_index(),
        {dot, x} <- row |> String.split("", trim: true) |> Enum.with_index(),
        reduce: {nil, %{}} do
      {start, map} ->
        case dot do
          "^" -> {{x, y}, Map.put(map, {x, y}, ".")}
          dot -> {start, Map.put(map, {x, y}, dot)}
        end
    end
  end

  def next_dir({0, -1}), do: {1, 0}
  def next_dir({1, 0}), do: {0, 1}
  def next_dir({0, 1}), do: {-1, 0}
  def next_dir({-1, 0}), do: {0, -1}
end

Day06.part1(example)
defmodule Day06P2 do
  def part2(input) do
    {start, map} = parse_input(input)

    for {position, "."} <- map,
        position != start,
        :loop == move(start, Map.put(map, position, "#"), {0, -1}, %{}),
        reduce: 0 do
      accu -> accu + 1
    end
  end

  def move(_, _map, _, :loop), do: :loop
  def move(_, _map, :out, _), do: :out

  def move({x, y}, map, {xmove, ymove} = dir, turns) do
    next = {x + xmove, y + ymove}

    {next, dir, turns} =
      case Map.get(map, next) do
        "." -> {next, dir, turns}
        "#" -> {{x, y}, next_dir(dir), check_turn(turns, {{x, y}, dir, next_dir(dir)})}
        nil -> {next, :out, turns}
      end

    move(next, map, dir, turns)
  end

  def parse_input(input) do
    for {row, y} <- input |> String.split("\n", trim: true) |> Enum.with_index(),
        {dot, x} <- row |> String.split("", trim: true) |> Enum.with_index(),
        reduce: {nil, %{}} do
      {start, map} ->
        case dot do
          "^" -> {{x, y}, Map.put(map, {x, y}, ".")}
          dot -> {start, Map.put(map, {x, y}, dot)}
        end
    end
  end

  def next_dir({0, -1}), do: {1, 0}
  def next_dir({1, 0}), do: {0, 1}
  def next_dir({0, 1}), do: {-1, 0}
  def next_dir({-1, 0}), do: {0, -1}

  def check_turn(turns, turn) do
    if Map.has_key?(turns, turn) do
      :loop
    else
      Map.put(turns, turn, true)
    end
  end
end

Day06P2.part2(example)