Skip to content

Commit 698a08a

Browse files
committed
Add day 22 solution
1 parent febb35f commit 698a08a

20 files changed

+999
-0
lines changed
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package eu.happycoders.adventofcode2022.day22;
2+
3+
import java.util.Arrays;
4+
5+
/**
6+
* Advent of Code 2022 – Object-Oriented Solutions in Java.
7+
*
8+
* <p>A map of the board with its open tiles and walls.
9+
*
10+
* <p>This board uses 0-based coordinates, that makes all position calculation much easier.
11+
*
12+
* @author <a href="mailto:sven@happycoders.eu">Sven Woltmann</a>
13+
*/
14+
class BoardMap {
15+
16+
private final int width;
17+
private final int height;
18+
19+
// With a board size of 150 x 200 = 30000,
20+
// we don't need to optimize for size and can easily use an enum to store a tile.
21+
private final Tile[][] tiles;
22+
23+
BoardMap(int width, int height) {
24+
this.width = width;
25+
this.height = height;
26+
this.tiles = new Tile[height][width];
27+
}
28+
29+
int width() {
30+
return width;
31+
}
32+
33+
int height() {
34+
return height;
35+
}
36+
37+
// Internally, we work with 0-based coordinates, that makes all position calculation much easier.
38+
void setTile(Position position, Tile tile) {
39+
tiles[position.row()][position.column()] = tile;
40+
}
41+
42+
// Internally, we work with 0-based coordinates, that makes all position calculation much easier.
43+
Tile getTile(Position position) {
44+
return tiles[position.row()][position.column()];
45+
}
46+
47+
Position findStartPosition() {
48+
// "leftmost open tile of the top row of tiles"
49+
for (int column = 0; column < width; column++) {
50+
Position position = new Position(column, 0);
51+
if (getTile(position) == Tile.OPEN) {
52+
return position;
53+
}
54+
}
55+
throw new IllegalStateException();
56+
}
57+
58+
@Override
59+
public boolean equals(Object object) {
60+
if (this == object) {
61+
return true;
62+
}
63+
64+
if (object == null || getClass() != object.getClass()) {
65+
return false;
66+
}
67+
68+
BoardMap that = (BoardMap) object;
69+
return Arrays.deepEquals(tiles, that.tiles);
70+
}
71+
72+
@Override
73+
public int hashCode() {
74+
return Arrays.deepHashCode(tiles);
75+
}
76+
77+
@Override
78+
public String toString() {
79+
StringBuilder result = new StringBuilder();
80+
81+
for (int row = 0; row < height; row++) {
82+
for (int column = 0; column < width; column++) {
83+
Tile tile = tiles[row][column];
84+
result.append(tile == null ? ' ' : tile.symbol());
85+
}
86+
result.append('\n');
87+
}
88+
89+
return result.toString();
90+
}
91+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package eu.happycoders.adventofcode2022.day22;
2+
3+
/**
4+
* Advent of Code 2022 – Object-Oriented Solutions in Java.
5+
*
6+
* <p>Coordinates on a cube face.
7+
*
8+
* @author <a href="mailto:sven@happycoders.eu">Sven Woltmann</a>
9+
*/
10+
record CubeFaceCoordinates(int faceId, int sideLength, Position position) {
11+
12+
CubeFaceCoordinates transportTo(WormholeCoordinates target, Direction sourceDirection) {
13+
int numberClockwiseTurns = (target.side().ordinal() - sourceDirection.ordinal() + 6) % 4;
14+
15+
Position newPosition = turnPositionOnCubeFace(numberClockwiseTurns);
16+
17+
newPosition = mirrorPositionOnCubeFace(newPosition, target);
18+
19+
return new CubeFaceCoordinates(target.cubeFaceId(), sideLength, newPosition);
20+
}
21+
22+
private Position turnPositionOnCubeFace(int numberClockwiseTurns) {
23+
return switch (numberClockwiseTurns) {
24+
case 0 -> new Position(position.column(), position.row());
25+
case 1 -> new Position(flip(position.row()), position.column());
26+
case 2 -> new Position(flip(position.column()), flip(position.row()));
27+
case 3 -> new Position(position.row(), flip(position.column()));
28+
default -> throw new IllegalStateException();
29+
};
30+
}
31+
32+
private Position mirrorPositionOnCubeFace(Position newPosition, WormholeCoordinates target) {
33+
return switch (target.side()) {
34+
case LEFT, RIGHT -> new Position(flip(newPosition.column()), newPosition.row());
35+
case UP, DOWN -> new Position(newPosition.column(), flip(newPosition.row()));
36+
};
37+
}
38+
39+
private int flip(int newPosition) {
40+
return sideLength - 1 - newPosition;
41+
}
42+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package eu.happycoders.adventofcode2022.day22;
2+
3+
import java.util.HashMap;
4+
import java.util.List;
5+
import java.util.Map;
6+
7+
/**
8+
* Advent of Code 2022 – Object-Oriented Solutions in Java.
9+
*
10+
* <p>The logic for mapping the 3D cube to the 2D board map and vice-versa.
11+
*
12+
* @author <a href="mailto:sven@happycoders.eu">Sven Woltmann</a>
13+
*/
14+
class CubeLogic {
15+
16+
private final int cubeFaceLength;
17+
private final Map<WormholeCoordinates, WormholeCoordinates> wormholeMap;
18+
19+
CubeLogic(int cubeFaceLength, List<Wormhole> wormholes) {
20+
this.cubeFaceLength = cubeFaceLength;
21+
22+
this.wormholeMap = new HashMap<>();
23+
for (Wormhole wormhole : wormholes) {
24+
this.wormholeMap.put(wormhole.start(), wormhole.end());
25+
this.wormholeMap.put(wormhole.end(), wormhole.start());
26+
}
27+
}
28+
29+
CubeFaceCoordinates toCubeFaceCoordinates(Position position, BoardMap boardMap) {
30+
int cubeFacesColumn = position.column() / cubeFaceLength;
31+
int cubeFacesRow = position.row() / cubeFaceLength;
32+
int horizontalCubes = boardMap.width() / cubeFaceLength;
33+
int cubeFaceId = cubeFacesRow * horizontalCubes + cubeFacesColumn;
34+
return new CubeFaceCoordinates(
35+
cubeFaceId,
36+
cubeFaceLength,
37+
new Position(
38+
position.column() - cubeFacesColumn * cubeFaceLength,
39+
position.row() - cubeFacesRow * cubeFaceLength));
40+
}
41+
42+
WormholeCoordinates findTransport(WormholeCoordinates startCoordinates) {
43+
return wormholeMap.get(startCoordinates);
44+
}
45+
46+
Position toBoardMapCoordinates(CubeFaceCoordinates cubeFaceCoordinates, BoardMap boardMap) {
47+
int horizontalCubes = boardMap.width() / cubeFaceLength;
48+
int offsetColumn = (cubeFaceCoordinates.faceId() % horizontalCubes) * cubeFaceLength;
49+
int offsetRow = (cubeFaceCoordinates.faceId() / horizontalCubes) * cubeFaceLength;
50+
int newColumn = offsetColumn + cubeFaceCoordinates.position().column();
51+
int newRow = offsetRow + cubeFaceCoordinates.position().row();
52+
return new Position(newColumn, newRow);
53+
}
54+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package eu.happycoders.adventofcode2022.day22;
2+
3+
/**
4+
* Advent of Code 2022 – Object-Oriented Solutions in Java.
5+
*
6+
* <p>Puzzle solver for day 22.
7+
*
8+
* @author <a href="mailto:sven@happycoders.eu">Sven Woltmann</a>
9+
*/
10+
class Day22Solver {
11+
12+
static int solveTask1(String input) {
13+
PuzzleInput puzzleInput = PuzzleInputParser.parse(input);
14+
InstructionExecutor instructionExecutor = new InstructionExecutor(puzzleInput.boardMap(), null);
15+
instructionExecutor.execute(puzzleInput.instructions());
16+
return instructionExecutor.calculateFinalPassword();
17+
}
18+
19+
static int solveTask2(String input, CubeLogic cubeLogic) {
20+
PuzzleInput puzzleInput = PuzzleInputParser.parse(input);
21+
InstructionExecutor instructionExecutor =
22+
new InstructionExecutor(puzzleInput.boardMap(), cubeLogic);
23+
instructionExecutor.execute(puzzleInput.instructions());
24+
return instructionExecutor.calculateFinalPassword();
25+
}
26+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package eu.happycoders.adventofcode2022.day22;
2+
3+
/**
4+
* Advent of Code 2022 – Object-Oriented Solutions in Java.
5+
*
6+
* <p>The direction into which you face/walk.
7+
*
8+
* @author <a href="mailto:sven@happycoders.eu">Sven Woltmann</a>
9+
*/
10+
enum Direction {
11+
RIGHT(0),
12+
DOWN(1),
13+
LEFT(2),
14+
UP(3);
15+
16+
private final int number;
17+
18+
Direction(int number) {
19+
this.number = number;
20+
}
21+
22+
int number() {
23+
return number;
24+
}
25+
26+
Direction clockwise() {
27+
int ordinal = (this.ordinal() + 1) % 4;
28+
return Direction.values()[ordinal];
29+
}
30+
31+
Direction counterClockwise() {
32+
// +3 instead of -1 so that the result of the remainder operation doesn't get negative
33+
int ordinal = (this.ordinal() + 3) % 4;
34+
return Direction.values()[ordinal];
35+
}
36+
37+
Direction flip() {
38+
return switch (this) {
39+
case RIGHT -> LEFT;
40+
case DOWN -> UP;
41+
case LEFT -> RIGHT;
42+
case UP -> DOWN;
43+
};
44+
}
45+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package eu.happycoders.adventofcode2022.day22;
2+
3+
/**
4+
* Advent of Code 2022 – Object-Oriented Solutions in Java.
5+
*
6+
* <p>The instruction to go forward a certain amount of tiles.
7+
*
8+
* @author <a href="mailto:sven@happycoders.eu">Sven Woltmann</a>
9+
*/
10+
record GoForward(int numberOfTiles) implements Instruction {
11+
12+
static GoForward tiles(int numberOfTiles) {
13+
return new GoForward(numberOfTiles);
14+
}
15+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package eu.happycoders.adventofcode2022.day22;
2+
3+
/**
4+
* Advent of Code 2022 – Object-Oriented Solutions in Java.
5+
*
6+
* <p>Interface for instructions.
7+
*
8+
* @author <a href="mailto:sven@happycoders.eu">Sven Woltmann</a>
9+
*/
10+
sealed interface Instruction permits GoForward, TurnClockwise, TurnCounterClockwise {}

0 commit comments

Comments
 (0)