Aetherus

Aetherus

This topic is about Day 7 of the Advent of Code 2020 .

Thanks to @egze, we have a private leaderboard:
https://adventofcode.com/2020/leaderboard/private/view/39276

The join code is:
39276-eeb74f9a

I become busy this week, so I may not be able to create such topics in time. Apologies in advance.

Showing Posts 17 to 8

Aetherus

Aetherus OP

Actually, your code is quite readable.

adolfont

adolfont

stevensonmt

stevensonmt

I was one short. I think on the final match I was returning before adding it to the stack, but not sure.

adamu

adamu

Maybe you counted the shiny gold bag.

jarimatti

jarimatti

I modeled the data as directed graph where the edge label is the count of bags inside the source bag using Erlang :digraph and :digraph_utils. Part 2 turned out with similar (not tail-recursive) structure. Not the most elegant but gets the job done:

  def count_bags_from(graph, node) do
    edges =
      for e <- :digraph.out_edges(graph, node) do
        :digraph.edge(graph, e)
      end

    own_counts =
      edges
      |> Enum.map(fn {_e, _from, _to, count} -> count end)
      |> Enum.sum()

    counts =
      for {_e, _from, to, count} <- edges do
        count * count_bags_from(graph, to)
      end

    own_counts + Enum.sum(counts)
  end

The benefit of :digraph is in the solution for first part:

  def part1 do
    graph = read_input()

    result = length(Digraph.reaching(graph, "shiny gold"))
    Digraph.delete(graph)
    result
  end

where Digraph.reaching/2 is defined as:

defmodule AoC2020.Day7.Digraph do
  ...
    def reaching(g, target) do
    :digraph_utils.reaching([target], g) -- [target]
  end
  ...
end
jarimatti

jarimatti

That’s a nice implementation of count_bags/2, much more readable than what I managed to do.

stevensonmt

stevensonmt

Starting to get a little tough. I managed to get this after examining some of the solutions posted here. I had a naive solution for part 1 that was off by one and I can’t figure out why. Since my final solution was derivative of other posts here not posting it but wanted to say thanks for everyone who did post their solutions for providing the guidance.

ricardo-h

ricardo-h

part2 bad parse - can be improved

defmodule Advent.Day7b do

  def start(file \\ "/tmp/input2.txt"), do:
    File.stream!(file)
    |> Enum.reduce(%{},
        fn line, acc -> format_map(acc, String.replace(line, ["bag", "bags", ".", "\n", "no other"], "") |> String.split(" contain"))
       end)
    |> process()
    |> elem(1)

  def process(map), do: map |> Map.get("shiny gold") |> process(map, 1, 0)

  def process(nil, _map, mult, total), do: {mult, total}
  def process(bags, map, mult, total) do
    Enum.reduce(bags, {mult, total}, fn {item, qtd}, {_, acc_total} ->
      case Map.get(map, item) do
        nil -> {mult, acc_total + mult * qtd}
        new_bags -> process(new_bags, map, mult * qtd, acc_total + mult * qtd)
      end
    end )
  end

  defp format_map(map, [_bag, "  "]), do: map
  defp format_map(map, [bag, bags]) do
    bags
    |> String.split(",")
    |> Enum.map(fn o -> String.trim(o)
            |> String.split(" ", parts: 2) end)
            |> Enum.filter(fn o -> o !== [[""]] end)
            |> Enum.reduce(map, fn [num, item], acc ->
                v = [{item, String.to_integer(num)}]
                Map.update(acc, String.trim(bag), v, fn lst -> v ++ lst end)
       end)
  end

end

egze

egze

Used the libgraph library.

GitHub

defmodule Aoc.Y2020.D7 do
  use Aoc.Boilerplate,
    transform: fn raw ->
      raw
      |> String.split("\n")
      |> Enum.reduce(Graph.new(), fn line, graph ->
        [main, others] = line |> String.split(" contain ")
        main_parsed = main |> String.replace(" bags", "")

        others
        |> String.split([", ", "."], trim: true)
        |> Enum.map(fn other_str ->
          other_str
          |> String.replace([" bags", "bag"], "", global: true)
          |> Integer.parse()
          |> case do
            :error -> {0, "no bags"}
            {n, bag} -> {n, String.trim(bag)}
          end
        end)
        |> Enum.reduce(graph, fn {count, bag}, graph_acc ->
          case count do
            0 -> graph_acc
            _ -> Graph.add_edge(graph_acc, main_parsed, bag, label: count)
          end
        end)
      end)
    end

  def part1(graph \\ processed()) do
    graph
    |> Graph.reaching_neighbors(["shiny gold"])
    |> Enum.count()
  end

  def part2(graph \\ processed()) do
    count_bags(graph, "shiny gold") - 1
  end

  defp count_bags(graph, vertex) do
    graph
    |> Graph.out_edges(vertex)
    |> Enum.reduce(1, fn %{v2: vertex, label: n}, total ->
      total + n * count_bags(graph, vertex)
    end)
  end
end
dominicletz

dominicletz

Creator of Elixir Desktop

I was first afraid there could be loops or sth. but seems fine. Here second solution:

#!/usr/bin/env elixir
my_bag = "shiny gold"

defmodule Day7 do
  def parse(rest) do
    case rest do
      ~w(no other bags.) -> []
      [count, shade, color, _bags] -> [{shade <> " " <> color, count}]
      [count, shade, color, _bags | rest] -> [{shade <> " " <> color, count} | parse(rest)]
    end
  end

  def count(_tree, nil), do: 0
  def count(_tree, []), do: 0
  def count(tree, [{node, cnt} | nodes]) do
    cnt = String.to_integer(cnt)
    cnt + (cnt * count(tree, tree[node])) + count(tree, nodes)
  end
end

tree = File.read!("7.csv")
|> String.split("\n", trim: true)
|> Enum.map(fn row ->
  [shade, color, "bags", "contain" | rest] = String.split(row)

  key = shade <> " " <> color
  contents = Day7.parse(rest)
  {key, contents}
end)
|> Map.new()

Day7.count(tree, tree[my_bag])
|> IO.inspect()

Where Next? Top

Trending in Challenges Top

Other Trending Topics Top

mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
webofbits
With AI doing more of the implementation work, I’ve been wondering how much coding I should deliberately keep doing myself. My main conc...
#ai
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews