rugyoga

rugyoga

Advent of Code 2021 - Day 8

part 1:

part 2:

Most Liked

hauleth

hauleth

Thanks @josevalim for custom operators. Again - LiveBook:


Day 8

input =
  File.stream!("day8.txt")
  |> Stream.map(fn line ->
    line
    |> String.split(" | ")
    |> Enum.map(fn part ->
      part
      |> String.trim()
      |> String.split(" ")
      |> Enum.map(fn disp ->
        disp
        |> String.to_charlist()
        |> Enum.sort()
        |> List.to_string()
      end)
    end)
    |> List.to_tuple()
  end)
#Stream<[
  enum: %File.Stream{
    line_or_bytes: :line,
    modes: [:raw, :read_ahead, :binary],
    path: "day8.txt",
    raw: true
  },
  funs: [#Function<47.58486609/1 in Stream.map/2>]
]>
input
|> Enum.map(fn {_, output} ->
  Enum.count(output, &(byte_size(&1) in [2, 3, 4, 7]))
end)
|> Enum.sum()
390
defmodule Day8.Task2 do
  def a --- b do
    MapSet.difference(a, b)
  end

  def a +++ b do
    MapSet.union(a, b)
  end

  def a <~> b do
    MapSet.intersection(a, b)
  end

  def a <|> b do
    (a +++ b) --- (a <~> b)
  end

  #            1.   7.    4. 2|3|5. 2|3|5. 2|3|5.  6|9|0.  6|9|0.  6|9|0.       8.
  def deduce({cf, acf, bcdf, acdeg, acdfg, abdfg, abdefg, abcdfg, abcefg, abcdefg}) do
    a = acf --- cf
    eg = abcdefg --- (acf +++ bcdf)
    bd = bcdf --- cf
    abfg = abdefg <|> abcdfg <|> abcefg
    b = abfg <~> bd
    f = abfg <~> cf
    g = abfg --- (a +++ b +++ f)
    d = bd --- b
    c = cf --- f
    e = eg --- g

    {a, b, c, d, e, f, g} =
      [a, b, c, d, e, f, g]
      |> Enum.map(&extract/1)
      |> List.to_tuple()

    [
      # 0
      [a, b, c, e, f, g],
      # 1
      [c, f],
      # 2
      [a, c, d, e, g],
      # 3
      [a, c, d, f, g],
      # 4
      [b, c, d, f],
      # 5
      [a, b, d, f, g],
      # 6
      [a, b, d, e, f, g],
      # 7
      [a, c, f],
      # 8
      [a, b, c, d, e, f, g],
      # 9
      [a, b, c, d, f, g]
    ]
    |> Enum.map(&List.to_string(Enum.sort(&1)))
    |> Enum.with_index()
    |> Map.new()
  end

  defp extract(a) do
    [v] = MapSet.to_list(a)

    v
  end

  def decode(matches, output) do
    output
    |> Enum.map(&matches[&1])
    |> Integer.undigits()
  end
end

input
|> Enum.map(fn {input, output} ->
  input
  |> Enum.sort_by(&byte_size/1)
  |> Enum.map(&MapSet.new(String.to_charlist(&1)))
  |> List.to_tuple()
  |> Day8.Task2.deduce()
  |> Day8.Task2.decode(output)
end)
|> Enum.sum()
warning: variable "abdfg" is unused (if the variable is not meant to be used, prefix it with an underscore)
  solutions.livemd#cell:19: Day8.Task2.deduce/1

warning: variable "acdeg" is unused (if the variable is not meant to be used, prefix it with an underscore)
  solutions.livemd#cell:19: Day8.Task2.deduce/1

warning: variable "acdfg" is unused (if the variable is not meant to be used, prefix it with an underscore)
  solutions.livemd#cell:19: Day8.Task2.deduce/1

1011785
mruoss

mruoss

Second part approach:

  • Get the correct mapping from segments to digit
    • 1, 4, 7 and 8 are unique by the number of segments
    • 6, 9, 0 all have 6 segments
      • derive 9 which is the only one that fully contains 4
      • derive 0 which is the only one that fully contains 7
      • 6 is the remainder of the 6-segment digits
    • 2, 3, 5 all have 5 segments
      • derive 3 which is the only one that fully contains 7
      • derive 5 which is the only one fully contained in 6
      • 2 is the remainder of the 5-segment digits
  def solve(stream, :second) do
    stream
    |> parse() # returns a tuple {patterns, output}, both being sorted charlists
    |> Stream.map(&derive_numbers/1)
    |> Enum.sum()
  end

  defp derive_numbers({patterns, output}) do
    %{2 => [one], 3 => [seven], 4 => [four], 5 => len_five, 6 => len_six, 7 => [eight]} =
      (output ++ patterns)
      |> Enum.uniq()
      |> Enum.group_by(&Kernel.length/1)

    {[nine],  len_six}  = Enum.split_with(len_six,  fn nr -> four -- nr == [] end)
    {[zero],  [six]}    = Enum.split_with(len_six,  fn nr -> seven -- nr == [] end)
    {[three], len_five} = Enum.split_with(len_five, fn nr -> seven -- nr == [] end)
    {[five],  [two]}    = Enum.split_with(len_five, fn nr -> nr -- six == [] end)

    output
    |> Enum.map(fn
      ^one -> 1
      ^two -> 2
      ^three -> 3
      ^four -> 4
      ^five -> 5
      ^six -> 6
      ^seven -> 7
      ^eight -> 8
      ^nine -> 9
      ^zero -> 0
    end)
    |> Integer.undigits()
  end
