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

Day 8

day8/index.livemd

Day 8

Setup

number_segments = %{
  0 => 6,
  1 => 2,
  2 => 5,
  3 => 5,
  4 => 4,
  5 => 5,
  6 => 6,
  7 => 3,
  8 => 7,
  9 => 6
}

# IO.inspect(segments: number_segments)
unique_segments =
  number_segments
  |> Enum.filter(fn {_, v} ->
    Enum.filter(number_segments, fn {_, v1} ->
      v1 == v
    end)
    |> Enum.count() == 1
  end)
  |> Enum.into(%{})

IO.inspect(unique_segments: unique_segments)

input =
  File.read!("aoc2021/day8/input.txt")
  |> String.trim("\n")
  |> String.split("\n")

signal_values =
  input
  |> Enum.map(fn row ->
    String.split(row, "|")
    |> then(fn val ->
      {String.trim(Enum.at(val, 0)), String.trim(Enum.at(val, 1))}
    end)
  end)

:ok
[unique_segments: %{1 => 2, 4 => 4, 7 => 3, 8 => 7}]
:ok

Part 1

Enum.map(signal_values, fn {_, value_string} ->
  String.split(value_string, " ")
  |> Enum.map(&String.length/1)
  |> Enum.filter(fn reading ->
    Enum.count(unique_segments, fn {_, val} ->
      reading == val
    end) > 0
  end)
  |> Enum.count()
end)
|> Enum.sum()
456

Part 2

# find 5, 2, 0 first
defmodule SevenSegDisplay do
  def find_unique_digit_patterns(all_values) do
    Enum.filter(all_values, fn value ->
      # 1
      # 4
      # 7
      # 8
      String.length(value) == 2 or
        String.length(value) == 4 or
        String.length(value) == 3 or
        String.length(value) == 7
    end)
    |> Enum.map(fn value ->
      case String.length(value) do
        2 -> {1, value}
        4 -> {4, value}
        3 -> {7, value}
        _ -> {8, value}
      end
    end)
    |> Enum.into(%{})
  end

  def find_wire_pattern(all_values) do
    digits_pattern = find_unique_digit_patterns(all_values)
    # we know they are 5 char len
    possible_2_3_5 =
      Enum.filter(all_values, fn value ->
        String.length(value) == 5
      end)

    # find 3 as it shares pattern with 1
    pattern_3 =
      Enum.filter(possible_2_3_5, fn pattern ->
        Enum.all?(String.graphemes(digits_pattern[1]), fn ch ->
          case :binary.match(pattern, to_string(ch)) do
            :nomatch -> false
            _ -> true
          end
        end)
      end)
      |> Enum.at(0)

    digits_pattern = Map.put_new(digits_pattern, 3, pattern_3)

    possible_0_6_9 =
      Enum.filter(all_values, fn pattern ->
        String.length(pattern) == 6
      end)

    # find 9 by comparing it to 3. 9 is 6 wires with all of them shared with 3
    pattern_9 =
      Enum.filter(possible_0_6_9, fn pattern ->
        Enum.all?(String.graphemes(pattern_3), fn ch ->
          case :binary.match(pattern, to_string(ch)) do
            :nomatch -> false
            _ -> true
          end
        end)
      end)
      |> Enum.at(0)

    digits_pattern = Map.put_new(digits_pattern, 9, pattern_9)

    # find 0 and 6 remainig
    possible_0_6 =
      Enum.filter(possible_0_6_9, fn pattern ->
        pattern != pattern_9
      end)

    # find 0 as it shares all the borders with 7.
    pattern_0 =
      Enum.filter(possible_0_6, fn pattern ->
        Enum.all?(String.graphemes(digits_pattern[7]), fn ch ->
          case :binary.match(pattern, to_string(ch)) do
            :nomatch -> false
            _ -> true
          end
        end)
      end)
      |> Enum.at(0)

    digits_pattern = Map.put_new(digits_pattern, 0, pattern_0)

    pattern_6 =
      Enum.filter(possible_0_6, fn pattern ->
        pattern != pattern_0
      end)
      |> Enum.at(0)

    digits_pattern = Map.put_new(digits_pattern, 6, pattern_6)

    # limit 2 and 5
    pattern_5 =
      Enum.filter(possible_2_3_5, fn pattern ->
        Enum.all?(String.graphemes(pattern), fn ch ->
          case :binary.match(digits_pattern[6], to_string(ch)) do
            :nomatch -> false
            _ -> true
          end
        end)
      end)
      |> Enum.at(0)

    digits_pattern = Map.put_new(digits_pattern, 5, pattern_5)

    # the remaining number is 2
    pattern_2 =
      Enum.filter(possible_2_3_5, fn pattern ->
        pattern != pattern_5 and pattern != pattern_3
      end)
      |> Enum.at(0)

    Map.put_new(digits_pattern, 2, pattern_2)
  end

  def clock_value(clock_wiring, display_patterns) do
    clock_val =
      Enum.flat_map(display_patterns, fn pattern ->
        Enum.filter(clock_wiring, fn {_, wire_pattern} ->
          wire_pattern ==
            Enum.sort(String.to_charlist(pattern))
            |> to_string()
        end)
      end)
      |> Enum.reduce("", fn item, acc ->
        {k, _} = item
        acc <> Integer.to_string(k)
      end)

    {ival, _} = Integer.parse(clock_val)
    ival
  end
end

Enum.map(signal_values, fn item ->
  {signal_value, readings} = item

  signal_value_sorted =
    String.split(signal_value, " ")
    |> Enum.map(fn value ->
      to_string(Enum.sort(to_charlist(value)))
    end)

  clock_wiring = SevenSegDisplay.find_wire_pattern(signal_value_sorted)

  reading_value_sorted =
    String.split(readings, " ")
    |> Enum.map(fn value ->
      to_string(Enum.sort(to_charlist(value)))
    end)

  SevenSegDisplay.clock_value(clock_wiring, reading_value_sorted)
end)
|> Enum.sum()
1091609