-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDay14.java
155 lines (130 loc) · 6.45 KB
/
Day14.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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package aoc2019.day14;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;
public class Day14 {
private static final String FUEL = "FUEL";
private static final String ORE = "ORE";
public static Map<Chemical, List<Chemical>> readInput(String input) {
Map<Chemical, List<Chemical>> chemicalListMap = new HashMap<>();
BufferedReader reader;
try {
reader = new BufferedReader(new FileReader(input));
String line = reader.readLine();
while (line != null) {
String[] reaction = line.split(" => ");
String[] consumed = reaction[0].split(", ");
List<Chemical> consumedChemicals = Arrays.stream(consumed)
.map(consumedChemical -> consumedChemical.split(" "))
.map(c -> new Chemical(Integer.parseInt(c[0]), c[1]))
.collect(Collectors.toList());
String[] produced = reaction[1].split(" ");
chemicalListMap.put(new Chemical(Integer.parseInt(produced[0]), produced[1]), consumedChemicals);
line = reader.readLine();
}
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
return chemicalListMap;
}
static long computeChemicals(Map<Chemical, List<Chemical>> map) {
return computeOreNeededFor1FuelProduction(map.get(new Chemical(1, FUEL)), map, new ArrayList<>()).getOreNeeded();
}
static long computeMaxFuel(Map<Chemical, List<Chemical>> map, long oreNum) {
List<Chemical> chemicalList = map.get(new Chemical(1, FUEL));
List<Chemical> storage = new ArrayList<>();
long oreTotal = 0;
long fuelProduced = 0;
while (oreTotal < oreNum) {
FuelProduction fuelProduction = computeOreNeededFor1FuelProduction(chemicalList, map, storage);
oreTotal += fuelProduction.getOreNeeded();
storage = fuelProduction.getWaste();
fuelProduced++;
chemicalList = map.get(new Chemical(1, FUEL));
}
return fuelProduced - 1;
}
private static FuelProduction computeOreNeededFor1FuelProduction(List<Chemical> chemicalList, Map<Chemical, List<Chemical>> map, List<Chemical> storage) {
long oreTotal = 0;
while (true) {
List<Chemical> neededChemicals = new ArrayList<>();
for (Chemical chemical : chemicalList) {
Map.Entry<Chemical, List<Chemical>> producerAndList = findProducersOfChemical(chemical.getName(), map);
Chemical producer = producerAndList.getKey();
Chemical chemInStorage = findChemicalInList(producer.getName(), storage);
chemical = checkExistingWaste(storage, chemical, chemInStorage);
int remainder;
int multiplier = 1;
// If the produced quantity is larger than needed, the waste is their difference
if (chemical.getQuantity() < producer.getQuantity()) {
remainder = producer.getQuantity() - chemical.getQuantity();
// Case when previous waste can be used to produce the chemical
if (chemical.getQuantity() == 0) {
multiplier = 0;
}
} else {
multiplier = (int) Math.ceil((double) chemical.getQuantity() / producer.getQuantity());
remainder = multiplier * producer.getQuantity() - chemical.getQuantity();
}
addWasteToStorage(storage, chemical, producer, remainder);
oreTotal = updateProducerChemicals(neededChemicals, oreTotal, producerAndList, multiplier);
}
chemicalList = new ArrayList<>(neededChemicals);
if (neededChemicals.isEmpty()) {
break;
}
}
return new FuelProduction(oreTotal, storage);
}
private static Chemical checkExistingWaste(List<Chemical> storage, Chemical chemical, Chemical chemInStorage) {
if (chemInStorage != null) {
// If the stored waste is larger than the needed amount, the chemical can be produced already
if (chemInStorage.getQuantity() > chemical.getQuantity()) {
storage.add(new Chemical(chemInStorage.getQuantity() - chemical.getQuantity(), chemical.getName()));
chemical = new Chemical(0, chemical.getName());
storage.remove(chemInStorage);
} else {
chemical = new Chemical(chemical.getQuantity() - chemInStorage.getQuantity(), chemical.getName());
storage.remove(chemInStorage);
}
}
return chemical;
}
private static void addWasteToStorage(List<Chemical> storage, Chemical chemical, Chemical producer, int remainder) {
// If there is waste, add it to storage, or update existing waste's quantity
if (remainder != 0 && chemical.getQuantity() != 0) {
Chemical chem = findChemicalInList(producer.getName(), storage);
if (chem != null) {
storage.add(new Chemical(chem.getQuantity() + remainder, producer.getName()));
storage.remove(chem);
} else {
storage.add(new Chemical(remainder, producer.getName()));
}
}
}
private static long updateProducerChemicals(List<Chemical> neededChemicals, long oreTotal, Map.Entry<Chemical, List<Chemical>> producerAndList, int multiplier) {
for (Chemical chem : producerAndList.getValue()) {
if (chem.getName().equals(ORE)) {
oreTotal += chem.getQuantity() * multiplier;
} else {
neededChemicals.add(new Chemical(chem.getQuantity() * multiplier, chem.getName()));
}
}
return oreTotal;
}
private static Chemical findChemicalInList(String name, List<Chemical> chemicals) {
return chemicals.stream()
.filter(carnet -> carnet.getName().equals(name))
.findFirst()
.orElse(null);
}
private static Map.Entry<Chemical, List<Chemical>> findProducersOfChemical(String name, Map<Chemical, List<Chemical>> map) {
return map.entrySet().stream()
.filter(entry -> entry.getKey().getName().equals(name))
.findFirst()
.orElse(null);
}
}