Skip to content

Commit ddc8d3e

Browse files
committed
Day 24
1 parent 95f8894 commit ddc8d3e

File tree

1 file changed

+179
-0
lines changed

1 file changed

+179
-0
lines changed

src/test/java/com/macasaet/Day24.java

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
package com.macasaet;
2+
3+
import java.io.IOException;
4+
import java.util.ArrayList;
5+
import java.util.Arrays;
6+
import java.util.Collections;
7+
import java.util.HashMap;
8+
import java.util.Map.Entry;
9+
import java.util.stream.Collectors;
10+
import java.util.stream.Stream;
11+
import java.util.stream.StreamSupport;
12+
13+
public class Day24 {
14+
15+
public static void main(final String[] args) throws IOException {
16+
final Address origin = new Address(0, 0, 0);
17+
final var lobbyFloor = new HashMap<Address, Integer>();
18+
try (var spliterator = new LineSpliterator(Day22.class.getResourceAsStream("/day-24-input.txt"))) {
19+
StreamSupport.stream(spliterator, false)
20+
.map(String::toCharArray)
21+
.map(array -> {
22+
int i = 0;
23+
var directions = new ArrayList<Direction>(array.length);
24+
while (i < array.length) {
25+
if (i < array.length - 1) { // check if there are at least 2 chars available
26+
final var twoLetterDirection = "" + array[i] + array[i + 1];
27+
// check if two chars is a valid direction
28+
if ("se".equalsIgnoreCase(twoLetterDirection)
29+
|| "sw".equalsIgnoreCase(twoLetterDirection)
30+
|| "nw".equalsIgnoreCase(twoLetterDirection)
31+
|| "ne".equalsIgnoreCase(twoLetterDirection)) {
32+
directions.add(Direction.forAbbreviation(twoLetterDirection));
33+
i = i + 2;
34+
continue;
35+
}
36+
}
37+
final var oneLetterDirection = "" + array[i];
38+
if ("e".equalsIgnoreCase(oneLetterDirection) || "w".equalsIgnoreCase(oneLetterDirection)) {
39+
directions.add(Direction.forAbbreviation(oneLetterDirection));
40+
i = i + 1;
41+
continue;
42+
}
43+
throw new IllegalArgumentException("Invalid direction: " + oneLetterDirection);
44+
}
45+
return Collections.unmodifiableList(directions);
46+
}).map(directions -> {
47+
Address cursor = origin;
48+
for (final var direction : directions) {
49+
cursor = direction.travel(cursor);
50+
}
51+
return cursor;
52+
}).forEach(address -> lobbyFloor.merge(address, 1, (old, def) -> old + 1));
53+
}
54+
final int blackTiles = lobbyFloor.values().stream().mapToInt(count -> count % 2).sum();
55+
System.out.println("Part 1: " + blackTiles);
56+
57+
for (int i = 1; i <= 100; i++) {
58+
final var tasks = lobbyFloor.entrySet().stream().flatMap(entry -> {
59+
// get the mapped tile
60+
// as well as unmapped (white) adjacent tiles
61+
final var from = entry.getKey();
62+
return Stream.concat(Stream.of(entry), Arrays.stream(Direction.values()).flatMap(direction -> {
63+
final var neighbour = direction.travel(from);
64+
if (!lobbyFloor.containsKey(neighbour)) {
65+
// neighbour has never been visited, create a virtual entry for them
66+
return Stream.of(new Entry<Address, Integer>() {
67+
public Address getKey() {
68+
return neighbour;
69+
}
70+
71+
public Integer getValue() {
72+
return 0;
73+
}
74+
75+
public Integer setValue(Integer value) {
76+
throw new UnsupportedOperationException();
77+
}
78+
});
79+
}
80+
return Stream.empty();
81+
}));
82+
}).map(entry -> { // NB: this might not be a real tile
83+
final var address = entry.getKey();
84+
final int adjacentBlackTiles = Arrays.stream(Direction.values())
85+
.map(direction -> direction.travel(address))
86+
.mapToInt(neighbour -> {
87+
final Integer neighbouringCount = lobbyFloor.get(neighbour);
88+
return neighbouringCount != null && neighbouringCount % 2 == 1 ? 1 : 0;
89+
}).sum();
90+
if (entry.getValue() % 2 == 1 && (adjacentBlackTiles == 0 || adjacentBlackTiles > 2)) {
91+
// Any black tile with zero or more than 2 black tiles immediately adjacent to it is flipped to white.
92+
return (Runnable) () -> lobbyFloor.put(address, 0);
93+
} else if (entry.getValue() % 2 == 0 && adjacentBlackTiles == 2) {
94+
// Any white tile with exactly 2 black tiles immediately adjacent to it is flipped to black.
95+
return (Runnable) () -> lobbyFloor.put(address, 1);
96+
}
97+
return (Runnable) () -> {
98+
};
99+
}).collect(Collectors.toUnmodifiableList());
100+
for (final var task : tasks) {
101+
task.run();
102+
}
103+
}
104+
final int count = lobbyFloor.values().stream().mapToInt(value -> value % 2).sum();
105+
System.out.println("Part 2: " + count);
106+
}
107+
108+
public enum Direction {
109+
EAST("e", 1, -1, 0),
110+
SOUTH_EAST("se", 0, -1, 1),
111+
SOUTH_WEST("sw", -1, 0, 1),
112+
WEST("w", -1, 1, 0),
113+
NORTH_WEST("nw", 0, 1, -1),
114+
NORTH_EAST("ne", 1, 0, -1);
115+
116+
private final String abbreviation;
117+
private final int xOffset;
118+
private final int yOffset;
119+
private final int zOffset;
120+
121+
Direction(final String abbreviation, final int xOffset, final int yOffset, final int zOffset) {
122+
this.abbreviation = abbreviation;
123+
this.xOffset = xOffset;
124+
this.yOffset = yOffset;
125+
this.zOffset = zOffset;
126+
}
127+
128+
public static Direction forAbbreviation(final String abbreviation) {
129+
for (final var candidate : values()) {
130+
if (candidate.abbreviation.equalsIgnoreCase(abbreviation)) {
131+
return candidate;
132+
}
133+
}
134+
throw new IllegalArgumentException("Invalid direction: " + abbreviation);
135+
}
136+
137+
public Address travel(final Address from) {
138+
return new Address(from.x + xOffset, from.y + yOffset, from.z + zOffset);
139+
}
140+
141+
}
142+
143+
public static class Address {
144+
145+
private final int x;
146+
private final int y;
147+
private final int z;
148+
149+
public Address(final int x, final int y, final int z) {
150+
this.x = x;
151+
this.y = y;
152+
this.z = z;
153+
}
154+
155+
public int hashCode() {
156+
int retval = 0;
157+
retval = 31 * retval + x;
158+
retval = 31 * retval + y;
159+
retval = 31 * retval + z;
160+
return retval;
161+
}
162+
163+
public boolean equals(final Object o) {
164+
if (this == o) {
165+
return true;
166+
} else if (o == null) {
167+
return false;
168+
}
169+
try {
170+
final Address other = (Address) o;
171+
return x == other.x && y == other.y && z == other.z;
172+
} catch (final ClassCastException cce) {
173+
return false;
174+
}
175+
}
176+
177+
}
178+
179+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy