Powered by AppSignal & Oban Pro

Advent of Code 2021 - Day 5

advent-of-code/2021/day05.livemd

Advent of Code 2021 - Day 5

Mix.install([
  {:kino, "~> 0.6.1"}
])

Instructions

https://adventofcode.com/2021/day/5

Test Input

test_input = """
0,9 -> 5,9
8,0 -> 0,8
9,4 -> 3,4
2,2 -> 2,1
7,0 -> 7,4
6,4 -> 2,0
0,9 -> 2,9
3,4 -> 1,4
0,0 -> 8,8
5,5 -> 8,2
"""

Puzzle Input

Paste your own input from Advent of Code or copy from sdball 2021 Advent of Code Day 5 input

puzzle_input = Kino.Input.textarea("Please paste your Day 5 puzzle input:")
puzzle_input = puzzle_input |> Kino.Input.read()

Input Parser Module

defmodule Day5.InputParser do
  def parse(text) do
    text
    |> String.split()
    |> Enum.chunk_every(3)
    |> Enum.map(fn [xy1, _, xy2] ->
      {
        String.split(xy1, ",") |> Enum.map(&String.to_integer/1) |> List.to_tuple(),
        String.split(xy2, ",") |> Enum.map(&String.to_integer/1) |> List.to_tuple()
      }
    end)
  end
end

Vent Scanner Module

defmodule VentScanner do
  def only_perpendicular(scan) do
    scan
    |> Enum.filter(fn {{start_x, start_y}, {end_x, end_y}} ->
      start_x == end_x or start_y == end_y
    end)
  end

  def count_intersections(scan) do
    scan
    |> vent_points()
    |> List.flatten()
    |> Enum.frequencies()
    |> Enum.filter(fn {_point, count} ->
      count >= 2
    end)
    |> Enum.count()
  end

  def vent_points(scan) do
    scan
    |> Enum.map(fn vent = {{start_x, start_y}, {end_x, end_y}} ->
      cond do
        start_x == end_x ->
          straight(vent)

        start_y == end_y ->
          straight(vent)

        true ->
          diagonal(vent)
      end
    end)
  end

  def straight({{start_x, start_y}, {end_x, end_y}}) do
    for x <- start_x..end_x,
        y <- start_y..end_y do
      {x, y}
    end
  end

  def diagonal({{start_x, start_y}, {end_x, end_y}}) do
    Enum.zip(start_x..end_x, start_y..end_y)
  end
end

Part 1

scan =
  test_input
  |> Day5.InputParser.parse()
  |> VentScanner.only_perpendicular()
  |> VentScanner.count_intersections()
scan =
  puzzle_input
  |> Day5.InputParser.parse()
  |> VentScanner.only_perpendicular()
  |> VentScanner.count_intersections()

Part 2

scan =
  test_input
  |> Day5.InputParser.parse()
  |> VentScanner.count_intersections()
scan =
  puzzle_input
  |> Day5.InputParser.parse()
  |> VentScanner.count_intersections()