This commit is contained in:
Shadowfacts 2018-12-07 15:25:06 -05:00
parent f677b1326e
commit 3203eeb9c3
Signed by: shadowfacts
GPG Key ID: 83FB3304046BADA4
3 changed files with 218 additions and 0 deletions

113
lib/day7/day7.ex Normal file
View File

@ -0,0 +1,113 @@
defmodule Day7 do
def get_requirement(str) do
[_, requirement, step] = Regex.run(~r/Step (\w) must be finished before step (\w) can begin./, str)
{step, requirement}
end
def all_nodes(requirements) do
requirements
|> Enum.reduce([], fn {step, req}, acc ->
[step | [req | acc]]
end)
|> Enum.uniq
end
def create_graph(requirements) do
Enum.reduce(requirements, %{}, fn {step, req}, acc ->
Map.update(acc, step, [req], &([req | &1]))
end)
end
@doc """
Topological sort implemented using Kahn's algorithm: https://en.wikipedia.org/wiki/Topological_sorting#Kahn's_algorithm
"""
def kahn(_nodes, sorted, _graph, []), do: Enum.reverse(sorted)
def kahn(nodes, sorted, graph, no_incoming_edges) do
# sort no_incoming_edges lexicographically as per AoC problem
[n | rest_no_incoming_edges] = no_incoming_edges |> Enum.sort()
sorted = [n | sorted]
{graph, no_incoming_edges} =
nodes
|> Enum.filter(fn m -> n in Map.get(graph, m, []) end)
|> Enum.reduce({graph, rest_no_incoming_edges}, fn m, {graph, no_incoming_edges} ->
new_dependencies_of_m = graph |> Map.get(m) |> List.delete(n)
new_graph = graph |> Map.put(m, new_dependencies_of_m)
{
new_graph,
case new_dependencies_of_m do
[] -> [m | no_incoming_edges]
_ -> no_incoming_edges
end
}
end)
kahn(nodes, sorted, graph, no_incoming_edges)
end
def kahn(nodes, graph) do
no_incoming_edges = Enum.filter(nodes, fn node -> !Map.has_key?(graph, node) end)
kahn(nodes, [], graph, no_incoming_edges)
end
def step_time(nil), do: 0
def step_time(<<c::utf8, _rest::binary>>) do
# step - ?A + 1 + extra
c - ?A + 60
end
def tick(workers, nodes, graph, done \\ [], time \\ 0) do
{workers, {done, nodes}} =
Enum.map_reduce(workers, {done, nodes}, fn {current_step, remaining}, {done, nodes} ->
case remaining do
0 ->
new_done = case current_step do
nil -> done
_ -> [current_step | done]
end
next_step =
nodes
|> Enum.find(fn node ->
Enum.all?(Map.get(graph, node, []), fn dep -> dep in new_done end)
end)
new_nodes = List.delete(nodes, next_step)
{{next_step, step_time(next_step)}, {new_done, new_nodes}}
n when n > 0 ->
{{current_step, n - 1}, {done, nodes}}
end
end)
IO.inspect(nodes)
IO.inspect(done)
IO.inspect(workers)
if length(nodes) == 0 and Enum.all?(workers, fn {step, _} -> step == nil end) do
time - 1
else
tick(workers, nodes, graph, done, time + 1)
end
end
def parse_input() do
File.read!("lib/day7/input.txt")
|> String.split("\n", trim: true)
|> Enum.map(&get_requirement/1)
end
def part1() do
requirements = parse_input()
nodes = all_nodes(requirements)
graph = create_graph(requirements)
kahn(nodes, graph)
|> Enum.join()
end
def part2() do
requirements = parse_input()
nodes = all_nodes(requirements)
graph = create_graph(requirements)
workers = for _ <- 1..5, do: {nil, 1}
tick(workers, nodes, graph)
end
end

101
lib/day7/input.txt Normal file
View File

