1
1
use crate :: solutions:: Solution ;
2
+ use crate :: utils:: deltoid_surface:: DeltoidSurface ;
2
3
use crate :: utils:: grid:: Grid ;
3
4
use crate :: utils:: point:: Point ;
4
5
use itertools:: Itertools ;
@@ -9,18 +10,46 @@ pub struct Day20;
9
10
10
11
impl Solution for Day20 {
11
12
fn part_one ( & self , input : & str ) -> String {
12
- self . cheats_in_range ( input, 100 ..) . to_string ( )
13
+ self . part_one_cheats_in_range ( input, 100 ..) . to_string ( )
13
14
}
14
15
15
- fn part_two ( & self , _input : & str ) -> String {
16
- String :: from ( '0' )
16
+ fn part_two ( & self , input : & str ) -> String {
17
+ // extract surface trait and contains method
18
+ // grid has function get every position in area
19
+ // rename surface range as rectangular area
20
+ //
21
+ self . part_two_cheats_in_range ( input, 100 ..) . to_string ( )
17
22
}
18
23
}
19
24
20
25
impl Day20 {
21
- fn cheats_in_range < R > ( & self , input : & str , range : R ) -> usize
26
+ fn part_one_cheats_in_range ( & self , input : & str , range : impl RangeBounds < usize > ) -> usize {
27
+ let cheat_range_from_current = |current : Point | {
28
+ current
29
+ . adjacent_vectors ( )
30
+ . map ( |v| v. forward ( ) . position ( ) )
31
+ . into_iter ( )
32
+ } ;
33
+
34
+ self . cheats_in_range ( input, range, & cheat_range_from_current)
35
+ }
36
+
37
+ fn part_two_cheats_in_range ( & self , input : & str , range : impl RangeBounds < usize > ) -> usize {
38
+ let cheat_range_from_current =
39
+ |current : Point | DeltoidSurface :: new ( current, 20 ) . points ( ) . into_iter ( ) ;
40
+
41
+ self . cheats_in_range ( input, range, & cheat_range_from_current)
42
+ }
43
+
44
+ fn cheats_in_range < R , I > (
45
+ & self ,
46
+ input : & str ,
47
+ range : R ,
48
+ cheat_positions : & dyn Fn ( Point ) -> I ,
49
+ ) -> usize
22
50
where
23
51
R : RangeBounds < usize > ,
52
+ I : Iterator < Item = Point > ,
24
53
{
25
54
let grid: Grid < char > = Grid :: from ( input) ;
26
55
let start = grid. get_first_position ( & 'S' ) . unwrap ( ) ;
@@ -32,30 +61,30 @@ impl Day20 {
32
61
. path ( )
33
62
. iter ( )
34
63
. flat_map ( |( current_time, current) | {
35
- current
36
- . adjacent_vectors ( )
37
- . iter ( )
38
- . filter ( |v| grid. is_for_point ( & v. position ( ) , '#' ) )
39
- . map ( |p| p. forward ( ) )
64
+ cheat_positions ( * current)
40
65
. filter ( |v| {
41
- grid. get_for_point ( & v . position ( ) )
66
+ grid. get_for_point ( v )
42
67
. is_some_and ( |element| [ '.' , 'E' ] . contains ( element) )
43
68
} )
44
- . filter_map ( |v| {
45
- if let Some ( time_after_cheat) =
46
- path_without_cheats. picoseconds_from ( v. position ( ) )
47
- {
48
- if time_after_cheat > * current_time {
49
- return Some ( time_after_cheat - current_time - 2 ) ;
50
- // why -2
69
+ . filter_map ( |cheat_position| {
70
+ let time_after_cheat = path_without_cheats
71
+ . picoseconds_from ( cheat_position)
72
+ . unwrap ( ) ;
73
+ let cheat_cost = current. manhattan_distance ( & cheat_position) as usize ;
74
+
75
+ if time_after_cheat > * current_time + cheat_cost {
76
+ let time = time_after_cheat - current_time - cheat_cost;
77
+ if range. contains ( & time) {
78
+ return Some ( time) ;
51
79
}
52
- }
53
80
54
- None
81
+ None
82
+ } else {
83
+ None
84
+ }
55
85
} )
56
86
. collect_vec ( )
57
87
} )
58
- . filter ( |time| range. contains ( time) )
59
88
. count ( )
60
89
}
61
90
@@ -126,17 +155,28 @@ mod tests {
126
155
###############"# ;
127
156
128
157
#[ test]
129
- fn test_solve ( ) {
130
- assert_eq ! ( 14 , Day20 . cheats_in_range( EXAMPLE , 2 ..=2 ) ) ;
131
- assert_eq ! ( 14 , Day20 . cheats_in_range( EXAMPLE , 4 ..=4 ) ) ;
132
- assert_eq ! ( 2 , Day20 . cheats_in_range( EXAMPLE , 6 ..=6 ) ) ;
133
- assert_eq ! ( 4 , Day20 . cheats_in_range( EXAMPLE , 8 ..=8 ) ) ;
134
- assert_eq ! ( 2 , Day20 . cheats_in_range( EXAMPLE , 10 ..=10 ) ) ;
135
- assert_eq ! ( 3 , Day20 . cheats_in_range( EXAMPLE , 12 ..=12 ) ) ;
136
- assert_eq ! ( 1 , Day20 . cheats_in_range( EXAMPLE , 20 ..=20 ) ) ;
137
- assert_eq ! ( 1 , Day20 . cheats_in_range( EXAMPLE , 36 ..=36 ) ) ;
138
- assert_eq ! ( 1 , Day20 . cheats_in_range( EXAMPLE , 38 ..=38 ) ) ;
139
- assert_eq ! ( 1 , Day20 . cheats_in_range( EXAMPLE , 40 ..=40 ) ) ;
140
- assert_eq ! ( 1 , Day20 . cheats_in_range( EXAMPLE , 64 ..=64 ) ) ;
158
+ fn part_one_cheats_in_range ( ) {
159
+ assert_eq ! ( 14 , Day20 . part_one_cheats_in_range( EXAMPLE , 2 ..=2 ) ) ;
160
+ assert_eq ! ( 14 , Day20 . part_one_cheats_in_range( EXAMPLE , 4 ..=4 ) ) ;
161
+ assert_eq ! ( 2 , Day20 . part_one_cheats_in_range( EXAMPLE , 6 ..=6 ) ) ;
162
+ assert_eq ! ( 4 , Day20 . part_one_cheats_in_range( EXAMPLE , 8 ..=8 ) ) ;
163
+ assert_eq ! ( 2 , Day20 . part_one_cheats_in_range( EXAMPLE , 10 ..=10 ) ) ;
164
+ assert_eq ! ( 3 , Day20 . part_one_cheats_in_range( EXAMPLE , 12 ..=12 ) ) ;
165
+ assert_eq ! ( 1 , Day20 . part_one_cheats_in_range( EXAMPLE , 20 ..=20 ) ) ;
166
+ assert_eq ! ( 1 , Day20 . part_one_cheats_in_range( EXAMPLE , 36 ..=36 ) ) ;
167
+ assert_eq ! ( 1 , Day20 . part_one_cheats_in_range( EXAMPLE , 38 ..=38 ) ) ;
168
+ assert_eq ! ( 1 , Day20 . part_one_cheats_in_range( EXAMPLE , 40 ..=40 ) ) ;
169
+ assert_eq ! ( 1 , Day20 . part_one_cheats_in_range( EXAMPLE , 64 ..=64 ) ) ;
170
+ }
171
+
172
+ #[ test]
173
+ fn part_two_cheats_in_range ( ) {
174
+ assert_eq ! ( 32 , Day20 . part_two_cheats_in_range( EXAMPLE , 50 ..=50 ) ) ;
175
+ assert_eq ! ( 31 , Day20 . part_two_cheats_in_range( EXAMPLE , 52 ..=52 ) ) ;
176
+ assert_eq ! ( 29 , Day20 . part_two_cheats_in_range( EXAMPLE , 54 ..=54 ) ) ;
177
+ assert_eq ! ( 39 , Day20 . part_two_cheats_in_range( EXAMPLE , 56 ..=56 ) ) ;
178
+ assert_eq ! ( 25 , Day20 . part_two_cheats_in_range( EXAMPLE , 58 ..=58 ) ) ;
179
+ assert_eq ! ( 23 , Day20 . part_two_cheats_in_range( EXAMPLE , 60 ..=60 ) ) ;
180
+ assert_eq ! ( 20 , Day20 . part_two_cheats_in_range( EXAMPLE , 62 ..=62 ) ) ;
141
181
}
142
182
}
0 commit comments