defmodule DaySeven do def part_one(input) do deps = parse_input(input) letters = Enum.map(?A..?Z, &(<<&1>>)) Enum.reverse resolve_instructions(deps, letters, []) end def part_two(input) do deps = parse_input(input) letters = Enum.map(?A..?Z, &(<<&1>>)) resolve_workers(deps, letters, [], 5, 0) - 1 end def parse_input(input) do regex = ~r/Step (\w) must be finished before step (\w) can begin\./ String.split(input, "\n") |> Enum.filter(&(&1 != "")) |> Enum.map(fn line -> [[_, on, dep]] = Regex.scan(regex, line) {on, dep} end) end def resolve_instructions([], [ letter ], acc), do: [letter | acc ] def resolve_instructions(deps, remletters, acc) do firsts = Enum.filter(remletters, fn letter -> not Enum.member?(Enum.map(deps, fn {_on, dep} -> dep end), letter) end) [first | _ ] = firsts |> Enum.sort rem = Enum.filter(deps, fn {on, _dep} -> on != first end) rletters = Enum.filter(remletters, fn letter -> letter != first end) resolve_instructions(rem, rletters, [first | acc]) end def resolve_workers(_deps, [], _workers, _, acc), do: acc def resolve_workers(deps, remletters, workers, maxworkers, acc) do sworkers = Enum.map(workers, fn {task, time} -> {task, time - 1} end) step_workers = Enum.filter(sworkers, fn {_, time} -> time != 0 end) completed = Enum.filter(sworkers, fn {_, time} -> time == 0 end) |> Enum.map(fn {task, _} -> task end) uremletters = Enum.filter(remletters, &(not Enum.member?(completed, &1))) udeps = Enum.filter(deps, fn {on, _dep} -> not Enum.member?(completed, on) end) canwork = Enum.filter(uremletters, fn letter -> not Enum.member?(Enum.map(udeps, fn {_on, dep} -> dep end), letter) end) |> Enum.filter(fn letter -> not Enum.member?(Enum.map(step_workers, fn {task, _} -> task end), letter) end) uworkers = if length(step_workers) < maxworkers and length(canwork) > 0 do schedule_work(canwork, maxworkers - length(step_workers), step_workers) else step_workers end # IO.puts "Move #{acc}, now working on #{Enum.map(uworkers, fn {task, time} -> "(#{task}: #{time})" end) |> Enum.join(", ")}" resolve_workers(udeps, uremletters, uworkers, maxworkers, acc + 1) end def schedule_work([], _, workers), do: workers def schedule_work(_, 0, workers), do: workers def schedule_work([work | tail], numworkers, workers) do schedule_work(tail, numworkers - 1, [{work, time_taken(work)} | workers]) end def time_taken(<< letter >>), do: letter - 4 end {:ok, content} = File.read("input7.txt") IO.puts("Part 1: #{DaySeven.part_one(content)}") IO.puts("Part 2: #{DaySeven.part_two(content)}")