88 lines
1.9 KiB
Crystal
88 lines
1.9 KiB
Crystal
|
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
|