@@ -8,23 +8,24 @@ namespace AdventOfCode.Y2021.Day23;
8
8
[ ProblemName ( "Amphipod" ) ]
9
9
class Solution : Solver {
10
10
11
- public object PartOne ( string input ) => Solve ( input ) . Min ( ) ;
12
- public object PartTwo ( string input ) => Solve ( Upscale ( input ) ) . Min ( ) ;
11
+ public object PartOne ( string input ) => Solve ( input ) ;
12
+ public object PartTwo ( string input ) => Solve ( Upscale ( input ) ) ;
13
13
14
- string Upscale ( string input ) {
14
+ string Upscale ( string input ) {
15
15
var lines = input . Split ( "\n " ) . ToList ( ) ;
16
16
lines . Insert ( 3 , " #D#C#B#A#" ) ;
17
17
lines . Insert ( 4 , " #D#B#A#C#" ) ;
18
18
return string . Join ( "\n " , lines ) ;
19
19
}
20
20
21
- IEnumerable < int > Solve ( string input ) {
21
+ int Solve ( string input ) {
22
22
var maze = GetMaze ( input ) ;
23
23
24
24
var q = new PriorityQueue < Maze , int > ( ) ;
25
- var seen = new Dictionary < string , Maze > ( ) ;
26
- q . Enqueue ( maze , maze . cost ) ;
27
- seen . Add ( maze . Tsto ( ) , maze ) ;
25
+ var cost = new Dictionary < Maze , int > ( ) ;
26
+
27
+ q . Enqueue ( maze , 0 ) ;
28
+ cost . Add ( maze , 0 ) ;
28
29
29
30
bool finished ( Maze maze ) {
30
31
bool colMatch ( int icol , char c ) {
@@ -39,28 +40,36 @@ bool colMatch(int icol, char c) {
39
40
}
40
41
41
42
while ( q . Count > 0 ) {
42
- maze = q . Dequeue ( ) ;
43
-
44
- foreach ( var mazeT in Neighbours ( maze ) ) {
45
- if ( finished ( mazeT ) ) {
46
- yield return mazeT . cost ;
47
- } else if ( ! seen . ContainsKey ( mazeT . Tsto ( ) ) || seen [ mazeT . Tsto ( ) ] . cost > mazeT . cost ) {
48
- seen [ mazeT . Tsto ( ) ] = mazeT ;
49
- q . Enqueue ( mazeT with { prev = maze } , mazeT . cost ) ;
43
+ while ( cost [ q . UnorderedItems . First ( ) . Element ] != q . UnorderedItems . First ( ) . Priority ) {
44
+ q . Dequeue ( ) ;
45
+ }
46
+
47
+ maze = q . Dequeue ( ) ; ;
48
+
49
+ if ( finished ( maze ) ) {
50
+ return cost [ maze ] ;
51
+ }
52
+
53
+ foreach ( var n in Neighbours ( maze ) ) {
54
+ if ( n . cost + cost [ maze ] < cost . GetValueOrDefault ( n . maze , int . MaxValue ) ) {
55
+ cost [ n . maze ] = n . cost + cost [ maze ] ;
56
+ q . Enqueue ( n . maze , cost [ n . maze ] ) ;
50
57
}
51
58
}
52
59
}
60
+
61
+ throw new Exception ( ) ;
53
62
}
54
63
55
64
Maze GetMaze ( string input ) {
56
65
var map = input . Split ( "\n " ) ;
57
- return new Maze ( (
58
- from y in Enumerable . Range ( 0 , map . Length )
59
- from x in Enumerable . Range ( 0 , map [ 0 ] . Length )
60
- select new KeyValuePair < Point , char > ( new Point ( y , x ) , y < map . Length && x < map [ y ] . Length ? map [ y ] [ x ] : ' ' )
61
- ) . ToImmutableDictionary ( ) ,
62
- 0
63
- ) ;
66
+ var maze = new Maze ( 0 , 0 , 0 , 0 , map . Length > 6 ) ;
67
+ foreach ( var y in Enumerable . Range ( 0 , map . Length ) ) {
68
+ foreach ( var x in Enumerable . Range ( 0 , map [ 0 ] . Length ) ) {
69
+ maze = maze . SetItem ( new Point ( y , x ) , y < map . Length && x < map [ y ] . Length ? map [ y ] [ x ] : '#' ) ;
70
+ }
71
+ }
72
+ return maze ;
64
73
}
65
74
66
75
int stepCost ( char actor ) {
@@ -97,7 +106,7 @@ bool finishedColumn(Maze maze, int icol) {
97
106
return true ;
98
107
}
99
108
100
- IEnumerable < Maze > Neighbours ( Maze maze ) {
109
+ IEnumerable < ( Maze maze , int cost ) > Neighbours ( Maze maze ) {
101
110
102
111
bool columnIsClean ( int icol , char ch ) {
103
112
var pt = new Point ( 2 , icol ) ;
@@ -125,7 +134,7 @@ Point step(Point pt) {
125
134
}
126
135
127
136
// le-e lehet menni?
128
- Maze Lemegy ( Maze maze ) {
137
+ ( Maze maze , int cost ) Lemegy ( Maze maze ) {
129
138
for ( var icol = 1 ; icol < 12 ; icol ++ ) {
130
139
var ch = maze . ItemAt ( new Point ( 1 , icol ) ) ;
131
140
@@ -144,17 +153,16 @@ Maze Lemegy(Maze maze) {
144
153
steps ++ ;
145
154
}
146
155
147
- return Lemegy ( maze with {
148
- map = maze . map . SetItem ( new Point ( 1 , icol ) , '.' ) . SetItem ( pt , ch ) ,
149
- cost = maze . cost + steps * stepCost ( ch )
150
- } ) ;
156
+ var l = Lemegy ( maze . SetItem ( new Point ( 1 , icol ) , '.' ) . SetItem ( pt , ch ) ) ;
157
+ return ( l . maze , l . cost + steps * stepCost ( ch ) ) ;
151
158
}
152
159
}
153
- return maze ;
160
+ return ( maze , 0 ) ;
154
161
}
155
162
156
- if ( Lemegy ( maze ) . Tsto ( ) != maze . Tsto ( ) ) {
157
- yield return Lemegy ( maze ) ;
163
+ var lemegy = Lemegy ( maze ) ;
164
+ if ( lemegy . cost != 0 ) {
165
+ yield return lemegy ;
158
166
yield break ;
159
167
}
160
168
var allowedHColumns = new int [ ] { 1 , 2 , 4 , 6 , 8 , 10 , 11 } ;
@@ -184,10 +192,10 @@ Maze Lemegy(Maze maze) {
184
192
while ( maze . ItemAt ( ptDst ) == '.' ) {
185
193
186
194
if ( allowedHColumns . Contains ( ptDst . icol ) ) {
187
- yield return maze with {
188
- map = maze . map . SetItem ( ptSrc , '.' ) . SetItem ( ptDst , ch ) ,
189
- cost = maze . cost + ( stepsV + stepsH ) * stepCost ( ch )
190
- } ;
195
+ yield return (
196
+ maze . SetItem ( ptSrc , '.' ) . SetItem ( ptDst , ch ) ,
197
+ ( stepsV + stepsH ) * stepCost ( ch )
198
+ ) ;
191
199
}
192
200
193
201
if ( dj == - 1 ) {
@@ -209,19 +217,78 @@ record Point(int irow, int icol) {
209
217
public Point Left => new Point ( irow , icol - 1 ) ;
210
218
public Point Right => new Point ( irow , icol + 1 ) ;
211
219
}
212
- record Maze ( ImmutableDictionary < Point , char > map , int cost , Maze prev = null ) {
213
-
214
- public char ItemAt ( Point pt ) => map . GetValueOrDefault ( pt , '#' ) ;
220
+ record Maze ( int a , int b , int c , int d , bool big ) {
221
+
222
+ int BitFromPoint ( Point pt ) =>
223
+ ( big , pt . irow , pt . icol ) switch {
224
+ ( _, 1 , 1 ) => 1 << 0 ,
225
+ ( _, 1 , 2 ) => 1 << 1 ,
226
+ ( _, 1 , 3 ) => 1 << 2 ,
227
+ ( _, 1 , 4 ) => 1 << 3 ,
228
+ ( _, 1 , 5 ) => 1 << 4 ,
229
+ ( _, 1 , 6 ) => 1 << 5 ,
230
+ ( _, 1 , 7 ) => 1 << 6 ,
231
+ ( _, 1 , 8 ) => 1 << 7 ,
232
+ ( _, 1 , 9 ) => 1 << 8 ,
233
+ ( _, 1 , 10 ) => 1 << 9 ,
234
+ ( _, 1 , 11 ) => 1 << 10 ,
235
+
236
+ ( _, 2 , 3 ) => 1 << 11 ,
237
+ ( _, 2 , 5 ) => 1 << 12 ,
238
+ ( _, 2 , 7 ) => 1 << 13 ,
239
+ ( _, 2 , 9 ) => 1 << 14 ,
240
+
241
+ ( _, 3 , 3 ) => 1 << 15 ,
242
+ ( _, 3 , 5 ) => 1 << 16 ,
243
+ ( _, 3 , 7 ) => 1 << 17 ,
244
+ ( _, 3 , 9 ) => 1 << 18 ,
245
+
246
+ ( true , 4 , 3 ) => 1 << 19 ,
247
+ ( true , 4 , 5 ) => 1 << 20 ,
248
+ ( true , 4 , 7 ) => 1 << 21 ,
249
+ ( true , 4 , 9 ) => 1 << 22 ,
250
+
251
+ ( true , 5 , 3 ) => 1 << 23 ,
252
+ ( true , 5 , 5 ) => 1 << 24 ,
253
+ ( true , 5 , 7 ) => 1 << 25 ,
254
+ ( true , 5 , 9 ) => 1 << 26 ,
255
+
256
+ _ => 1 << 31 ,
257
+ } ;
258
+
259
+ public char ItemAt ( Point pt ) {
260
+ var bit = BitFromPoint ( pt ) ;
261
+ return
262
+ bit == 1 << 31 ? '#' :
263
+ ( a & bit ) != 0 ? 'A' :
264
+ ( b & bit ) != 0 ? 'B' :
265
+ ( c & bit ) != 0 ? 'C' :
266
+ ( d & bit ) != 0 ? 'D' :
267
+ ( d & bit ) != 0 ? 'D' :
268
+ '.' ;
269
+ }
215
270
216
- public string Tsto ( ) {
217
- var st = "" ;
218
- for ( var irow = 0 ; irow < 7 ; irow ++ ) {
219
- for ( var icol = 0 ; icol < 13 ; icol ++ ) {
220
- st += map . GetValueOrDefault ( new Point ( irow , icol ) , ' ' ) ;
221
- }
222
- st += "\n " ;
271
+ public Maze SetItem ( Point pt , char ch ) {
272
+ var bit = BitFromPoint ( pt ) ;
273
+ if ( bit == 1 << 31 ) {
274
+ if ( ch != '#' && ch != ' ' )
275
+ throw new Exception ( ) ;
276
+ return this ;
223
277
}
224
- st += "---\n " ;
225
- return st ;
278
+
279
+ return ch switch {
280
+ '.' =>
281
+ this with {
282
+ a = a & ~ bit ,
283
+ b = b & ~ bit ,
284
+ c = c & ~ bit ,
285
+ d = d & ~ bit
286
+ } ,
287
+ 'A' => this with { a = a | bit } ,
288
+ 'B' => this with { b = b | bit } ,
289
+ 'C' => this with { c = c | bit } ,
290
+ 'D' => this with { d = d | bit } ,
291
+ _ => throw new Exception ( )
292
+ } ;
226
293
}
227
294
}
0 commit comments