1
1
advent_of_code:: solution!( 3 ) ;
2
2
3
- use advent_of_code:: maneatingape:: parse:: * ;
4
-
5
- use regex:: Regex ;
6
-
7
3
enum Command {
8
4
Enable ,
9
5
Disable ,
10
6
Multiply ( u32 , u32 ) ,
11
7
}
12
8
13
9
fn parse_data ( input : & str ) -> Vec < Command > {
14
- let mut commands = vec ! [ ] ;
10
+ ( 0 ..input. len ( ) )
11
+ . filter_map ( |i| {
12
+ let value = & input[ i..] ;
13
+
14
+ // Enable
15
+ if value. starts_with ( "do()" ) {
16
+ return Some ( Command :: Enable ) ;
17
+ }
15
18
16
- let mul_re = Regex :: new ( r"^mul\((\d{1,3}),(\d{1,3})\)" ) . unwrap ( ) ;
19
+ // Disable
20
+ if value. starts_with ( "don't()" ) {
21
+ return Some ( Command :: Disable ) ;
22
+ }
17
23
18
- for i in 0 ..input. len ( ) {
19
- if input[ i..] . starts_with ( "mul" ) {
20
- if let Some ( m) = mul_re. captures ( & input[ i..] ) {
21
- let [ x, y] = m. extract ( ) . 1 . map ( |x| x. unsigned ( ) ) ;
22
- commands. push ( Command :: Multiply ( x, y) ) ;
24
+ // Multiply
25
+ if value. starts_with ( "mul(" ) {
26
+ let mut first_number = None ;
27
+ let mut number = 0 ;
28
+
29
+ for c in value. bytes ( ) . skip ( 4 ) {
30
+ match c {
31
+ b'0' ..=b'9' => {
32
+ if number > 1000 {
33
+ return None ;
34
+ }
35
+
36
+ number = number * 10 + ( c - b'0' ) as u32 ;
37
+ }
38
+ b',' => {
39
+ if number == 0 || first_number. is_some ( ) {
40
+ return None ;
41
+ }
42
+
43
+ first_number = Some ( number) ;
44
+ number = 0 ;
45
+ }
46
+ b')' => {
47
+ if number == 0 {
48
+ return None ;
49
+ }
50
+
51
+ return Some ( Command :: Multiply ( first_number?, number) ) ;
52
+ }
53
+ _ => {
54
+ return None ;
55
+ }
56
+ }
57
+ }
23
58
}
24
- } else if input[ i..] . starts_with ( "do()" ) {
25
- commands. push ( Command :: Enable ) ;
26
- } else if input[ i..] . starts_with ( "don't()" ) {
27
- commands. push ( Command :: Disable ) ;
28
- }
29
- }
30
59
31
- commands
60
+ None
61
+ } )
62
+ . collect ( )
32
63
}
33
64
34
65
pub fn part_one ( input : & str ) -> Option < u32 > {
@@ -48,16 +79,15 @@ pub fn part_one(input: &str) -> Option<u32> {
48
79
pub fn part_two ( input : & str ) -> Option < u32 > {
49
80
let data = parse_data ( input) ;
50
81
51
- let mut enabled = true ;
52
-
53
- let mut result = 0 ;
54
- for c in data {
55
- match c {
56
- Command :: Multiply ( x, y) => result += if enabled { x * y } else { 0 } ,
57
- Command :: Enable => enabled = true ,
58
- Command :: Disable => enabled = false ,
59
- }
60
- }
82
+ let result = data
83
+ . into_iter ( )
84
+ . fold ( ( 0 , true ) , |acc, c| match ( c, acc. 1 ) {
85
+ ( Command :: Enable , false ) => ( acc. 0 , true ) ,
86
+ ( Command :: Disable , true ) => ( acc. 0 , false ) ,
87
+ ( Command :: Multiply ( x, y) , true ) => ( acc. 0 + x * y, true ) ,
88
+ _ => acc,
89
+ } )
90
+ . 0 ;
61
91
62
92
Some ( result)
63
93
}
@@ -68,13 +98,15 @@ mod tests {
68
98
69
99
#[ test]
70
100
fn test_part_one ( ) {
71
- let result = part_one ( & advent_of_code:: template:: read_file ( "examples" , DAY ) ) ;
101
+ let input = advent_of_code:: template:: read_file ( "examples" , DAY ) ;
102
+ let result = part_one ( & input) ;
72
103
assert_eq ! ( result, Some ( 161 ) ) ;
73
104
}
74
105
75
106
#[ test]
76
107
fn test_part_two ( ) {
77
- let result = part_two ( & advent_of_code:: template:: read_file ( "examples" , DAY ) ) ;
108
+ let input = advent_of_code:: template:: read_file ( "examples" , DAY ) ;
109
+ let result = part_two ( & input) ;
78
110
assert_eq ! ( result, Some ( 48 ) ) ;
79
111
}
80
112
}
0 commit comments