Skip to content

Commit 47aab7c

Browse files
committed
Solve 2018/7
1 parent 9cf10cf commit 47aab7c

3 files changed

Lines changed: 229 additions & 0 deletions

File tree

lib/2018/day_07.ex

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
defmodule AdventOfCode.Y2018.Day07 do
2+
@moduledoc """
3+
--- Day 7: The Sum of Its Parts ---
4+
Problem Link: https://adventofcode.com/2018/day/7
5+
Difficulty: m
6+
Tags: graph topological-sort simulation
7+
"""
8+
alias AdventOfCode.Helpers.{InputReader, Transformers}
9+
alias Yog.Builder.Labeled
10+
alias Yog.Traversal
11+
12+
def input, do: InputReader.read_from_file(2018, 7)
13+
14+
def run(input \\ input()) do
15+
# Build the directed graph of dependencies.
16+
graph = parse(input)
17+
18+
{run_1(graph), run_2(graph)}
19+
end
20+
21+
defp run_1(graph) do
22+
# Part 1: Order of steps.
23+
# We must pick the alphabetically first step among all available ones.
24+
# Yog's lexicographical_topological_sort is built for exactly this!
25+
{:ok, ids} =
26+
Traversal.lexicographical_topological_sort(graph, fn a, b ->
27+
cond do
28+
a < b -> :lt
29+
a > b -> :gt
30+
true -> :eq
31+
end
32+
end)
33+
34+
ids
35+
|> Enum.map(&Yog.Model.node(graph, &1))
36+
|> Enum.join("")
37+
end
38+
39+
defp run_2(graph) do
40+
# Part 2: Time to complete steps with 5 workers.
41+
# Each step duration: 60 + letter_value ('A'=1, etc.)
42+
all_nodes = Yog.Model.all_nodes(graph)
43+
44+
# Initial in-degrees for dependency tracking
45+
in_degrees =
46+
all_nodes
47+
|> Map.new(fn id -> {id, length(Yog.Model.predecessors(graph, id))} end)
48+
49+
# Initial available nodes (no dependencies)
50+
available =
51+
all_nodes
52+
|> Enum.filter(&(in_degrees[&1] == 0))
53+
|> Enum.sort_by(&Yog.Model.node(graph, &1))
54+
55+
simulate(0, [], available, in_degrees, graph)
56+
end
57+
58+
# Simulation loop: advances time and manages workers.
59+
defp simulate(time, [], [], _in_degrees, _graph), do: time
60+
61+
defp simulate(time, workers, available, in_degrees, graph) do
62+
# Assign free workers (up to 5 total)
63+
num_free = 5 - length(workers)
64+
{to_assign, remaining_available} = Enum.split(available, num_free)
65+
66+
new_workers =
67+
Enum.reduce(to_assign, workers, fn id, acc ->
68+
label = Yog.Model.node(graph, id)
69+
duration = 60 + hd(String.to_charlist(label)) - ?A + 1
70+
[{id, duration} | acc]
71+
end)
72+
73+
# Find the nearest event (finish of a worker)
74+
dt = Enum.min_by(new_workers, fn {_, t} -> t end) |> elem(1)
75+
76+
# Advance time!
77+
# Update worker timers and separate finishing ones
78+
{finishing, busy} =
79+
new_workers
80+
|> Enum.map(fn {id, t} -> {id, t - dt} end)
81+
|> Enum.split_with(fn {_, t} -> t == 0 end)
82+
83+
# When a step finishes, we decrease the in-degree of its successors
84+
{new_in_degrees, newly_available} =
85+
Enum.reduce(finishing, {in_degrees, []}, fn {id, _}, {degs, acc_new} ->
86+
successors = Yog.Model.successors(graph, id) |> Enum.map(&elem(&1, 0))
87+
88+
Enum.reduce(successors, {degs, acc_new}, fn succ, {d_acc, a_acc} ->
89+
new_deg = d_acc[succ] - 1
90+
new_d_acc = Map.put(d_acc, succ, new_deg)
91+
new_a_acc = if new_deg == 0, do: [succ | a_acc], else: a_acc
92+
{new_d_acc, new_a_acc}
93+
end)
94+
end)
95+
96+
# Finalize the next iteration's available nodes (must be sorted alphabetically)
97+
final_available =
98+
(remaining_available ++ newly_available)
99+
|> Enum.sort_by(&Yog.Model.node(graph, &1))
100+
101+
simulate(time + dt, busy, final_available, new_in_degrees, graph)
102+
end
103+
104+
def parse(data \\ input()) do
105+
# Build a directed graph from the dependency strings.
106+
Transformers.lines(data)
107+
|> Enum.reduce(Labeled.directed(), fn line, builder ->
108+
# Example: "Step C must be finished before step P can begin."
109+
words = String.split(line, " ")
110+
prereq = Enum.at(words, 1)
111+
step = Enum.at(words, 7)
112+
Labeled.add_unweighted_edge(builder, prereq, step)
113+
end)
114+
|> Labeled.to_graph()
115+
end
116+
end

