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
 |