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

Day 8: Seven Segment Search

2021/elixir/day-08.livemd

Day 8: Seven Segment Search

Setup

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

Input

input = Kino.Input.textarea("Input")

Part 1

Kino.Input.read(input)
|> String.split("\n", trim: true)
|> Enum.map(fn line ->
  line
  |> String.split("|")
  |> List.to_tuple()
  |> elem(1)
  |> String.split(" ", trim: true)
  |> Enum.map(&String.length(&1))
  |> Enum.filter(&Enum.member?([2, 4, 3, 7], &1))
  |> Enum.count()
end)
|> Enum.sum()

Part 2

defmodule M do
  @digits %{
    'bc' => 1,
    'abdeg' => 2,
    'abcdg' => 3,
    'bcfg' => 4,
    'acdfg' => 5,
    'acdefg' => 6,
    'abc' => 7,
    'abcdefg' => 8,
    'abcdfg' => 9,
    'abcdef' => 0
  }

  def find(l, len) do
    Enum.filter(l, fn s -> length(s) == len end)
    |> Enum.at(0)
  end

  def interpret(l, s) do
    ?a..?g
    |> Enum.map(fn x ->
      {apply(M, String.to_atom(<>), [l]), String.to_charlist(<>)}
    end)
    |> Map.new()
    |> then(&amp;Enum.map(s, fn c -> Map.get(&amp;1, [c]) end))
    |> Enum.sort()
    |> Enum.join()
    |> String.to_charlist()
    |> then(&amp;Map.get(@digits, &amp;1))
  end

  def a(l) do
    # 7 - 1 => A
    [find(l, 3), find(l, 2)]
    |> Enum.map(&amp;MapSet.new/1)
    |> then(fn [x, y] -> MapSet.difference(x, y) end)
    |> MapSet.to_list()
  end

  def d(l) do
    # A + 4 =>  9 => D
    find(l, 4)
    |> Kernel.++(a(l))
    |> then(fn x ->
      Enum.filter(l, fn e ->
        e != find(l, 7) and MapSet.subset?(MapSet.new(x), MapSet.new(e))
      end)
      |> Enum.at(0)
      |> MapSet.new()
      |> MapSet.difference(MapSet.new(x))
      |> MapSet.to_list()
    end)
  end

  def g(l) do
    # 5 & 2 & 3 - A - D = G
    Enum.filter(l, fn s -> length(s) == 5 end)
    |> Enum.map(&amp;MapSet.new/1)
    |> Enum.reduce(&amp;MapSet.intersection/2)
    |> MapSet.to_list()
    |> Kernel.--(a(l))
    |> Kernel.--(d(l))
  end

  def e(l) do
    # 8 - 4 - A - D => E
    find(l, 7) -- (find(l, 4) ++ a(l) ++ d(l))
  end

  def f(l) do
    # 4 - 1 - G = F
    (find(l, 4) -- find(l, 2)) -- g(l)
  end

  def c(l) do
    # 0 & 6 & 9 - A - F - D = C
    Enum.filter(l, fn s -> length(s) == 6 end)
    |> Enum.map(&amp;MapSet.new/1)
    |> Enum.reduce(&amp;MapSet.intersection/2)
    |> Enum.to_list()
    |> Kernel.--(a(l))
    |> Kernel.--(f(l))
    |> Kernel.--(d(l))
  end

  def b(l) do
    # 1 - C = B
    find(l, 2)
    |> Kernel.--(c(l))
  end
end

Kino.Input.read(input)
|> String.split("\n", trim: true)
|> Enum.map(fn line ->
  line
  |> String.split("|")
  |> Enum.map(
    &amp;(String.split(&amp;1, " ", trim: true)
      |> Enum.map(fn r -> String.to_charlist(r) end))
  )
  |> then(fn [l, r] ->
    Enum.map(r, &amp;M.interpret(l, &amp;1)) |> Enum.join() |> String.to_integer()
  end)
end)
|> Enum.sum()