diff --git a/lib/day7/day7.ex b/lib/day7/day7.ex new file mode 100644 index 0000000..24ce3a1 --- /dev/null +++ b/lib/day7/day7.ex @@ -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(<>) 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 \ No newline at end of file diff --git a/lib/day7/input.txt b/lib/day7/input.txt new file mode 100644 index 0000000..76d8d71 --- /dev/null +++ b/lib/day7/input.txt @@ -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. \ No newline at end of file diff --git a/test/day7_test.exs b/test/day7_test.exs new file mode 100644 index 0000000..6493791 --- /dev/null +++ b/test/day7_test.exs @@ -0,0 +1,4 @@ +defmodule Day7Test do + use ExUnit.Case + doctest Day7 +end