Skip to content

Commit 94a3fa0

Browse files
committed
Add day 19 solution
1 parent 7cb0abd commit 94a3fa0

File tree

17 files changed

+960
-0
lines changed

17 files changed

+960
-0
lines changed
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package eu.happycoders.adventofcode2022.day19;
2+
3+
import java.util.EnumMap;
4+
5+
/**
6+
* Advent of Code 2022 – Object-Oriented Solutions in Java.
7+
*
8+
* <p>A blueprint defining which robots the {@link RobotFactory} can produce at what cost.
9+
*
10+
* @author <a href="mailto:sven@happycoders.eu">Sven Woltmann</a>
11+
*/
12+
class Blueprint {
13+
14+
private final int id;
15+
private final EnumMap<ResourceType, Resources> robotCosts = new EnumMap<>(ResourceType.class);
16+
17+
Blueprint(
18+
int id,
19+
Resources oreRobotCost,
20+
Resources clayRobotCost,
21+
Resources obsidianRobotCost,
22+
Resources geodeRobotCost) {
23+
this.id = id;
24+
robotCosts.put(ResourceType.ORE, oreRobotCost);
25+
robotCosts.put(ResourceType.CLAY, clayRobotCost);
26+
robotCosts.put(ResourceType.OBSIDIAN, obsidianRobotCost);
27+
robotCosts.put(ResourceType.GEODE, geodeRobotCost);
28+
}
29+
30+
int getId() {
31+
return id;
32+
}
33+
34+
Resources getRobotCost(ResourceType resourceType) {
35+
return robotCosts.get(resourceType);
36+
}
37+
38+
@Override
39+
public boolean equals(Object object) {
40+
if (this == object) {
41+
return true;
42+
}
43+
44+
if (object == null || getClass() != object.getClass()) {
45+
return false;
46+
}
47+
48+
Blueprint that = (Blueprint) object;
49+
return id == that.id && robotCosts.equals(that.robotCosts);
50+
}
51+
52+
@Override
53+
public int hashCode() {
54+
int result = id;
55+
result = 31 * result + robotCosts.hashCode();
56+
return result;
57+
}
58+
59+
@Override
60+
public String toString() {
61+
StringBuilder result = new StringBuilder();
62+
result.append("Blueprint ").append(id).append(':');
63+
64+
for (ResourceType resourceType : ResourceType.values()) {
65+
result.append(
66+
" Each %s robot costs %s.".formatted(resourceType, robotCosts.get(resourceType)));
67+
}
68+
69+
return result.toString();
70+
}
71+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package eu.happycoders.adventofcode2022.day19;
2+
3+
import static eu.happycoders.adventofcode2022.day19.ResourceType.CLAY;
4+
import static eu.happycoders.adventofcode2022.day19.ResourceType.OBSIDIAN;
5+
import static eu.happycoders.adventofcode2022.day19.ResourceType.ORE;
6+
7+
import java.util.List;
8+
import java.util.regex.Matcher;
9+
import java.util.regex.Pattern;
10+
11+
/**
12+
* Advent of Code 2022 – Object-Oriented Solutions in Java.
13+
*
14+
* <p>Parses the puzzle input text into a list of {@link Blueprint}s.
15+
*
16+
* @author <a href="mailto:sven@happycoders.eu">Sven Woltmann</a>
17+
*/
18+
class BlueprintsParser {
19+
private static final Pattern PATTERN =
20+
Pattern.compile(
21+
"Blueprint (\\d+): "
22+
+ "Each ore robot costs (\\d+) ore. "
23+
+ "Each clay robot costs (\\d+) ore. "
24+
+ "Each obsidian robot costs (\\d+) ore and (\\d+) clay. "
25+
+ "Each geode robot costs (\\d+) ore and (\\d+) obsidian.");
26+
27+
static List<Blueprint> parse(String input) {
28+
return input.lines().map(BlueprintsParser::parseBlueprint).toList();
29+
}
30+
31+
private static Blueprint parseBlueprint(String input) {
32+
Matcher matcher = PATTERN.matcher(input);
33+
if (!matcher.matches()) {
34+
throw new IllegalArgumentException(input);
35+
}
36+
37+
int id = Integer.parseInt(matcher.group(1));
38+
39+
int oreRobotCostOre = Integer.parseInt(matcher.group(2));
40+
Resources oreRobotCost = Resources.builder().with(ORE, oreRobotCostOre).build();
41+
42+
int clayRobotCostOre = Integer.parseInt(matcher.group(3));
43+
Resources clayRobotCost = Resources.builder().with(ORE, clayRobotCostOre).build();
44+
45+
int obsidianRobotCostOre = Integer.parseInt(matcher.group(4));
46+
int obsidianRobotCostClay = Integer.parseInt(matcher.group(5));
47+
Resources obsidianRobotCost =
48+
Resources.builder()
49+
.with(ORE, obsidianRobotCostOre)
50+
.with(CLAY, obsidianRobotCostClay)
51+
.build();
52+
53+
int geodeRobotCostOre = Integer.parseInt(matcher.group(6));
54+
int geodeRobotCostObsidian = Integer.parseInt(matcher.group(7));
55+
Resources geodeRobotCost =
56+
Resources.builder()
57+
.with(ORE, geodeRobotCostOre)
58+
.with(OBSIDIAN, geodeRobotCostObsidian)
59+
.build();
60+
61+
return new Blueprint(id, oreRobotCost, clayRobotCost, obsidianRobotCost, geodeRobotCost);
62+
}
63+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package eu.happycoders.adventofcode2022.day19;
2+
3+
import java.util.List;
4+
5+
/**
6+
* Advent of Code 2022 – Object-Oriented Solutions in Java.
7+
*
8+
* <p>Puzzle solver for day 19.
9+
*
10+
* @author <a href="mailto:sven@happycoders.eu">Sven Woltmann</a>
11+
*/
12+
class Day19Solver {
13+
14+
static int solveTask1(String input) {
15+
List<Blueprint> blueprints = BlueprintsParser.parse(input);
16+
17+
int sumOfQualityLevels = 0;
18+
19+
for (Blueprint blueprint : blueprints) {
20+
RobotFactory factory = new RobotFactory(blueprint);
21+
Simulator simulator = new Simulator(factory, 24);
22+
int largestNumberOfGeodes = simulator.runSimulation();
23+
int qualityLevel = blueprint.getId() * largestNumberOfGeodes;
24+
25+
System.out.printf(
26+
"Blueprint %d: %d geodes -> qualityLevel = %d%n",
27+
blueprint.getId(), largestNumberOfGeodes, qualityLevel);
28+
29+
sumOfQualityLevels += qualityLevel;
30+
}
31+
32+
System.out.printf("Sum of quality levels: %d%n", sumOfQualityLevels);
33+
34+
return sumOfQualityLevels;
35+
}
36+
37+
static int solveTask2(String input) {
38+
List<Blueprint> blueprints = BlueprintsParser.parse(input);
39+
40+
int product = 1;
41+
42+
// This time only the first three blueprints
43+
for (int i = 0; i < Math.min(blueprints.size(), 3); i++) {
44+
Blueprint blueprint = blueprints.get(i);
45+
RobotFactory factory = new RobotFactory(blueprint);
46+
Simulator simulator = new Simulator(factory, 32);
47+
int largestNumberOfGeodes = simulator.runSimulation();
48+
49+
System.out.printf("Blueprint %d: %d geodes%n", blueprint.getId(), largestNumberOfGeodes);
50+
51+
product *= largestNumberOfGeodes;
52+
}
53+
54+
System.out.printf("Product of first three quality levels: %d%n", product);
55+
56+
return product;
57+
}
58+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package eu.happycoders.adventofcode2022.day19;
2+
3+
/**
4+
* Advent of Code 2022 – Object-Oriented Solutions in Java.
5+
*
6+
* <p>Main application for day 19.
7+
*
8+
* @author <a href="mailto:sven@happycoders.eu">Sven Woltmann</a>
9+
*/
10+
class Main19 {
11+
12+
private static final String INPUT =
13+
"""
14+
Blueprint 1: Each ore robot costs 2 ore. Each clay robot costs 2 ore. Each obsidian robot costs 2 ore and 17 clay. Each geode robot costs 2 ore and 10 obsidian.
15+
Blueprint 2: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 15 clay. Each geode robot costs 3 ore and 8 obsidian.
16+
Blueprint 3: Each ore robot costs 3 ore. Each clay robot costs 3 ore. Each obsidian robot costs 2 ore and 16 clay. Each geode robot costs 2 ore and 18 obsidian.
17+
Blueprint 4: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 17 clay. Each geode robot costs 2 ore and 13 obsidian.
18+
Blueprint 5: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 5 clay. Each geode robot costs 3 ore and 15 obsidian.
19+
Blueprint 6: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 17 clay. Each geode robot costs 4 ore and 20 obsidian.
20+
Blueprint 7: Each ore robot costs 3 ore. Each clay robot costs 3 ore. Each obsidian robot costs 2 ore and 9 clay. Each geode robot costs 2 ore and 9 obsidian.
21+
Blueprint 8: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 12 clay. Each geode robot costs 3 ore and 8 obsidian.
22+
Blueprint 9: Each ore robot costs 2 ore. Each clay robot costs 2 ore. Each obsidian robot costs 2 ore and 8 clay. Each geode robot costs 2 ore and 14 obsidian.
23+
Blueprint 10: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 2 ore and 12 clay. Each geode robot costs 3 ore and 15 obsidian.
24+
Blueprint 11: Each ore robot costs 2 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 19 clay. Each geode robot costs 2 ore and 18 obsidian.
25+
Blueprint 12: Each ore robot costs 2 ore. Each clay robot costs 4 ore. Each obsidian robot costs 2 ore and 16 clay. Each geode robot costs 2 ore and 9 obsidian.
26+
Blueprint 13: Each ore robot costs 2 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 18 clay. Each geode robot costs 2 ore and 11 obsidian.
27+
Blueprint 14: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 18 clay. Each geode robot costs 3 ore and 13 obsidian.
28+
Blueprint 15: Each ore robot costs 3 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 9 clay. Each geode robot costs 3 ore and 7 obsidian.
29+
Blueprint 16: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 2 ore and 7 clay. Each geode robot costs 3 ore and 10 obsidian.
30+
Blueprint 17: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 6 clay. Each geode robot costs 2 ore and 20 obsidian.
31+
Blueprint 18: Each ore robot costs 4 ore. Each clay robot costs 3 ore. Each obsidian robot costs 2 ore and 19 clay. Each geode robot costs 3 ore and 13 obsidian.
32+
Blueprint 19: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 2 ore and 14 clay. Each geode robot costs 4 ore and 15 obsidian.
33+
Blueprint 20: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 2 ore and 9 clay. Each geode robot costs 3 ore and 15 obsidian.
34+
Blueprint 21: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 3 ore and 10 clay. Each geode robot costs 2 ore and 7 obsidian.
35+
Blueprint 22: Each ore robot costs 3 ore. Each clay robot costs 3 ore. Each obsidian robot costs 2 ore and 16 clay. Each geode robot costs 3 ore and 14 obsidian.
36+
Blueprint 23: Each ore robot costs 3 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 20 clay. Each geode robot costs 2 ore and 12 obsidian.
37+
Blueprint 24: Each ore robot costs 3 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 6 clay. Each geode robot costs 2 ore and 16 obsidian.
38+
Blueprint 25: Each ore robot costs 4 ore. Each clay robot costs 3 ore. Each obsidian robot costs 4 ore and 20 clay. Each geode robot costs 2 ore and 15 obsidian.
39+
Blueprint 26: Each ore robot costs 4 ore. Each clay robot costs 3 ore. Each obsidian robot costs 2 ore and 20 clay. Each geode robot costs 3 ore and 9 obsidian.
40+
Blueprint 27: Each ore robot costs 2 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 13 clay. Each geode robot costs 3 ore and 15 obsidian.
41+
Blueprint 28: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 2 ore and 11 clay. Each geode robot costs 3 ore and 14 obsidian.
42+
Blueprint 29: Each ore robot costs 4 ore. Each clay robot costs 3 ore. Each obsidian robot costs 4 ore and 15 clay. Each geode robot costs 4 ore and 9 obsidian.
43+
Blueprint 30: Each ore robot costs 4 ore. Each clay robot costs 3 ore. Each obsidian robot costs 2 ore and 7 clay. Each geode robot costs 3 ore and 8 obsidian.""";
44+
45+
public static void main(String[] args) {
46+
Day19Solver.solveTask1(INPUT);
47+
Day19Solver.solveTask2(INPUT);
48+
}
49+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package eu.happycoders.adventofcode2022.day19;
2+
3+
import java.util.Locale;
4+
5+
/**
6+
* Advent of Code 2022 – Object-Oriented Solutions in Java.
7+
*
8+
* <p>The specific resource type (ore, clay, obsidian, geode).
9+
*
10+
* @author <a href="mailto:sven@happycoders.eu">Sven Woltmann</a>
11+
*/
12+
enum ResourceType {
13+
ORE,
14+
CLAY,
15+
OBSIDIAN,
16+
GEODE;
17+
18+
@Override
19+
public String toString() {
20+
return name().toLowerCase(Locale.US);
21+
}
22+
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package eu.happycoders.adventofcode2022.day19;
2+
3+
import java.util.EnumMap;
4+
import java.util.Objects;
5+
6+
/**
7+
* Advent of Code 2022 – Object-Oriented Solutions in Java.
8+
*
9+
* <p>A collection of ore, clay, obsidian and geode.
10+
*
11+
* <p>This class is immutable.
12+
*
13+
* @author <a href="mailto:sven@happycoders.eu">Sven Woltmann</a>
14+
*/
15+
class Resources {
16+
17+
private final EnumMap<ResourceType, Integer> numberOfResources;
18+
19+
Resources() {
20+
this.numberOfResources = new EnumMap<>(ResourceType.class);
21+
}
22+
23+
private Resources(EnumMap<ResourceType, Integer> numberOfResources) {
24+
this.numberOfResources = numberOfResources;
25+
}
26+
27+
int get(ResourceType resourceType) {
28+
return numberOfResources.getOrDefault(resourceType, 0);
29+
}
30+
31+
Resources subtract(Resources cost) {
32+
ResourcesBuilder builder = new ResourcesBuilder();
33+
for (ResourceType resourceType : ResourceType.values()) {
34+
int oldValue = get(resourceType);
35+
int costValue = cost.get(resourceType);
36+
int newValue = oldValue - costValue;
37+
builder.with(resourceType, newValue);
38+
}
39+
return builder.build();
40+
}
41+
42+
boolean cover(Resources cost) {
43+
for (ResourceType value : ResourceType.values()) {
44+
if (cost.get(value) > get(value)) {
45+
return false;
46+
}
47+
}
48+
return true;
49+
}
50+
51+
@Override
52+
public boolean equals(Object object) {
53+
if (this == object) {
54+
return true;
55+
}
56+
57+
if (object == null || getClass() != object.getClass()) {
58+
return false;
59+
}
60+
61+
Resources that = (Resources) object;
62+
return Objects.equals(numberOfResources, that.numberOfResources);
63+
}
64+
65+
@Override
66+
public int hashCode() {
67+
return numberOfResources != null ? numberOfResources.hashCode() : 0;
68+
}
69+
70+
@Override
71+
public String toString() {
72+
StringBuilder result = new StringBuilder();
73+
for (ResourceType resourceType : ResourceType.values()) {
74+
addResourceTypeToString(result, get(resourceType), resourceType);
75+
}
76+
return result.toString();
77+
}
78+
79+
private void addResourceTypeToString(
80+
StringBuilder result, int amount, ResourceType resourceType) {
81+
if (amount > 0) {
82+
if (!result.isEmpty()) {
83+
result.append(" and ");
84+
}
85+
result.append(amount);
86+
result.append(' ');
87+
result.append(resourceType);
88+
}
89+
}
90+
91+
static ResourcesBuilder builder() {
92+
return new ResourcesBuilder();
93+
}
94+
95+
static class ResourcesBuilder {
96+
97+
private final EnumMap<ResourceType, Integer> numberOfResources =
98+
new EnumMap<>(ResourceType.class);
99+
100+
ResourcesBuilder with(ResourceType resourceType, int value) {
101+
numberOfResources.put(resourceType, value);
102+
return this;
103+
}
104+
105+
Resources build() {
106+
return new Resources(numberOfResources);
107+
}
108+
}
109+
}

0 commit comments

Comments
 (0)