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

Day 5

day5/index.livemd

Day 5

Structs

defmodule Coord do
  defstruct x: 0, y: 0
end

defmodule VentLine do
  defstruct start: %Coord{x: 0, y: 0}, endc: %Coord{x: 0, y: 0}
end

Setup

input_1 =
  File.read!("day5/input.txt")
  |> String.replace(" ", "")
  |> String.trim("\n")
  |> String.split("\n")
  |> Enum.map(fn data ->
    String.split(data, "->")
  end)
  |> Enum.map(fn row ->
    Enum.map(row, fn item ->
      Enum.map(String.split(item, ","), fn num ->
        {x, _} = Integer.parse(num)
        x
      end)
    end)
  end)

input =
  input_1
  |> Enum.map(fn row ->
    [start | [endc]] = row

    %VentLine{
      start: %Coord{x: Enum.at(start, 0), y: Enum.at(start, 1)},
      endc: %{x: Enum.at(endc, 0), y: Enum.at(endc, 1)}
    }
  end)

grid_size =
  List.flatten(input_1)
  |> Enum.max()

# Create the grid.
grid =
  for _ <- 0..grid_size do
    for _ <- 0..grid_size do
      0
    end
  end

:ok

Part 1

defmodule VentMap do
  def mark_coords([start | tail], grid) do
    new_grid =
      List.update_at(grid, start.y, fn row ->
        List.update_at(row, start.x, &amp;(&amp;1 + 1))
      end)

    mark_coords(tail, new_grid)
  end

  def mark_coords([], grid) do
    grid
  end

  def vector_to_line(%VentLine{} = vent_line) do
    if vent_line.start.x != vent_line.endc.x do
      for x <- vent_line.start.x..vent_line.endc.x do
        %Coord{x: x, y: vent_line.start.y}
      end
    else
      for y <- vent_line.start.y..vent_line.endc.y do
        %Coord{x: vent_line.start.x, y: y}
      end
    end
  end

  def vector_to_diagonal(%VentLine{} = vent_line) do
    x_coords =
      for x <- vent_line.start.x..vent_line.endc.x do
        x
      end

    y_coords =
      for y <- vent_line.start.y..vent_line.endc.y do
        y
      end

    Enum.zip_with([x_coords, y_coords], fn [x, y] ->
      %Coord{x: x, y: y}
    end)
  end

  def create_map(coords, grid) when is_list(coords) do
    Enum.reduce(coords, grid, fn coord, gridacc ->
      VentMap.mark_coords(coord, gridacc)
    end)
  end

  def count_marks(grid, min) do
    grid
    |> Enum.reduce(0, fn row, acc ->
      Enum.reduce(row, acc, fn item, acc1 ->
        case item > min do
          true -> acc1 + 1
          _ -> acc1
        end
      end)
    end)
  end
end

# Filter input to horizontal/vertical lines
hor_ver_input =
  input
  |> Enum.filter(fn coord ->
    coord.start.x == coord.endc.x or coord.start.y == coord.endc.y
  end)

coords =
  hor_ver_input
  |> Enum.map(fn coord ->
    VentMap.vector_to_line(coord)
  end)

part1 =
  coords
  |> VentMap.create_map(grid)
  |> VentMap.count_marks(1)

Part 2

# Part 2
diagonal_input =
  input
  |> Enum.filter(fn coord ->
    abs(coord.start.x - coord.endc.x) == abs(coord.endc.y - coord.start.y)
  end)

coords_diag =
  diagonal_input
  |> Enum.map(fn coord ->
    VentMap.vector_to_diagonal(coord)
  end)

all_coords = coords_diag ++ coords

part2 =
  all_coords
  |> VentMap.create_map(grid)
  |> VentMap.count_marks(1)