DEV Community

Discussion on: AoC Day 3: No Matter How You Slice It

Collapse
 
yordiverkroost profile image
Yordi Verkroost • Edited

Solution in Elixir below.

It took me a while to figure out the best way to store the fabric because matrices are not really a thing in Elixir. And it's a bit harder for me (coming from an OOP background), as everything is immutable in a functional language like Elixir. A mindset switch is necessary sometimes.

Part one:


defmodule AoC.DayThree.PartOne do
  alias AoC.DayThree.Common

  def main() do
    "lib/day3/input.txt"
    |> Common.read_input()
    |> Common.parse_into_structs()
    |> Common.get_fabric()
    |> Enum.filter(fn {_key, value} -> value > 1 end)
    |> Enum.count()
  end
end

Part two:

defmodule AoC.DayThree.PartTwo do
  alias AoC.DayThree.Common

  def main() do
    claims =
      "lib/day3/input.txt"
      |> Common.read_input()
      |> Common.parse_into_structs()

    fabric = Common.get_fabric(claims)
    find_non_overlapping_claim(fabric, claims)
  end

  defp find_non_overlapping_claim(fabric, claims) do
    Enum.reduce_while(claims, false, fn claim, _ ->
      result_columns =
        Enum.reduce_while((claim.left + 1)..(claim.left + claim.columns), false, fn x, _ ->
          result_rows =
            Enum.reduce_while((claim.top + 1)..(claim.top + claim.rows), false, fn y, _ ->
              if Map.get(fabric, {x, y}) > 1, do: {:halt, false}, else: {:cont, true}
            end)

          if result_rows, do: {:cont, true}, else: {:halt, false}
        end)

      if result_columns, do: {:halt, claim.id}, else: {:cont, false}
    end)
  end
end

Common:

defmodule AoC.DayThree.Common do
  alias AoC.DayThree.Claim

  def read_input(path) do
    path
    |> File.stream!()
    |> Stream.map(&String.trim_trailing/1)
    |> Enum.to_list()
  end

  def get_fabric(claims) do
    Enum.reduce(claims, %{}, fn claim, map ->
      Enum.reduce((claim.left + 1)..(claim.left + claim.columns), map, fn x, acc_x ->
        Enum.reduce((claim.top + 1)..(claim.top + claim.rows), acc_x, fn y, acc_y ->
          Map.update(acc_y, {x, y}, 1, &(&1 + 1))
        end)
      end)
    end)
  end

  def parse_into_structs(input) do
    input
    |> Enum.map(&parse_struct/1)
  end

  defp parse_struct(input) do
    [id, rest] = String.split(input, "@")
    [location, dimension] = String.split(rest, ":")
    [left, top] = String.split(location, ",")
    [columns, rows] = String.split(dimension, "x")

    id =
      id
      |> String.trim("#")
      |> to_integer()

    left =
      left
      |> to_integer()

    top =
      top
      |> to_integer()

    columns =
      columns
      |> to_integer()

    rows =
      rows
      |> to_integer()

    %Claim{id: id, left: left, top: top, columns: columns, rows: rows}
  end

  defp to_integer(input) do
    input
    |> String.trim()
    |> String.to_integer()
  end
end
Collapse
 
rpalo profile image
Ryan Palo

Wow, nice! Elixir really does seem like a big brain shift.