DEV Community

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

Collapse
 
niorad profile image
Antonio Radovcic • Edited

My solution (Elixir) for the first part was:

  • Make a list of every data-point's coords and size [((x,y), (w,h)), ...]
  • Transform each entry to a list of coords (all coords of this rect) [(x,y), ...], so now I have a list of lists with w * h coordinate-pairs
  • Concatenate all lists into one, so now I have a huge list of every occupied field.
  • Count every coordinate in a map, %{(x,y) => count, (x,y) => count, ...}
  • Throw out every entry where count < 2
  • Count entries in resulting list

Takes about a second. The first version used lists and list-diffing to find duplicates, but this took minutes to compute. Maps were much faster at this size (hundeds of thousands of entries).

I should mention I'm just learning Elixir, so this is not to be understood as "good code" or "knows what he's doing".

Here's the code:

defmodule Ac3 do
  def doit do
    filly =
      getFilledList()
      |> Enum.reduce(%{}, &count/2)

    :maps.filter(fn _, v -> v != 0 end, filly)
    |> Enum.reduce(0, fn i, acc -> acc + 1 end)
    |> IO.inspect()
  end

  def count(item, acc) do
    acc
    |> Map.update(item, 0, &(&1 + 1))
  end

  def getFilledList() do
    File.stream!("input.txt")
    |> Enum.to_list()
    |> Enum.map(&String.trim_trailing/1)
    |> Enum.map(&parse/1)
    |> Enum.map(&to_coords/1)
    |> Enum.reduce([], fn i, acc -> i ++ acc end)
  end

  def to_coords(unit) do
    x = elem(elem(unit, 0), 0)
    y = elem(elem(unit, 0), 1)
    x2 = x + elem(elem(unit, 1), 0) - 1
    y2 = y + elem(elem(unit, 1), 1) - 1
    fill(x, y, x, y, x2, y2)
  end

  def fill(x, y, _x1, _y1, x2, y2) when x === x2 and y === y2 do
    [{x, y}]
  end

  def fill(x, y, x1, y1, x2, y2) when x < x2 do
    [{x, y} | fill(x + 1, y, x1, y1, x2, y2)]
  end

  def fill(x, y, x1, y1, x2, y2) when x === x2 do
    [{x, y} | fill(x1, y + 1, x1, y1, x2, y2)]
  end

  def parse(str) do
    {
      unwrap(Enum.at(split(str), 3)),
      unwrap(Enum.at(split(str), 5))
    }
  end

  def split(str) do
    String.split(str, [" ", ":", "#"])
  end

  def unwrap(str) do
    {
      str
      |> String.split([",", "x"])
      |> Enum.at(0)
      |> String.to_integer(),
      str
      |> String.split([",", "x"])
      |> Enum.at(1)
      |> String.to_integer()
    }
  end
end

Ac3.doit()

Collapse
 
rpalo profile image
Ryan Palo

Cool! Thanks for sharing!

Just a heads up, you can put the word β€œelixir” immediately after the opening triple backtick, and your code will show up with syntax highlighting. 😁