require "./common.cr" lines = File.read("day7_input").split("\n") lines.pop REGEX = /Step (.+) must be finished before step (.+) can begin./ all_children = {} of String => Set(String) all = Set(String).new finished = Set(String).new finished_array = Array(String).new lines.map(&.match(REGEX)).each do |match| match = match.not_nil! child = match[1] parent = match[2] all << child all << parent parent_set = all_children[parent]? || Set(String).new parent_set << child all_children[parent] = parent_set end available_at = {} of String => Int32 class String def cost return (self[0].bytes[0] - 'A'.bytes[0]).to_i32 + 1 end end def get_available(all, finished, children) available = all.select do |it| next false if finished.includes? it next true unless set = children[it]? next true if set.size == 0 end end children = all_children.clone while finished.size != all.size available = get_available(all, finished, children) available.sort! first = available.first finished << first finished_array << first children.values.each do |value| value.delete first end end puts finished_array.join "" finished.clear finished_array.clear children = all_children.clone workers = [0, 0, 0, 0, 0] current_time = 0 finished_at = {} of String => Int32 while finished.size < all.size workers.each_with_index do |worker, index| next if worker > current_time current_finished = finished_at.select { |k, v| v <= current_time }.map(&.[0]).to_set available = all.select do |it| next false if finished.includes? it next true unless nodes = children[it]? (nodes - current_finished).size == 0 end available = available.sort! next if available.empty? first = available.first finished_at[first] = current_time + first.cost + 60 workers[index] = current_time + first.cost + 60 finished_array << first finished << first end current_time += 1 end puts finished_at.values.max