Skip to content

Commit d68c131

Browse files
committed
[2023] Solution for day 8
1 parent e618ba3 commit d68c131

File tree

7 files changed

+995
-1
lines changed

7 files changed

+995
-1
lines changed

2023/day08/README.md

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# Day 8: Haunted Wasteland
2+
3+
[https://adventofcode.com/2023/day/8](https://adventofcode.com/2023/day/8)
4+
5+
## Description
6+
7+
### Part One
8+
9+
You're still riding a camel across Desert Island when you spot a sandstorm quickly approaching. When you turn to warn the Elf, she disappears before your eyes! To be fair, she had just finished warning you about _ghosts_ a few minutes ago.
10+
11+
One of the camel's pouches is labeled "maps" - sure enough, it's full of documents (your puzzle input) about how to navigate the desert. At least, you're pretty sure that's what they are; one of the documents contains a list of left/right instructions, and the rest of the documents seem to describe some kind of _network_ of labeled nodes.
12+
13+
It seems like you're meant to use the _left/right_ instructions to _navigate the network_. Perhaps if you have the camel follow the same instructions, you can escape the haunted wasteland!
14+
15+
After examining the maps for a bit, two nodes stick out: `AAA` and `ZZZ`. You feel like `AAA` is where you are now, and you have to follow the left/right instructions until you reach `ZZZ`.
16+
17+
This format defines each _node_ of the network individually. For example:
18+
19+
RL
20+
21+
AAA = (BBB, CCC)
22+
BBB = (DDD, EEE)
23+
CCC = (ZZZ, GGG)
24+
DDD = (DDD, DDD)
25+
EEE = (EEE, EEE)
26+
GGG = (GGG, GGG)
27+
ZZZ = (ZZZ, ZZZ)
28+
29+
30+
Starting with `AAA`, you need to _look up the next element_ based on the next left/right instruction in your input. In this example, start with `AAA` and go _right_ (`R`) by choosing the right element of `AAA`, _`CCC`_. Then, `L` means to choose the _left_ element of `CCC`, _`ZZZ`_. By following the left/right instructions, you reach `ZZZ` in _`2`_ steps.
31+
32+
Of course, you might not find `ZZZ` right away. If you run out of left/right instructions, repeat the whole sequence of instructions as necessary: `RL` really means `RLRLRLRLRLRLRLRL...` and so on. For example, here is a situation that takes _`6`_ steps to reach `ZZZ`:
33+
34+
LLR
35+
36+
AAA = (BBB, BBB)
37+
BBB = (AAA, ZZZ)
38+
ZZZ = (ZZZ, ZZZ)
39+
40+
41+
Starting at `AAA`, follow the left/right instructions. _How many steps are required to reach `ZZZ`?_
42+
43+
### Part Two
44+
45+
The <span title="Duhduhduhduhduh! Dah, duhduhduhduhduh!">sandstorm</span> is upon you and you aren't any closer to escaping the wasteland. You had the camel follow the instructions, but you've barely left your starting position. It's going to take _significantly more steps_ to escape!
46+
47+
What if the map isn't for people - what if the map is for _ghosts_? Are ghosts even bound by the laws of spacetime? Only one way to find out.
48+
49+
After examining the maps a bit longer, your attention is drawn to a curious fact: the number of nodes with names ending in `A` is equal to the number ending in `Z`! If you were a ghost, you'd probably just _start at every node that ends with `A`_ and follow all of the paths at the same time until they all simultaneously end up at nodes that end with `Z`.
50+
51+
For example:
52+
53+
LR
54+
55+
11A = (11B, XXX)
56+
11B = (XXX, 11Z)
57+
11Z = (11B, XXX)
58+
22A = (22B, XXX)
59+
22B = (22C, 22C)
60+
22C = (22Z, 22Z)
61+
22Z = (22B, 22B)
62+
XXX = (XXX, XXX)
63+
64+
65+
Here, there are two starting nodes, `11A` and `22A` (because they both end with `A`). As you follow each left/right instruction, use that instruction to _simultaneously_ navigate away from both nodes you're currently on. Repeat this process until _all_ of the nodes you're currently on end with `Z`. (If only some of the nodes you're on end with `Z`, they act like any other node and you continue as normal.) In this example, you would proceed as follows:
66+
67+
* Step 0: You are at `11A` and `22A`.
68+
* Step 1: You choose all of the _left_ paths, leading you to `11B` and `22B`.
69+
* Step 2: You choose all of the _right_ paths, leading you to _`11Z`_ and `22C`.
70+
* Step 3: You choose all of the _left_ paths, leading you to `11B` and _`22Z`_.
71+
* Step 4: You choose all of the _right_ paths, leading you to _`11Z`_ and `22B`.
72+
* Step 5: You choose all of the _left_ paths, leading you to `11B` and `22C`.
73+
* Step 6: You choose all of the _right_ paths, leading you to _`11Z`_ and _`22Z`_.
74+
75+
So, in this example, you end up entirely on nodes that end in `Z` after _`6`_ steps.
76+
77+
Simultaneously start on every node that ends with `A`. _How many steps does it take before you're only on nodes that end with `Z`?_

2023/day08/build.gradle.kts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
plugins {
2+
id("com.github.kfarnung.adventofcode.aoc2023.java-application-conventions")
3+
}
4+
5+
dependencies {
6+
implementation(project(":utilities"))
7+
}
8+
9+
application {
10+
mainClass.set("com.github.kfarnung.adventofcode.aoc2023.day08.App")
11+
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/*
2+
* Solution for Advent of Code 2023 day 8.
3+
*/
4+
package com.github.kfarnung.adventofcode.aoc2023.day08;
5+
6+
7+
import java.io.IOException;
8+
import java.util.ArrayList;
9+
import java.util.HashMap;
10+
import java.util.List;
11+
import java.util.Map;
12+
13+
import static com.github.kfarnung.adventofcode.aoc2023.utilities.InputUtils.readLinesFromFile;
14+
import static com.github.kfarnung.adventofcode.aoc2023.utilities.MathUtils.leastCommonMultiple;
15+
16+
public class App {
17+
public static void main(String[] args) {
18+
try {
19+
List<String> lines = readLinesFromFile(args[0]);
20+
System.out.printf("Part 1: %s%n", getPart1(lines));
21+
System.out.printf("Part 2: %s%n", getPart2(lines));
22+
} catch (IOException e) {
23+
e.printStackTrace();
24+
}
25+
}
26+
27+
public static String getPart1(List<String> lines) {
28+
char[] directions = lines.get(0).toCharArray();
29+
Map<String, String[]> map = new HashMap<>();
30+
for (int i = 2; i < lines.size(); i++) {
31+
String[] parts = lines.get(i).split(" = ");
32+
String[] values = parts[1].substring(1, parts[1].length() - 1).split(", ");
33+
map.put(parts[0], values);
34+
}
35+
36+
long count = 0;
37+
int directionsIndex = 0;
38+
String current = "AAA";
39+
while (!current.equals("ZZZ")) {
40+
String[] values = map.get(current);
41+
if (directions[directionsIndex] == 'L') {
42+
current = values[0];
43+
} else {
44+
current = values[1];
45+
}
46+
directionsIndex = (directionsIndex + 1) % directions.length;
47+
count++;
48+
}
49+
50+
return Long.toString(count);
51+
}
52+
53+
public static String getPart2(List<String> lines) {
54+
char[] directions = lines.get(0).toCharArray();
55+
Map<String, String[]> map = new HashMap<>();
56+
List<String> currentNodes = new ArrayList<>();
57+
for (int i = 2; i < lines.size(); i++) {
58+
String[] parts = lines.get(i).split(" = ");
59+
String[] values = parts[1].substring(1, parts[1].length() - 1).split(", ");
60+
map.put(parts[0], values);
61+
if (parts[0].endsWith("A")) {
62+
currentNodes.add(parts[0]);
63+
}
64+
}
65+
66+
long count = 1;
67+
for (String current : currentNodes) {
68+
count = leastCommonMultiple(count, findCycle(map, current, directions));
69+
}
70+
71+
return Long.toString(count);
72+
}
73+
74+
private static long findCycle(Map<String, String[]> map, String current, char[] directions) {
75+
Map<String, Long> stateMap = new HashMap<>();
76+
long count = 0;
77+
int directionsIndex = 0;
78+
while (!stateMap.containsKey(current + ":" + directionsIndex)) {
79+
stateMap.put(current + ":" + directionsIndex, count);
80+
String[] values = map.get(current);
81+
if (directions[directionsIndex] == 'L') {
82+
current = values[0];
83+
} else {
84+
current = values[1];
85+
}
86+
directionsIndex = (directionsIndex + 1) % directions.length;
87+
count++;
88+
}
89+
90+
return count - stateMap.get(current + ":" + directionsIndex);
91+
}
92+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Test cases for Advent of Code 2023 day 8.
3+
*/
4+
package com.github.kfarnung.adventofcode.aoc2023.day08;
5+
6+
import static com.github.kfarnung.adventofcode.aoc2023.utilities.InputUtils.readLinesFromResources;
7+
import static org.junit.jupiter.api.Assertions.assertEquals;
8+
9+
import java.io.IOException;
10+
import java.util.List;
11+
12+
import org.junit.jupiter.api.Test;
13+
14+
class AppTest {
15+
private final List<String> input = List.of(
16+
"RL",
17+
"",
18+
"AAA = (BBB, CCC)",
19+
"BBB = (DDD, EEE)",
20+
"CCC = (ZZZ, GGG)",
21+
"DDD = (DDD, DDD)",
22+
"EEE = (EEE, EEE)",
23+
"GGG = (GGG, GGG)",
24+
"ZZZ = (ZZZ, ZZZ)");
25+
private final List<String> input2 = List.of(
26+
"LLR",
27+
"",
28+
"AAA = (BBB, BBB)",
29+
"BBB = (AAA, ZZZ)",
30+
"ZZZ = (ZZZ, ZZZ)");
31+
private final List<String> input3 = List.of(
32+
"LR",
33+
"",
34+
"11A = (11B, XXX)",
35+
"11B = (XXX, 11Z)",
36+
"11Z = (11B, XXX)",
37+
"22A = (22B, XXX)",
38+
"22B = (22C, 22C)",
39+
"22C = (22Z, 22Z)",
40+
"22Z = (22B, 22B)",
41+
"XXX = (XXX, XXX)");
42+
43+
@Test
44+
void testGetPart1() throws IOException {
45+
assertEquals("2", App.getPart1(input));
46+
assertEquals("6", App.getPart1(input2));
47+
48+
List<String> realInput = readLinesFromResources(this, "input.txt");
49+
assertEquals("13207", App.getPart1(realInput));
50+
}
51+
52+
@Test
53+
void testGetPart2() throws IOException {
54+
assertEquals("6", App.getPart2(input3));
55+
56+
List<String> realInput = readLinesFromResources(this, "input.txt");
57+
assertEquals("12324145107121", App.getPart2(realInput));
58+
}
59+
}

0 commit comments

Comments
 (0)