-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathAoC072018.java
133 lines (118 loc) Β· 5.63 KB
/
AoC072018.java
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package com.adventofcode.aoc2018;
import static com.adventofcode.utils.Utils.AT;
import static com.adventofcode.utils.Utils.DOT;
import static com.adventofcode.utils.Utils.decrementMapElement;
import static com.adventofcode.utils.Utils.incrementMapElement;
import static com.adventofcode.utils.Utils.itoa;
import static com.adventofcode.utils.Utils.splitOnTabOrSpace;
import com.adventofcode.Solution;
import com.adventofcode.utils.Pair;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Set;
import java.util.function.BinaryOperator;
import java.util.stream.Stream;
class AoC072018 implements Solution {
private static void setup(final List<String> input, final Map<Character, Set<Character>> edges, final Map<Character,
Long> in, final Queue<Character> stepsReady, final List<Pair<Character, Integer>> workersReady,
final int nWorkers) {
computeEdges(input, edges, in);
computeStepsReady(edges, in, stepsReady);
computeWorkersReady(workersReady, nWorkers);
}
private static void computeWorkersReady(final List<Pair<Character, Integer>> workersReady,
final int nWorkers) {
for (int i = 0; i < nWorkers; i++) {
workersReady.add(new Pair<>(DOT, 0));
}
}
private static boolean isSolutionInput(final List<String> input) {
return input.size() > 10;
}
private static void computeStepsReady(final Map<Character, Set<Character>> edges, final Map<Character, Long> in,
final Queue<Character> stepsReady) {
for (final Character k : edges.keySet()) {
if (!in.containsKey(k)) {
stepsReady.add(k);
}
}
}
private static void computeEdges(final List<String> input, final Map<Character, Set<Character>> edges,
final Map<Character, Long> in) {
for (final String s : input) {
final List<String> row = splitOnTabOrSpace(s);
final Character from = row.get(1).charAt(0);
final Character to = row.get(7).charAt(0);
edges.computeIfAbsent(from, k -> new HashSet<>()).add(to);
edges.computeIfAbsent(to, k -> new HashSet<>());
incrementMapElement(in, to);
}
}
private static String solve(final List<String> input, final int nWorkers,
final BinaryOperator<String> computeResult) {
final Map<Character, Set<Character>> edges = new HashMap<>();
final Map<Character, Long> in = new HashMap<>();
final Queue<Character> stepsReady = new PriorityQueue<>();
final List<Pair<Character, Integer>> workersBusy = new ArrayList<>();
final List<Pair<Character, Integer>> workersReady = new ArrayList<>();
setup(input, edges, in, stepsReady, workersReady, nWorkers);
int steps = -1;
final StringBuilder tasksOrdered = new StringBuilder();
while (!workersBusy.isEmpty() || !stepsReady.isEmpty()) {
steps++;
performWork(edges, in, stepsReady, workersBusy, workersReady, tasksOrdered);
distributeWork(input, stepsReady, workersBusy, workersReady);
}
return computeResult.apply(tasksOrdered.toString(), itoa(steps));
}
private static void distributeWork(final List<String> input, final Queue<Character> stepsReady, final List<Pair<Character, Integer>> workersBusy, final List<Pair<Character, Integer>> workersReady) {
//give work to available workers
final var iterator = workersReady.iterator();
while (iterator.hasNext() && !stepsReady.isEmpty()) {
final Pair<Character, Integer> w = iterator.next();
final Character min = stepsReady.remove();
w.setFirst(min);
w.setSecond(getTime(min, isSolutionInput(input)));
//worker is busy
iterator.remove();
workersBusy.add(w);
}
}
private static void performWork(final Map<Character, Set<Character>> edges, final Map<Character, Long> in, final Queue<Character> stepsReady, final List<Pair<Character, Integer>> workersBusy, final List<Pair<Character, Integer>> workersReady, final StringBuilder tasksOrdered) {
final var iterator = workersBusy.iterator();
while (iterator.hasNext()) {
final Pair<Character, Integer> w = iterator.next();
w.setSecond(w.getSecond() - 1); //work on it
if (w.getSecond() == 0) {
//task completed
final Character completed = w.getFirst();
tasksOrdered.append(completed);
for (final Character to : edges.get(completed)) {
if (decrementMapElement(in, to) == 0) {
//no remaining dependencies
stepsReady.add(to);
}
}
//worker is available
iterator.remove();
workersReady.add(w);
}
}
}
private static int getTime(final char c, boolean isSolutionInput) {
//'A'==1, 'B'==2, etc...
return (c - AT) + (isSolutionInput ? 60 : 0);
}
public String solveFirstPart(final Stream<String> input) {
return solve(input.toList(), 1, (tasks, steps) -> tasks);
}
public String solveSecondPart(final Stream<String> input) {
final List<String> list = input.toList();
return solve(list, isSolutionInput(list) ? 5 : 2, (tasks, steps) -> steps);
}
}