1
+ package com .macasaet ;
2
+
3
+ import org .junit .jupiter .api .Test ;
4
+
5
+ import java .util .Set ;
6
+ import java .util .SortedMap ;
7
+ import java .util .TreeMap ;
8
+ import java .util .TreeSet ;
9
+ import java .util .stream .Stream ;
10
+ import java .util .stream .StreamSupport ;
11
+
12
+ /**
13
+ * --- Day 9: Rope Bridge ---
14
+ * <a href="https://adventofcode.com/2022/day/9">https://adventofcode.com/2022/day/9</a>
15
+ */
16
+ public class Day09 {
17
+
18
+ record Coordinate (int x , int y ) {
19
+
20
+ public int distance (final Coordinate other ) {
21
+ return (int )Math .sqrt (Math .pow ((double )x () - (double )other .x (), 2.0 ) + Math .pow ((double )y () - (double )other .y (), 2.0 ));
22
+ }
23
+
24
+ public Coordinate step (final int xDistance , final int yDistance ) {
25
+ return new Coordinate (x () + xDistance , y + yDistance );
26
+ }
27
+ public Coordinate stepTowards (final Coordinate leader ) {
28
+ final var xDistance = Integer .compare (leader .x (), x ());
29
+ final var yDistance = Integer .compare (leader .y (), y ());
30
+ return step (xDistance , yDistance );
31
+ }
32
+ }
33
+
34
+ public static class Rope {
35
+
36
+ Coordinate [] knotCoordinates ;
37
+
38
+ final SortedMap <Integer , Set <Integer >> visited = new TreeMap <>();
39
+
40
+ public Rope (final int knots ) {
41
+ knotCoordinates = new Coordinate [knots ];
42
+ for (int i = knots ; --i >= 0 ; knotCoordinates [i ] = new Coordinate (0 , 0 ));
43
+ visited .computeIfAbsent (0 , (key ) -> new TreeSet <>()).add (0 );
44
+ }
45
+
46
+ public int countVisited () {
47
+ int result = 0 ;
48
+ for ( final var map : visited .values () ) {
49
+ result += map .size ();
50
+ }
51
+ return result ;
52
+ }
53
+
54
+ public void process (final Instruction instruction ) {
55
+ final int xStep = instruction .direction ().xStep ();
56
+ final int yStep = instruction .direction ().yStep ();
57
+
58
+ for (int i = instruction .distance (); --i >= 0 ; ) {
59
+ knotCoordinates [0 ] = knotCoordinates [0 ].step (xStep , yStep );
60
+ for (int j = 1 ; j < knotCoordinates .length ; j ++) {
61
+ moveKnot (j );
62
+ }
63
+ }
64
+ }
65
+
66
+ protected void moveKnot (int knotIndex ) {
67
+ if (knotIndex <= 0 ) {
68
+ throw new IllegalArgumentException ("Cannot move head" );
69
+ }
70
+ final var leader = knotCoordinates [knotIndex - 1 ];
71
+ var follower = knotCoordinates [knotIndex ];
72
+
73
+ if (leader .equals (follower )) {
74
+ return ;
75
+ } else if (leader .distance (follower ) <= 1 ) {
76
+ return ;
77
+ }
78
+
79
+ follower = follower .stepTowards (leader );
80
+ knotCoordinates [knotIndex ] = follower ;
81
+
82
+ if (knotIndex == knotCoordinates .length - 1 ) {
83
+ visited .computeIfAbsent (follower .x (), (key ) -> new TreeSet <>()).add (follower .y ());
84
+ }
85
+ }
86
+
87
+ }
88
+
89
+ enum Direction {
90
+ Up {
91
+ int xStep () {
92
+ return -1 ;
93
+ }
94
+ int yStep () {
95
+ return 0 ;
96
+ }
97
+ },
98
+ Down {
99
+ int xStep () {
100
+ return 1 ;
101
+ }
102
+ int yStep () {
103
+ return 0 ;
104
+ }
105
+ },
106
+ Left {
107
+ int xStep () {
108
+ return 0 ;
109
+ }
110
+ int yStep () {
111
+ return -1 ;
112
+ }
113
+ },
114
+ Right {
115
+ int xStep () {
116
+ return 0 ;
117
+ }
118
+ int yStep () {
119
+ return 1 ;
120
+ }
121
+ };
122
+
123
+ abstract int xStep ();
124
+ abstract int yStep ();
125
+
126
+ static Direction parse (final String string ) {
127
+ return switch (string .trim ()) {
128
+ case "U" -> Up ;
129
+ case "D" -> Down ;
130
+ case "L" -> Left ;
131
+ case "R" -> Right ;
132
+ default -> throw new IllegalArgumentException ("Invalid direction: " + string );
133
+ };
134
+ }
135
+ }
136
+
137
+ record Instruction (Direction direction , int distance ) {
138
+ static Instruction parse (final String string ) {
139
+ final var components = string .split (" " );
140
+ final var direction = Direction .parse (components [0 ]);
141
+ final var distance = Integer .parseInt (components [1 ]);
142
+ return new Instruction (direction , distance );
143
+ }
144
+ }
145
+
146
+ protected Stream <Instruction > getInput () {
147
+ return StreamSupport
148
+ .stream (new LineSpliterator ("day-09.txt" ),
149
+ false )
150
+ .map (Instruction ::parse );
151
+ }
152
+
153
+ @ Test
154
+ public final void part1 () {
155
+ final var rope = new Rope (2 );
156
+ getInput ().forEach (rope ::process );
157
+ final var result = rope .countVisited ();
158
+ System .out .println ("Part 1: " + result );
159
+ // NOT 7017
160
+ }
161
+
162
+ @ Test
163
+ public final void part2 () {
164
+ final var rope = new Rope (10 );
165
+ getInput ().forEach (rope ::process );
166
+ final var result = rope .countVisited ();
167
+ System .out .println ("Part 2: " + result );
168
+ }
169
+
170
+ }
0 commit comments