-
Notifications
You must be signed in to change notification settings - Fork 0
/
Program.fs
91 lines (70 loc) · 2.67 KB
/
Program.fs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
open System
open System.IO
open System.Text.RegularExpressions
let (|Regex|_|) pattern input =
let m = Regex.Match(input, pattern)
if m.Success
then Some(List.tail [ for g in m.Groups -> g.Value ])
else None
let parse line =
match line with
| Regex @"Step ([A-Z]) must be finished before step ([A-Z]) can begin." [ a; b ] -> a.[0], b.[0]
| _ -> failwithf "Unable to parse line: %s" line
type Task = { Task: char; TimeLeft: int }
type Worker =
| Idle
| Working of Task
let solve timePerTask numWorkers dependencies =
let allTasks =
dependencies
|> Seq.collect (fun (a, b) -> [ a; b ])
|> Set.ofSeq
let dependencyMap =
dependencies
|> Seq.groupBy snd
|> Map.ofSeq
|> Map.map (fun _ values -> Seq.map fst values |> Seq.toList)
let mutable finished = List.empty
let mutable remaining = Set.toList allTasks
let isTaskReady task =
Map.tryFind task dependencyMap
|> Option.map (List.except finished >> List.isEmpty)
|> Option.defaultValue true
let pullTask () =
let readyTasks =
remaining |> List.filter isTaskReady |> List.sort
match readyTasks with
| [] -> Idle
| task :: _ ->
remaining <- List.except [ task ] remaining
let time = timePerTask + (int task - int 'A' + 1)
Working { Task = task; TimeLeft = time }
let mutable t = 0
let maxT =
List.length remaining * (timePerTask + 26)
let schedule = Array2D.create maxT numWorkers Idle
while not (Set.forall (fun task -> List.contains task finished) allTasks) do
for w in 0 .. numWorkers - 1 do
if t = 0 then
schedule.[t, w] <- pullTask ()
else
match schedule.[t - 1, w] with
| Idle -> schedule.[t, w] <- pullTask ()
| Working task when task.TimeLeft = 1 ->
finished <- finished @ [ task.Task ]
schedule.[t, w] <- pullTask ()
| Working task ->
schedule.[t, w] <- Working
{ task with
TimeLeft = task.TimeLeft - 1 }
t <- t + 1
finished, t - 1
[<EntryPoint>]
let main argv =
let dependencies =
File.ReadLines("Input.txt") |> Seq.map parse
let order, _ = solve 0 1 dependencies
printfn "Part one: %s" (String.Concat order)
let _, time = solve 60 5 dependencies
printfn "Part two: %d" time
0 // return an integer exit code