|
2 | 2 |
|
3 | 3 | import com.sbaars.adventofcode.year17.Day2017;
|
4 | 4 | import java.util.*;
|
5 | | -import java.util.regex.*; |
| 5 | +import java.util.regex.Matcher; |
| 6 | +import java.util.regex.Pattern; |
6 | 7 |
|
7 | 8 | public class Day25 extends Day2017 {
|
8 | | - private enum Direction { LEFT, RIGHT } |
9 | | - |
10 | | - private static class Rule { |
11 | | - final int writeValue; |
12 | | - final Direction moveDirection; |
13 | | - final char nextState; |
14 | | - |
15 | | - Rule(int writeValue, Direction moveDirection, char nextState) { |
16 | | - this.writeValue = writeValue; |
17 | | - this.moveDirection = moveDirection; |
18 | | - this.nextState = nextState; |
19 | | - } |
20 | | - } |
21 | | - |
22 | | - private final Map<Character, Map<Integer, Rule>> states = new HashMap<>(); |
23 | | - private final char initialState; |
24 | | - private final int steps; |
25 | | - |
| 9 | + private record StateRule(int writeValue, int moveDirection, char nextState) {} |
| 10 | + private record State(StateRule zeroRule, StateRule oneRule) {} |
| 11 | + |
26 | 12 | public Day25() {
|
27 | 13 | super(25);
|
28 | | - List<String> input = dayStream().toList(); |
29 | | - initialState = input.get(0).charAt(15); |
30 | | - steps = Integer.parseInt(input.get(1).replaceAll("\\D+", "")); |
| 14 | + } |
| 15 | + |
| 16 | + public static void main(String[] args) { |
| 17 | + new Day25().printParts(); |
| 18 | + } |
| 19 | + |
| 20 | + private Map<Character, State> parseStates() { |
| 21 | + String[] lines = dayStrings(); |
| 22 | + Map<Character, State> states = new HashMap<>(); |
31 | 23 |
|
32 | | - for (int i = 3; i < input.size(); i++) { |
33 | | - if (input.get(i).startsWith("In state")) { |
34 | | - char state = input.get(i).charAt(9); |
35 | | - Map<Integer, Rule> stateRules = new HashMap<>(); |
36 | | - |
| 24 | + Pattern statePattern = Pattern.compile("In state ([A-Z]):"); |
| 25 | + Pattern valuePattern = Pattern.compile("If the current value is ([01]):"); |
| 26 | + Pattern writePattern = Pattern.compile("- Write the value ([01])."); |
| 27 | + Pattern movePattern = Pattern.compile("- Move one slot to the (right|left)."); |
| 28 | + Pattern nextPattern = Pattern.compile("- Continue with state ([A-Z])."); |
| 29 | + |
| 30 | + int i = 2; // Skip first two lines |
| 31 | + while (i < lines.length) { |
| 32 | + if (lines[i].trim().isEmpty()) { |
| 33 | + i++; |
| 34 | + continue; |
| 35 | + } |
| 36 | + |
| 37 | + Matcher stateMatcher = statePattern.matcher(lines[i]); |
| 38 | + if (stateMatcher.find()) { |
| 39 | + char stateName = stateMatcher.group(1).charAt(0); |
| 40 | + StateRule[] rules = new StateRule[2]; |
| 41 | + |
37 | 42 | for (int value = 0; value <= 1; value++) {
|
38 | | - i += 2; |
39 | | - int writeValue = Character.getNumericValue(input.get(i).charAt(input.get(i).length() - 2)); |
40 | 43 | i++;
|
41 | | - Direction direction = input.get(i).contains("right") ? Direction.RIGHT : Direction.LEFT; |
| 44 | + Matcher valueMatcher = valuePattern.matcher(lines[i]); |
| 45 | + if (!valueMatcher.find() || Integer.parseInt(valueMatcher.group(1)) != value) { |
| 46 | + throw new IllegalStateException("Invalid value line: " + lines[i]); |
| 47 | + } |
| 48 | + |
| 49 | + i++; |
| 50 | + Matcher writeMatcher = writePattern.matcher(lines[i]); |
| 51 | + if (!writeMatcher.find()) { |
| 52 | + throw new IllegalStateException("Invalid write line: " + lines[i]); |
| 53 | + } |
| 54 | + int writeValue = Integer.parseInt(writeMatcher.group(1)); |
| 55 | + |
42 | 56 | i++;
|
43 | | - char nextState = input.get(i).charAt(input.get(i).length() - 2); |
44 | | - stateRules.put(value, new Rule(writeValue, direction, nextState)); |
| 57 | + Matcher moveMatcher = movePattern.matcher(lines[i]); |
| 58 | + if (!moveMatcher.find()) { |
| 59 | + throw new IllegalStateException("Invalid move line: " + lines[i]); |
| 60 | + } |
| 61 | + int moveDirection = moveMatcher.group(1).equals("right") ? 1 : -1; |
| 62 | + |
| 63 | + i++; |
| 64 | + Matcher nextMatcher = nextPattern.matcher(lines[i]); |
| 65 | + if (!nextMatcher.find()) { |
| 66 | + throw new IllegalStateException("Invalid next state line: " + lines[i]); |
| 67 | + } |
| 68 | + char nextState = nextMatcher.group(1).charAt(0); |
| 69 | + |
| 70 | + rules[value] = new StateRule(writeValue, moveDirection, nextState); |
45 | 71 | }
|
46 | | - |
47 | | - states.put(state, stateRules); |
| 72 | + |
| 73 | + states.put(stateName, new State(rules[0], rules[1])); |
| 74 | + i++; |
| 75 | + } else { |
| 76 | + i++; |
48 | 77 | }
|
49 | 78 | }
|
| 79 | + |
| 80 | + return states; |
50 | 81 | }
|
51 | | - |
52 | | - public static void main(String[] args) { |
53 | | - new Day25().printParts(); |
| 82 | + |
| 83 | + private int getSteps() { |
| 84 | + String firstLine = dayStrings()[1]; |
| 85 | + Pattern stepsPattern = Pattern.compile("Perform a diagnostic checksum after (\\d+) steps."); |
| 86 | + Matcher stepsMatcher = stepsPattern.matcher(firstLine); |
| 87 | + if (!stepsMatcher.find()) { |
| 88 | + throw new IllegalStateException("Invalid steps line: " + firstLine); |
| 89 | + } |
| 90 | + return Integer.parseInt(stepsMatcher.group(1)); |
54 | 91 | }
|
55 | | - |
| 92 | + |
| 93 | + private char getInitialState() { |
| 94 | + String firstLine = dayStrings()[0]; |
| 95 | + Pattern statePattern = Pattern.compile("Begin in state ([A-Z])."); |
| 96 | + Matcher stateMatcher = statePattern.matcher(firstLine); |
| 97 | + if (!stateMatcher.find()) { |
| 98 | + throw new IllegalStateException("Invalid initial state line: " + firstLine); |
| 99 | + } |
| 100 | + return stateMatcher.group(1).charAt(0); |
| 101 | + } |
| 102 | + |
56 | 103 | @Override
|
57 | 104 | public Object part1() {
|
58 | | - Map<Integer, Integer> tape = new HashMap<>(); |
| 105 | + Map<Character, State> states = parseStates(); |
| 106 | + int steps = getSteps(); |
| 107 | + char currentState = getInitialState(); |
| 108 | + |
| 109 | + // Use a TreeSet to store positions of 1s (tape is infinite with 0s by default) |
| 110 | + Set<Integer> tape = new TreeSet<>(); |
59 | 111 | int cursor = 0;
|
60 | | - char currentState = initialState; |
61 | | - |
| 112 | + |
62 | 113 | for (int i = 0; i < steps; i++) {
|
63 | | - int currentValue = tape.getOrDefault(cursor, 0); |
64 | | - Rule rule = states.get(currentState).get(currentValue); |
65 | | - |
66 | | - tape.put(cursor, rule.writeValue); |
67 | | - cursor += (rule.moveDirection == Direction.RIGHT) ? 1 : -1; |
68 | | - currentState = rule.nextState; |
| 114 | + State state = states.get(currentState); |
| 115 | + boolean currentValue = tape.contains(cursor); |
| 116 | + StateRule rule = currentValue ? state.oneRule() : state.zeroRule(); |
| 117 | + |
| 118 | + if (rule.writeValue() == 1) { |
| 119 | + tape.add(cursor); |
| 120 | + } else { |
| 121 | + tape.remove(cursor); |
| 122 | + } |
| 123 | + |
| 124 | + cursor += rule.moveDirection(); |
| 125 | + currentState = rule.nextState(); |
69 | 126 | }
|
70 | | - |
71 | | - return tape.values().stream().mapToInt(Integer::intValue).sum(); |
| 127 | + |
| 128 | + return tape.size(); |
72 | 129 | }
|
73 | | - |
| 130 | + |
74 | 131 | @Override
|
75 | 132 | public Object part2() {
|
| 133 | + // Part 2 is automatically solved by collecting all stars |
76 | 134 | return "Merry Christmas!";
|
77 | 135 | }
|
78 | 136 | }
|
0 commit comments