1010use std:: fmt:: Display ;
1111use std:: str:: FromStr ;
1212
13+ use num:: Integer ;
14+
1315use crate :: AoCError ;
1416
1517#[ derive( Debug ) ]
1618enum Instruction {
17- Left ( i16 ) ,
18- Right ( i16 ) ,
19+ Left ( u16 ) ,
20+ Right ( u16 ) ,
1921}
2022
2123impl FromStr for Instruction {
@@ -38,18 +40,11 @@ impl FromStr for Instruction {
3840
3941impl Display for Instruction {
4042 fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
41- write ! (
42- f,
43- "Rotate {} {} clicks" ,
44- match self {
45- Self :: Left ( _) => "left" ,
46- Self :: Right ( _) => "right" ,
47- } ,
48- match self {
49- Self :: Left ( i) => i,
50- Self :: Right ( i) => i,
51- }
52- )
43+ let ( dir, amt) = match self {
44+ Self :: Left ( i) => ( "L" , i) ,
45+ Self :: Right ( i) => ( "R" , i) ,
46+ } ;
47+ write ! ( f, "{}{}" , dir, amt)
5348 }
5449}
5550
@@ -69,27 +64,48 @@ impl Display for Dial {
6964}
7065
7166impl Dial {
72- fn rotate ( & mut self , instruction : Instruction ) {
67+ fn rotate ( & mut self , instruction : Instruction ) -> u32 {
68+ let mut ret = 0 ;
69+
7370 match instruction {
7471 Instruction :: Left ( count) => {
72+ let ( full_rotations, count) = count. div_mod_floor ( & 100 ) ;
73+ ret += full_rotations as u32 ;
7574 let count: i64 = count. into ( ) ;
75+ let prezero = self . 0 == 0 ;
7676 self . 0 -= count;
77+ if self . 0 < 0 {
78+ self . 0 += 100 ;
79+ if !prezero {
80+ ret += 1 ;
81+ }
82+ } else if count > 0 && self . 0 == 0 {
83+ ret += 1 ;
84+ }
7785 }
7886 Instruction :: Right ( count) => {
87+ let ( full_rotations, count) = count. div_mod_floor ( & 100 ) ;
88+ ret += full_rotations as u32 ;
7989 let count: i64 = count. into ( ) ;
8090 self . 0 += count;
91+ if self . 0 > 99 {
92+ self . 0 -= 100 ;
93+ ret += 1 ;
94+ } else if count > 0 && self . 0 == 0 {
95+ ret += 1 ;
96+ }
8197 }
8298 }
83- self . clampinate ( ) ;
84- }
85-
86- fn clampinate ( & mut self ) {
87- while self . 0 < 0 {
88- self . 0 += 100 ;
89- }
90- while self . 0 > 99 {
91- self . 0 -= 100 ;
99+ if ret > 0 {
100+ log:: debug!(
101+ "The dial is rotated {instruction} to point at {}; {ret} passes of 0" ,
102+ self . 0
103+ ) ;
104+ } else {
105+ log:: debug!( "The dial is rotated {instruction} to point at {}" , self . 0 ) ;
92106 }
107+
108+ ret
93109 }
94110}
95111
@@ -98,8 +114,6 @@ pub fn part_1(data: crate::DataIn) -> crate::AoCResult<String> {
98114 let mut dial: Dial = Default :: default ( ) ;
99115 for line in data {
100116 let instruction = line. parse ( ) ?;
101- log:: debug!( "{dial}" ) ;
102- log:: debug!( "-> {instruction}" ) ;
103117 dial. rotate ( instruction) ;
104118 if dial. 0 == 0 {
105119 ret += 1 ;
@@ -109,12 +123,111 @@ pub fn part_1(data: crate::DataIn) -> crate::AoCResult<String> {
109123 Ok ( ret. to_string ( ) )
110124}
111125
126+ pub fn part_2 ( data : crate :: DataIn ) -> crate :: AoCResult < String > {
127+ let mut ret = 0 ;
128+ let mut dial: Dial = Default :: default ( ) ;
129+ for line in data {
130+ let instruction = line. parse ( ) ?;
131+ ret += dial. rotate ( instruction) ;
132+ }
133+ log:: info!( "{dial}" ) ;
134+ Ok ( ret. to_string ( ) )
135+ }
136+
112137inventory:: submit!( crate :: AoCDay {
113138 year: "2025" ,
114139 day: "1" ,
115140 part_1: crate :: AoCPart {
116141 main: part_1,
117142 example: part_1
118143 } ,
119- part_2: None
144+ part_2: Some ( crate :: AoCPart {
145+ main: part_2,
146+ example: part_2
147+ } )
120148} ) ;
149+
150+ #[ cfg( test) ]
151+ mod test {
152+ use super :: { Dial , Instruction } ;
153+
154+ #[ test]
155+ fn test_safe_zero ( ) {
156+ let mut dial = Dial ( 50 ) ;
157+ let instruction = Instruction :: Left ( 50 ) ;
158+
159+ let ret = dial. rotate ( instruction) ;
160+ assert_eq ! ( dial. 0 , 0 ) ;
161+ assert_eq ! ( ret, 1 ) ;
162+ }
163+
164+ #[ test]
165+ fn test_right_zero ( ) {
166+ let mut dial = Dial ( 50 ) ;
167+ let instruction = Instruction :: Right ( 50 ) ;
168+
169+ let ret = dial. rotate ( instruction) ;
170+ assert_eq ! ( dial. 0 , 0 ) ;
171+ assert_eq ! ( ret, 1 ) ;
172+ }
173+
174+ #[ test]
175+ fn test_left_multi_rot ( ) {
176+ let mut dial = Dial ( 50 ) ;
177+ let instruction = Instruction :: Left ( 150 ) ;
178+
179+ let ret = dial. rotate ( instruction) ;
180+ assert_eq ! ( dial. 0 , 0 ) ;
181+ assert_eq ! ( ret, 2 ) ;
182+ }
183+
184+ #[ test]
185+ fn test_right_multi_rot ( ) {
186+ let mut dial = Dial ( 50 ) ;
187+ let instruction = Instruction :: Right ( 150 ) ;
188+
189+ let ret = dial. rotate ( instruction) ;
190+ assert_eq ! ( dial. 0 , 0 ) ;
191+ assert_eq ! ( ret, 2 ) ;
192+ }
193+
194+ #[ test]
195+ fn test_zero_full_left ( ) {
196+ let mut dial = Dial ( 0 ) ;
197+ let instruction = Instruction :: Left ( 100 ) ;
198+
199+ let ret = dial. rotate ( instruction) ;
200+ assert_eq ! ( dial. 0 , 0 ) ;
201+ assert_eq ! ( ret, 1 ) ;
202+ }
203+
204+ #[ test]
205+ fn test_zero_full_right ( ) {
206+ let mut dial = Dial ( 0 ) ;
207+ let instruction = Instruction :: Right ( 100 ) ;
208+
209+ let ret = dial. rotate ( instruction) ;
210+ assert_eq ! ( dial. 0 , 0 ) ;
211+ assert_eq ! ( ret, 1 ) ;
212+ }
213+
214+ #[ test]
215+ fn test_one_click_left ( ) {
216+ let mut dial = Dial ( 0 ) ;
217+ let instruction = Instruction :: Left ( 1 ) ;
218+
219+ let ret = dial. rotate ( instruction) ;
220+ assert_eq ! ( dial. 0 , 99 ) ;
221+ assert_eq ! ( ret, 0 ) ;
222+ }
223+
224+ #[ test]
225+ fn test_one_click_right ( ) {
226+ let mut dial = Dial ( 0 ) ;
227+ let instruction = Instruction :: Right ( 1 ) ;
228+
229+ let ret = dial. rotate ( instruction) ;
230+ assert_eq ! ( dial. 0 , 1 ) ;
231+ assert_eq ! ( ret, 0 ) ;
232+ }
233+ }
0 commit comments