josevalim

josevalim

Creator of Elixir

Day 8 was my favorite day by far, here is my solution: aoc/day-08.livemd at main · josevalim/aoc · GitHub

Ended up using a lot of pattern matching and charlists. Streaming here: Twitch (there is a discussion about bytes, charlists, and Unicode at the end).

groovyda

groovyda

I went down the same route initially - of looking segment-by-segment. But somewhere I realised that I just need the numbers themselves - and then I modified the code.

That was definitely a red herring - given how much time they spent explaining the segments and matching them…

Used a very similar approach to @mruoss - but used MapSet

defmodule Day8 do
  def input2nums(input) do
    segs = 
      input
      |> String.split
      |> Enum.map(&String.to_charlist/1)
      |> Enum.map(&MapSet.new/1)
      |> Enum.sort_by(&MapSet.size/1)

    one = Enum.at(segs, 0)
    seven = Enum.at(segs, 1)
    four = Enum.at(segs, 2)
    eight = Enum.at(segs, 9)
    possible_253 = [Enum.at(segs, 3), Enum.at(segs, 4), Enum.at(segs, 5)]
    possible_069 = [Enum.at(segs, 6), Enum.at(segs, 7), Enum.at(segs, 8)]
    [six] = 
      Enum.filter(
        possible_069, 
        fn num -> 1 == MapSet.intersection(num, one) |> MapSet.size end)
    [three] = 
      Enum.filter(
        possible_253,
        fn num -> 2 == MapSet.intersection(num, one) |> MapSet.size end)
    [nine] = 
      Enum.filter(
        possible_069,
        fn num -> MapSet.intersection(num, three) == three end)
    [zero] = possible_069 -- [six, nine]
    [two] = 
      Enum.filter(
        possible_253,
        fn num -> 2 == MapSet.intersection(num, four) |> MapSet.size end)
    [five] = possible_253 -- [two, three]
    [zero, one, two, three, four, five, six, seven, eight, nine]
  end

  def output2num(line, nums_set) do
    line = 
      line
      |> String.split
      |> Enum.map(&String.to_charlist/1)
      |> Enum.map(&MapSet.new/1)
    
    out = for x <- line, do: Enum.find_index(nums_set, &(&1 == x))
    Enum.join(out)
    |> String.to_integer
  end

  def convert_line(input, output) do
    nums_set = input2nums(input)
    output2num(output, nums_set)
  end
end
stefanluptak

stefanluptak

Part 2 was really interesting today.
I am bit afraid of what’s ahead of us. :smiley:

Where Next?

Popular in Challenges Top

Aetherus
This topic is about Day 16 of the Advent of Code 2020 . Thanks to @egze, we have a private leaderboard: https://adventofcode.com/2020/l...
New
sasajuric
Note by the Moderators: This topic is to talk about Day 5 of the Advent of Code. For general discussion about the Advent of Code 2018 an...
New
bjorng
This topic is about Day 18 of the Advent of Code 2020 . Thanks to @egze, we have a private leaderboard: https://adventofcode.com/2020/l...
New
Qqwy
Note by the Moderators: This topic is to talk about Day 6 of the Advent of Code. For general discussion about the Advent of Code 2018 an...
New
sb8244
Note: This topic is to talk about Day 10 of the Advent of Code 2019 . There is a private leaderboard for elixirforum members. You can jo...
New
adamu
Nobody’s doing Advent of Code this year? :smile: I might do the first week or so. For Day 1, first I solved it using regular expression...
New
jkwchui
Monkeys fitted squarely as GenServers in my head. My initial problem was using cast instead of call; I imagine impolite monkeys slinging...
New
DmitriyChernyavskiy
Hello everyone, I’m a new in elexir and functional language. I’m trying to implement Websocket interraction with server. On first layer...
New
New
Aetherus
Hello, guys. I’m back again, but only for the weekends, maybe. This topic is about Day 13 of the Advent of Code 2020 . Thanks to @egze,...
New

Other popular topics Top

Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID&lt;0.412.0&gt; terminating ** (Postgrex.Error) FATAL...
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
JDanielMartinez
Hi! May someone helps me, please! I have two apps into an umbrella project: the first one is Database, which manages queries, and the se...
New
chrismccord
Phoenix 1.4.0 released Phoenix 1.4 is out! This release ships with exciting new features, most notably with HTTP2 support, improved deve...
688 30048 115
New
sergio
In Ruby, I can go: User.find_by(email: "foobar@email.com").update(email: "hello@email.com") How can I do something similar in Elixir? ...
New
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 45766 226
New
dokuzbir
Hello, I am trying to convert my lists to string without losing brackets.For start i have 3 map. They look like these buyer = %{ id: ...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
vac
Hi, I'm quite new in Elixir and I'm trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and ...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New

We're in Beta

About us Mission Statement