Skip to content

Commit

Permalink
Day 08 - Done
Browse files Browse the repository at this point in the history
  • Loading branch information
kocmana committed Dec 25, 2023
1 parent ba2b935 commit 4cacf8f
Show file tree
Hide file tree
Showing 9 changed files with 949 additions and 2 deletions.
4 changes: 3 additions & 1 deletion README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Solutions for the https://adventofcode.com/2023/:[advent of code] of 2023.
|05| |
|06|👍|👍
|07| |
|08| |
|08|👍|👍*
|09| |
|10| |
|11| |
Expand All @@ -48,3 +48,5 @@ Solutions for the https://adventofcode.com/2023/:[advent of code] of 2023.
|23| |
|24| |
|===

__* read up on better solutions before commiting__
5 changes: 5 additions & 0 deletions src/main/java/at/kocmana/aoc23/dec08/Direction.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package at.kocmana.aoc23.dec08;

public enum Direction {
L, R
}
76 changes: 76 additions & 0 deletions src/main/java/at/kocmana/aoc23/dec08/HauntedWastelandPartOne.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package at.kocmana.aoc23.dec08;

import at.kocmana.aoc23.common.ResourceToString;
import at.kocmana.aoc23.common.Tuple;
import java.util.AbstractMap;
import java.util.Map;
import java.util.regex.MatchResult;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

public class HauntedWastelandPartOne {

static final Pattern NETWORK_ENTRY_PATTERN =
Pattern.compile("(?<source>[A-Z]{3}) = \\((?<left>[A-Z]{3}), (?<right>[A-Z]{3})\\)");

public static void main(String[] args) {
var puzzleInput = ResourceToString.from("dec08", "HauntedWasteland.txt");
var map = parseMap(puzzleInput);
var result = traverse(map);
System.out.printf("Result: %d%n", result);
}

static int traverse(WastelandMap map) {
var directions = map.directions();
var network = map.network();

var numberOfSteps = 0;
var currentNode = "AAA";
while (!currentNode.equals("ZZZ")) {
var currentDirection = directions.get(numberOfSteps % directions.size());
System.out.printf("Step %d. Current Node: %s, Possible Directions: %s, Next Move: %s%n",
numberOfSteps, currentNode, network.get(currentNode), currentDirection);
currentNode = network.get(currentNode).move(currentDirection);
numberOfSteps++;
}
return numberOfSteps;
}

public static WastelandMap parseMap(String input) {
var directionsAndNetwork = input.split("\\n", 3);

var directions = directionsAndNetwork[0].chars()
.mapToObj(c -> Direction.valueOf(String.valueOf((char) c)))
.toList();

var network = directionsAndNetwork[2].lines()
.map(NETWORK_ENTRY_PATTERN::matcher)
.flatMap(Matcher::results)
.map(HauntedWastelandPartOne::toNetworkNode)
.collect(Collectors.toMap(Tuple::key, Tuple::value));

return new WastelandMap(directions, network);
}

static Tuple<String, Node> toNetworkNode(MatchResult matchResult) {
return new Tuple<String, Node>(
matchResult.group("source"),
new Node(matchResult.group("left"), matchResult.group("right")));
}

static Map.Entry<String, Node> toMapEntry(String input) {
System.out.printf("Parsing input: %s%n", input);
var result = NETWORK_ENTRY_PATTERN.matcher(input);

return new AbstractMap.SimpleImmutableEntry<>(
result.group("source"),
new Node(
result.group("left"),
result.group("right")
)
);
}


}
100 changes: 100 additions & 0 deletions src/main/java/at/kocmana/aoc23/dec08/HauntedWastelandPartTwo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package at.kocmana.aoc23.dec08;

import at.kocmana.aoc23.common.ResourceToString;
import at.kocmana.aoc23.common.Tuple;
import java.util.AbstractMap;
import java.util.List;
import java.util.Map;
import java.util.regex.MatchResult;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

public class HauntedWastelandPartTwo {

static final Pattern NETWORK_ENTRY_PATTERN =
Pattern.compile("(?<source>[A-Z]{3}) = \\((?<left>[A-Z]{3}), (?<right>[A-Z]{3})\\)");

public static void main(String[] args) {
var puzzleInput = ResourceToString.from("dec08", "HauntedWasteland.txt");
var map = parseMap(puzzleInput);
var result = play(map);
System.out.printf("Result: %d%n", result);
}

static Long play(WastelandMap map) {
return traverse(map);
}

static Long traverse(WastelandMap map) {
var currentNodes = map.network().keySet().stream()
.filter(node -> node.endsWith("A"))
.map(node -> HauntedWastelandPartTwo.traversePerNode(map, node))
.toList();

return lcm(currentNodes);
}

static Long traversePerNode(WastelandMap map, String startNode) {
var directions = map.directions();
var network = map.network();

var numberOfSteps = 0L;
var currentNode = startNode;
while (!currentNode.endsWith("Z")) {
var currentDirection = directions.get((int) numberOfSteps % directions.size());
currentNode = network.get(currentNode).move(currentDirection);
numberOfSteps++;
}
return numberOfSteps;
}

/* LCM Solution for n numbers taken from
https://stackoverflow.com/questions/4201860/how-to-find-gcd-lcm-on-a-set-of-numbers
*/
private static long gcd(long x, long y) {
return (y == 0) ? x : gcd(y, x % y);
}

private static long lcm(List<Long> numbers) {
return numbers.stream()
.reduce(1L, (x, y) -> x * (y / gcd(x, y)));
}

public static WastelandMap parseMap(String input) {
var directionsAndNetwork = input.split("\\n", 3);

var directions = directionsAndNetwork[0].chars()
.mapToObj(c -> Direction.valueOf(String.valueOf((char) c)))
.toList();

var network = directionsAndNetwork[2].lines()
.map(NETWORK_ENTRY_PATTERN::matcher)
.flatMap(Matcher::results)
.map(HauntedWastelandPartTwo::toNetworkNode)
.collect(Collectors.toMap(Tuple::key, Tuple::value));

return new WastelandMap(directions, network);
}

static Tuple<String, Node> toNetworkNode(MatchResult matchResult) {
return new Tuple<String, Node>(
matchResult.group("source"),
new Node(matchResult.group("left"), matchResult.group("right")));
}

static Map.Entry<String, Node> toMapEntry(String input) {
System.out.printf("Parsing input: %s%n", input);
var result = NETWORK_ENTRY_PATTERN.matcher(input);

return new AbstractMap.SimpleImmutableEntry<>(
result.group("source"),
new Node(
result.group("left"),
result.group("right")
)
);
}


}
15 changes: 15 additions & 0 deletions src/main/java/at/kocmana/aoc23/dec08/Node.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package at.kocmana.aoc23.dec08;

public record Node (
String left,
String right
) {

String move(Direction direction) {
return switch (direction) {
case L -> left;
case R -> right;
};
}

}
9 changes: 9 additions & 0 deletions src/main/java/at/kocmana/aoc23/dec08/WastelandMap.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package at.kocmana.aoc23.dec08;

import java.util.List;
import java.util.Map;

public record WastelandMap(
List<Direction> directions,
Map<String, Node> network
) {}
Loading

0 comments on commit 4cacf8f

Please sign in to comment.