1
+ import groovy.transform.TupleConstructor ;
2
+
3
+
4
+ def input = new File (" input/day03.txt" ). readLines();
5
+
6
+ @TupleConstructor
7
+ class PartNumber {
8
+ Schematic schematic;
9
+ int x;
10
+ int y;
11
+ int len;
12
+ int value;
13
+
14
+ boolean isValid () {
15
+ int x0 = Math . max(0 , x - 1 );
16
+ int x1 = Math . min(schematic. width - 1 , x + len + 1 );
17
+ int y0 = Math . max(0 , y - 1 );
18
+ int y1 = Math . min(schematic. height - 1 , y + 1 );
19
+ for (int j in y0.. y1) {
20
+ for (int i in x0.. x1) {
21
+ char c = schematic. get(i, j);
22
+ if (! c. isDigit() && c != ' .' ) {
23
+ return true ;
24
+ }
25
+ }
26
+ }
27
+
28
+ return false ;
29
+ }
30
+
31
+ boolean includes (int px , int py ) {
32
+ int x0 = Math . max(0 , x - 1 );
33
+ int x1 = Math . min(schematic. width - 1 , x + len + 1 );
34
+ int y0 = Math . max(0 , y - 1 );
35
+ int y1 = Math . min(schematic. height - 1 , y + 1 );
36
+
37
+ return x0 <= px && px <= x1 && y0 <= py && py <= y1;
38
+ }
39
+
40
+ String toString () {
41
+ int x0 = Math . max(0 , x - 1 );
42
+ int x1 = Math . min(schematic. width - 1 , x + len + 1 );
43
+ int y0 = Math . max(0 , y - 1 );
44
+ int y1 = Math . min(schematic. height - 1 , y + 1 );
45
+
46
+ def result = " " ;
47
+ for (int j in y0.. y1) {
48
+ for (int i in x0.. x1) {
49
+ result + = schematic. get(i, j);
50
+ }
51
+ result + = " \n " ;
52
+ }
53
+ return result;
54
+ }
55
+ }
56
+
57
+ class Schematic {
58
+ private final char [] arr;
59
+ final int width;
60
+ final int height;
61
+
62
+ private def partNumbersCache;
63
+
64
+ Schematic (List<String > input ) {
65
+ arr = input. join(" " ). toCharArray();
66
+ width = input[0 ]. size();
67
+ height = input. size();
68
+ }
69
+
70
+ def get (int x , int y ) {
71
+ int pos = x + y * width;
72
+ return arr[pos];
73
+ }
74
+
75
+ def getPartNumbers () {
76
+ if (partNumbersCache != null ) {
77
+ return partNumbersCache;
78
+ }
79
+
80
+ def result = [];
81
+
82
+ def numberIndices = arr. findIndexValues { it. isDigit() };
83
+
84
+ int pnStart = numberIndices[0 ];
85
+ int curr, next;
86
+ for (int i = 0 ; i < numberIndices. size(); i++ ) {
87
+ curr = numberIndices[i];
88
+ next = numberIndices[i + 1 ] ?: -1 ;
89
+ if (next - curr == 1 ) {
90
+ continue ;
91
+ }
92
+
93
+ int pnX = pnStart % width;
94
+ int pnY = Math . floor(pnStart / width);
95
+ def pnEnd = curr;
96
+ def pnLength = pnEnd - pnStart;
97
+ result << new PartNumber (this , pnX, pnY, pnLength, arr[pnStart.. pnEnd]. join(" " ). toInteger());
98
+
99
+ pnStart = next;
100
+ }
101
+
102
+ partNumbersCache = result;
103
+ return result;
104
+ }
105
+
106
+ def getGears () {
107
+ def gearIndices = arr. findIndexValues { it == ' *' };
108
+ return gearIndices. collect {
109
+ int gX = it % width;
110
+ int gY = Math . floor(it / width);
111
+ return getPartNumbers(). findAll { pn ->
112
+ return pn. includes(gX, gY);
113
+ };
114
+ }. findAll { pnc -> pnc. size() == 2 };
115
+ }
116
+
117
+ String toString () {
118
+ def result = " " ;
119
+ for (int y = 0 ; y < height; y++ ) {
120
+ for (int x = 0 ; x < width; x++ ) {
121
+ result + = this . get(x, y);
122
+ }
123
+ result + = " \n " ;
124
+ }
125
+ return result;
126
+ }
127
+ }
128
+
129
+ def schematic = new Schematic (input);
130
+
131
+ def partNumberSum = schematic. getPartNumbers(). inject(0 ) { acc , it ->
132
+ return it. isValid() ? acc + it. value : acc;
133
+ };
134
+ println (partNumberSum);
135
+
136
+ def gearRatioSum = schematic. getGears(). inject(0 ) { acc , it ->
137
+ return acc + (it[0 ]. value * it[1 ]. value);
138
+ };
139
+ println (gearRatioSum);
0 commit comments