1
+ package com .macasaet ;
2
+
3
+ import java .util .ArrayList ;
4
+ import java .util .LinkedList ;
5
+ import java .util .List ;
6
+ import java .util .stream .Stream ;
7
+ import java .util .stream .StreamSupport ;
8
+
9
+ import org .junit .jupiter .api .Test ;
10
+
11
+ /**
12
+ * --- Day 10: Syntax Scoring ---
13
+ */
14
+ public class Day10 {
15
+
16
+ protected Stream <String > getInput () {
17
+ return StreamSupport
18
+ .stream (new LineSpliterator ("day-10.txt" ),
19
+ false );
20
+ }
21
+
22
+ /**
23
+ * The type of open and closing delimiter for a chunk in the navigation subsystem
24
+ */
25
+ public enum BracketType {
26
+ PARENTHESIS ('(' , ')' , 3 , 1 ),
27
+ SQUARE ('[' , ']' , 57 , 2 ),
28
+ CURLY ('{' , '}' , 1197 , 3 ),
29
+ ANGLED ('<' , '>' , 25137 , 4 );
30
+
31
+ private final char open ;
32
+ private final char close ;
33
+ private final int corruptionPoints ;
34
+ private final int autocompletePoints ;
35
+
36
+ BracketType (char open , char close , int corruptionPoints , final int autocompletePoints ) {
37
+ this .open = open ;
38
+ this .close = close ;
39
+ this .corruptionPoints = corruptionPoints ;
40
+ this .autocompletePoints = autocompletePoints ;
41
+ }
42
+
43
+ public static BracketType forOpen (final char c ) {
44
+ return switch (c ) {
45
+ case '(' -> PARENTHESIS ;
46
+ case '[' -> SQUARE ;
47
+ case '{' -> CURLY ;
48
+ case '<' -> ANGLED ;
49
+ default -> throw new IllegalStateException ("Unexpected value: " + c );
50
+ };
51
+ }
52
+
53
+ public static BracketType forClose (final char c ) {
54
+ return switch (c ) {
55
+ case ')' -> PARENTHESIS ;
56
+ case ']' -> SQUARE ;
57
+ case '}' -> CURLY ;
58
+ case '>' -> ANGLED ;
59
+ default -> throw new IllegalStateException ("Unexpected value: " + c );
60
+ };
61
+ }
62
+ }
63
+
64
+ /**
65
+ * @param line a line in the navigation subsystem
66
+ * @return a score of how corrupt the line is. A score of zero means it is not corrupt. The higher the value, the
67
+ * more corrupt the line is.
68
+ */
69
+ public int calculateCorruptionScore (final char [] line ) {
70
+ final var stack = new LinkedList <BracketType >();
71
+ for (int i = 0 ; i < line .length ; i ++) {
72
+ final var c = line [i ];
73
+ if (c == '(' || c == '[' || c == '{' || c == '<' ) {
74
+ stack .push (BracketType .forOpen (c ));
75
+ } else if (c == ')' || c == ']' || c == '}' || c == '>' ) {
76
+ if (stack .peek ().close == c ) {
77
+ stack .pop ();
78
+ } else {
79
+ // corrupt
80
+ return BracketType .forClose (c ).corruptionPoints ;
81
+ }
82
+ }
83
+ }
84
+ // if stack is not empty, it's incomplete
85
+ return 0 ;
86
+ }
87
+
88
+ /**
89
+ * @param line a non-corrupt line in the navigation subsystem. Behaviour is undefined for corrupt lines.
90
+ * @return the score for the suffix required to complete the line
91
+ */
92
+ public long calculateCompletionScore (final char [] line ) {
93
+ final var stack = new LinkedList <BracketType >();
94
+ for (int i = 0 ; i < line .length ; i ++) {
95
+ final var c = line [i ];
96
+ if (c == '(' || c == '[' || c == '{' || c == '<' ) {
97
+ stack .push (BracketType .forOpen (c ));
98
+ } else if (c == ')' || c == ']' || c == '}' || c == '>' ) {
99
+ if (stack .peek ().close == c ) {
100
+ stack .pop ();
101
+ } else {
102
+ throw new IllegalArgumentException ("Corrupt: " + new String (line ));
103
+ }
104
+ }
105
+ }
106
+ long result = 0 ;
107
+ while (!stack .isEmpty ()) {
108
+ final var unclosed = stack .pop ();
109
+ result = result * 5 + unclosed .autocompletePoints ;
110
+ }
111
+ return result ;
112
+ }
113
+
114
+ @ Test
115
+ public final void part1 () {
116
+ final var result = getInput ()
117
+ .map (String ::toCharArray )
118
+ .filter (line -> line .length > 0 )
119
+ .mapToInt (this ::calculateCorruptionScore )
120
+ .sum ();
121
+ System .out .println ("Part 1: " + result );
122
+ }
123
+
124
+ @ Test
125
+ public final void part2 () {
126
+ final var list = getInput ()
127
+ .map (String ::toCharArray )
128
+ .filter (line -> line .length > 0 )
129
+ .filter (line -> calculateCorruptionScore (line ) <= 0 ) // discard corrupted lines
130
+ .mapToLong (this ::calculateCompletionScore )
131
+ .sorted ()
132
+ .collect (ArrayList <Long >::new , List ::add , List ::addAll );
133
+ final var result = list .get (list .size () / 2 );
134
+ System .out .println ("Part 2: " + result );
135
+ }
136
+
137
+ }
0 commit comments