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

Day 8: Seven Segment Search

2021/day_08_seven_segment_search.livemd

Day 8: Seven Segment Search

Mix.install([:kino])

input = Kino.Input.textarea("Please paste your input:")

Part 1

inputs =
  input
  |> Kino.Input.read()
  |> String.split([" | ", "\n"], trim: true)
  |> Enum.map(fn patterns -> patterns |> String.split(" ") |> Enum.map(&String.graphemes/1) end)
  |> Enum.chunk_every(2)

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

Solve: Part 1

unique_sizes = [2, 3, 4, 7]

inputs
|> Enum.map(fn [_patterns, outputs] ->
  outputs |> Enum.count(&(Enum.count(&1) in unique_sizes))
end)
|> Enum.sum()

Part 2

https://adventofcode.com/2021/day/8#part2

Solve: Part 2

defmodule SevenSegment do
  def interpret(patterns) do
    {pattern_1, rest_patterns} = find_1(patterns)
    {pattern_4, rest_patterns} = find_4(rest_patterns)
    {pattern_7, rest_patterns} = find_7(rest_patterns)
    {pattern_8, rest_patterns} = find_8(rest_patterns)
    {pattern_3, rest_patterns} = find_3(rest_patterns, pattern_7)
    {pattern_9, rest_patterns} = find_9(rest_patterns, pattern_3)
    {pattern_0, rest_patterns} = find_0(rest_patterns, pattern_1)
    {pattern_6, rest_patterns} = find_6(rest_patterns)
    {pattern_5, [pattern_2]} = find_5(rest_patterns, pattern_6)

    [
      pattern_0,
      pattern_1,
      pattern_2,
      pattern_3,
      pattern_4,
      pattern_5,
      pattern_6,
      pattern_7,
      pattern_8,
      pattern_9
    ]
    |> Enum.with_index()
  end

  def translate_output(output, interpreted_patterns) do
    interpreted_patterns
    |> Enum.find_value(fn {interpreted_pattern, number} ->
      case equals?(interpreted_pattern, output) do
        true -> number
        _ -> nil
      end
    end)
  end

  defp find_1(patterns) do
    find_by_count(patterns, 2)
  end

  defp find_4(patterns) do
    find_by_count(patterns, 4)
  end

  defp find_7(patterns) do
    find_by_count(patterns, 3)
  end

  defp find_8(patterns) do
    find_by_count(patterns, 7)
  end

  defp find_3(patterns, pattern_7) do
    index = patterns |> Enum.find_index(&(Enum.count(&1) == 5 and contains?(&1, pattern_7)))
    List.pop_at(patterns, index)
  end

  defp find_9(patterns, pattern_3) do
    find_by_contains(patterns, pattern_3)
  end

  defp find_0(patterns, pattern_1) do
    find_by_contains(patterns, pattern_1)
  end

  defp find_6(patterns) do
    find_by_count(patterns, 6)
  end

  defp find_5(patterns, pattern_6) do
    index = patterns |> Enum.find_index(&contains?(pattern_6, &1))
    List.pop_at(patterns, index)
  end

  defp find_by_count(patterns, count) do
    index = patterns |> Enum.find_index(&(Enum.count(&1) == count))
    List.pop_at(patterns, index)
  end

  defp find_by_contains(patterns, contained_pattern) do
    index = patterns |> Enum.find_index(&contains?(&1, contained_pattern))
    List.pop_at(patterns, index)
  end

  defp contains?(a, b) do
    b -- a == []
  end

  defp equals?(a, b) do
    contains?(a, b) and contains?(b, a)
  end
end

_answer =
  inputs
  |> Enum.map(fn [patterns, outputs] ->
    interpreted_patterns = SevenSegment.interpret(patterns)

    outputs
    |> Enum.map(&SevenSegment.translate_output(&1, interpreted_patterns))
    |> Enum.reduce(0, fn x, acc ->
      acc * 10 + x
    end)
  end)
  |> Enum.sum()