Once I got there, I found part 2 to be a fairly straightforward extension to parallelise the work and keep track of remaining time. One trick was to make the Work ordering put in-progress work first, so on each iterations the workers pulled active steps from the stack first.

I was convinced at first I could sort the steps like this:

It worked on the test data, but not on the full problem. I was really frustrated for a while, and had to google it, coming up with Kahn's algorithm

I went through an imperative, mutation-heavy version first but my Kotlin for part 1 ended up like this:

Once I got there, I found part 2 to be a fairly straightforward extension to parallelise the work and keep track of remaining time. One trick was to make the

`Work`

ordering put in-progress work first, so on each iterations the workers pulled active steps from the stack first.