priv/input_files/2018_7.txt

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
Step C must be finished before step P can begin.
2+
Step V must be finished before step Q can begin.
3+
Step T must be finished before step X can begin.
4+
Step B must be finished before step U can begin.
5+
Step Z must be finished before step O can begin.
6+
Step P must be finished before step I can begin.
7+
Step D must be finished before step G can begin.
8+
Step A must be finished before step Y can begin.
9+
Step R must be finished before step O can begin.
10+
Step J must be finished before step E can begin.
11+
Step N must be finished before step S can begin.
12+
Step X must be finished before step H can begin.
13+
Step F must be finished before step L can begin.
14+
Step S must be finished before step I can begin.
15+
Step W must be finished before step Q can begin.
16+
Step H must be finished before step K can begin.
17+
Step K must be finished before step Q can begin.
18+
Step E must be finished before step L can begin.
19+
Step Q must be finished before step O can begin.
20+
Step U must be finished before step G can begin.
21+
Step L must be finished before step O can begin.
22+
Step Y must be finished before step G can begin.
23+
Step G must be finished before step I can begin.
24+
Step M must be finished before step I can begin.
25+
Step I must be finished before step O can begin.
26+
Step A must be finished before step N can begin.
27+
Step H must be finished before step O can begin.
28+
Step T must be finished before step O can begin.
29+
Step H must be finished before step U can begin.
30+
Step A must be finished before step I can begin.
31+
Step B must be finished before step R can begin.
32+
Step V must be finished before step T can begin.
33+
Step H must be finished before step M can begin.
34+
Step C must be finished before step A can begin.
35+
Step B must be finished before step G can begin.
36+
Step L must be finished before step Y can begin.
37+
Step T must be finished before step J can begin.
38+
Step A must be finished before step R can begin.
39+
Step X must be finished before step L can begin.
40+
Step B must be finished before step L can begin.
41+
Step A must be finished before step F can begin.
42+
Step K must be finished before step O can begin.
43+
Step W must be finished before step M can begin.
44+
Step Z must be finished before step N can begin.
45+
Step Z must be finished before step S can begin.
46+
Step R must be finished before step K can begin.
47+
Step Q must be finished before step L can begin.
48+
Step G must be finished before step O can begin.
49+
Step F must be finished before step Y can begin.
50+
Step V must be finished before step H can begin.
51+
Step E must be finished before step I can begin.
52+
Step W must be finished before step Y can begin.
53+
Step U must be finished before step I can begin.
54+
Step F must be finished before step K can begin.
55+
Step M must be finished before step O can begin.
56+
Step Z must be finished before step H can begin.
57+
Step X must be finished before step S can begin.
58+
Step J must be finished before step O can begin.
59+
Step B must be finished before step I can begin.
60+
Step F must be finished before step H can begin.
61+
Step D must be finished before step U can begin.
62+
Step E must be finished before step M can begin.
63+
Step Z must be finished before step X can begin.
64+
Step P must be finished before step L can begin.
65+
Step W must be finished before step H can begin.
66+
Step C must be finished before step D can begin.
67+
Step A must be finished before step X can begin.
68+
Step Q must be finished before step I can begin.
69+
Step R must be finished before step Y can begin.
70+
Step B must be finished before step A can begin.
71+
Step N must be finished before step L can begin.
72+
Step H must be finished before step G can begin.
73+
Step Y must be finished before step M can begin.
74+
Step L must be finished before step G can begin.
75+
Step G must be finished before step M can begin.
76+
Step Z must be finished before step R can begin.
77+
Step S must be finished before step Q can begin.
78+
Step P must be finished before step J can begin.
79+
Step V must be finished before step J can begin.
80+
Step J must be finished before step I can begin.
81+
Step J must be finished before step X can begin.
82+
Step W must be finished before step O can begin.
83+
Step B must be finished before step F can begin.
84+
Step R must be finished before step M can begin.
85+
Step V must be finished before step S can begin.
86+
Step H must be finished before step E can begin.
87+
Step E must be finished before step U can begin.
88+
Step R must be finished before step W can begin.
89+
Step X must be finished before step Q can begin.
90+
Step N must be finished before step G can begin.
91+
Step T must be finished before step I can begin.
92+
Step L must be finished before step M can begin.
93+
Step H must be finished before step I can begin.
94+
Step U must be finished before step M can begin.
95+
Step C must be finished before step H can begin.
96+
Step P must be finished before step H can begin.
97+
Step J must be finished before step F can begin.
98+
Step A must be finished before step O can begin.
99+
Step X must be finished before step M can begin.
100+
Step H must be finished before step L can begin.
101+
Step W must be finished before step K can begin.

test/2018/day_07_test.exs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
defmodule AdventOfCode.Y2018.Day07Test do
2+
@moduledoc false
3+
4+
use ExUnit.Case, async: true
5+
@moduletag :y1807
6+
7+
alias AdventOfCode.Y2018.Day07, as: Solution
8+
9+
test "Year 2018, Day 7 run/1" do
10+
assert Solution.run() == {"BCADPVTJFZNRWXHEKSQLUYGMIO", 973}
11+
end
12+
end

0 commit comments

Comments
 (0)