@ -0,0 +1,101 @@
Step T must be finished before step C can begin.
Step V must be finished before step C can begin.
Step Y must be finished before step H can begin.
Step R must be finished before step U can begin.
Step B must be finished before step J can begin.
Step Q must be finished before step O can begin.
Step W must be finished before step O can begin.
Step S must be finished before step X can begin.
Step I must be finished before step N can begin.
Step X must be finished before step H can begin.
Step M must be finished before step L can begin.
Step A must be finished before step F can begin.
Step G must be finished before step P can begin.
Step U must be finished before step E can begin.
Step Z must be finished before step E can begin.
Step H must be finished before step L can begin.
Step P must be finished before step C can begin.
Step K must be finished before step F can begin.
Step O must be finished before step C can begin.
Step C must be finished before step F can begin.
Step D must be finished before step L can begin.
Step L must be finished before step F can begin.
Step N must be finished before step E can begin.
Step J must be finished before step F can begin.
Step F must be finished before step E can begin.
Step I must be finished before step A can begin.
Step Z must be finished before step J can begin.
Step I must be finished before step P can begin.
Step T must be finished before step E can begin.
Step R must be finished before step F can begin.
Step U must be finished before step H can begin.
Step K must be finished before step E can begin.
Step D must be finished before step N can begin.
Step U must be finished before step C can begin.
Step D must be finished before step J can begin.
Step N must be finished before step F can begin.
Step C must be finished before step J can begin.
Step U must be finished before step J can begin.
Step A must be finished before step O can begin.
Step H must be finished before step N can begin.
Step P must be finished before step O can begin.
Step I must be finished before step E can begin.
Step G must be finished before step F can begin.
Step O must be finished before step J can begin.
Step Q must be finished before step F can begin.
Step G must be finished before step J can begin.
Step X must be finished before step E can begin.
Step S must be finished before step D can begin.
Step R must be finished before step P can begin.
Step K must be finished before step L can begin.
Step R must be finished before step Q can begin.
Step L must be finished before step N can begin.
Step Q must be finished before step C can begin.
Step C must be finished before step D can begin.
Step C must be finished before step N can begin.
Step O must be finished before step E can begin.
Step W must be finished before step F can begin.
Step K must be finished before step D can begin.
Step T must be finished before step H can begin.
Step M must be finished before step D can begin.
Step Y must be finished before step Z can begin.
Step J must be finished before step E can begin.
Step S must be finished before step F can begin.
Step G must be finished before step U can begin.
Step V must be finished before step S can begin.
Step Y must be finished before step F can begin.
Step G must be finished before step H can begin.
Step T must be finished before step Q can begin.
Step S must be finished before step U can begin.
Step V must be finished before step D can begin.
Step W must be finished before step M can begin.
Step M must be finished before step E can begin.
Step A must be finished before step H can begin.
Step B must be finished before step F can begin.
Step B must be finished before step N can begin.
Step D must be finished before step F can begin.
Step W must be finished before step K can begin.
Step P must be finished before step E can begin.
Step B must be finished before step X can begin.
Step Q must be finished before step U can begin.
Step Q must be finished before step X can begin.
Step X must be finished before step N can begin.
Step M must be finished before step Z can begin.
Step G must be finished before step Z can begin.
Step S must be finished before step G can begin.
Step P must be finished before step F can begin.
Step I must be finished before step O can begin.
Step R must be finished before step A can begin.
Step L must be finished before step J can begin.
Step B must be finished before step I can begin.
Step C must be finished before step E can begin.
Step B must be finished before step W can begin.
Step P must be finished before step N can begin.
Step H must be finished before step C can begin.
Step K must be finished before step J can begin.
Step Y must be finished before step M can begin.
Step Z must be finished before step P can begin.
Step I must be finished before step K can begin.
Step V must be finished before step E can begin.
Step Y must be finished before step P can begin.
Step T must be finished before step R can begin.

4
test/day7_test.exs Normal file
View File

@ -0,0 +1,4 @@
defmodule Day7Test do
use ExUnit.Case
doctest Day7
end