11use std:: num:: ParseIntError ;
22
33use anyhow:: Result ;
4- use itertools:: Itertools ;
54use num:: Integer ;
6- use rustc_hash:: FxHashSet ;
75
86#[ derive( Debug , Clone , Copy ) ]
97struct Moon {
10- x : i32 ,
11- y : i32 ,
12- z : i32 ,
13- vx : i32 ,
14- vy : i32 ,
15- vz : i32 ,
8+ p : [ i32 ; 3 ] ,
9+ v : [ i32 ; 3 ] ,
1610}
1711
1812impl Moon {
19- pub fn new ( x : i32 , y : i32 , z : i32 ) -> Self {
13+ fn new ( x : i32 , y : i32 , z : i32 ) -> Self {
2014 Self {
21- x,
22- y,
23- z,
24- vx : 0 ,
25- vy : 0 ,
26- vz : 0 ,
15+ p : [ x, y, z] ,
16+ v : [ 0 ; 3 ] ,
2717 }
2818 }
19+ #[ inline( always) ]
20+ fn kinetic_energy ( & self ) -> i32 {
21+ self . v [ 0 ] . abs ( ) + self . v [ 1 ] . abs ( ) + self . v [ 2 ] . abs ( )
22+ }
23+ #[ inline( always) ]
24+ fn potential_energy ( & self ) -> i32 {
25+ self . p [ 0 ] . abs ( ) + self . p [ 1 ] . abs ( ) + self . p [ 2 ] . abs ( )
26+ }
27+ #[ inline( always) ]
28+ fn energy ( & self ) -> i32 {
29+ self . kinetic_energy ( ) * self . potential_energy ( )
30+ }
31+ }
32+
33+ #[ derive( Clone , Copy , Debug ) ]
34+ struct State {
35+ moons : [ Moon ; 4 ] ,
36+ }
37+
38+ impl State {
39+ #[ inline]
40+ fn step_coord < const C : usize > ( & mut self ) {
41+ for a in 0 ..4 {
42+ for b in ( a + 1 ) ..4 {
43+ self . moons [ a] . v [ C ] += ( self . moons [ b] . p [ C ] - self . moons [ a] . p [ C ] ) . signum ( ) ;
44+ self . moons [ b] . v [ C ] += ( self . moons [ a] . p [ C ] - self . moons [ b] . p [ C ] ) . signum ( ) ;
45+ }
46+ }
47+ for a in 0 ..4 {
48+ self . moons [ a] . p [ C ] += self . moons [ a] . v [ C ] ;
49+ }
50+ }
51+ #[ inline( always) ]
52+ fn eq_coord < const C : usize > ( & self , other : & Self ) -> bool {
53+ self . moons [ 0 ] . p [ C ] == other. moons [ 0 ] . p [ C ]
54+ && self . moons [ 1 ] . p [ C ] == other. moons [ 1 ] . p [ C ]
55+ && self . moons [ 2 ] . p [ C ] == other. moons [ 2 ] . p [ C ]
56+ && self . moons [ 3 ] . p [ C ] == other. moons [ 3 ] . p [ C ]
57+ && self . moons [ 0 ] . v [ C ] == other. moons [ 0 ] . v [ C ]
58+ && self . moons [ 1 ] . v [ C ] == other. moons [ 1 ] . v [ C ]
59+ && self . moons [ 2 ] . v [ C ] == other. moons [ 2 ] . v [ C ]
60+ && self . moons [ 3 ] . v [ C ] == other. moons [ 3 ] . v [ C ]
61+ }
62+ #[ inline]
63+ fn cycle < const C : usize > ( & self ) -> usize {
64+ let mut length = 1 ;
65+ let mut state = * self ;
66+ state. step_coord :: < C > ( ) ;
67+ while !self . eq_coord :: < C > ( & state) {
68+ state. step_coord :: < C > ( ) ;
69+ length += 1 ;
70+ }
71+
72+ length
73+ }
74+ #[ inline( always) ]
75+ fn step ( & mut self ) {
76+ self . step_coord :: < 0 > ( ) ;
77+ self . step_coord :: < 1 > ( ) ;
78+ self . step_coord :: < 2 > ( ) ;
79+ }
2980}
3081
3182pub async fn day12 ( input : String ) -> Result < ( String , String ) > {
32- let moons = input
83+ let state = input
3384 . trim ( )
3485 . chars ( )
3586 . filter ( |c| c. is_ascii_digit ( ) || matches ! ( c, '-' | ',' | '\n' ) )
@@ -43,72 +94,26 @@ pub async fn day12(input: String) -> Result<(String, String)> {
4394 Ok ( Moon :: new ( components[ 0 ] , components[ 1 ] , components[ 2 ] ) )
4495 } )
4596 . collect :: < Result < Vec < Moon > , ParseIntError > > ( ) ?;
97+ let state = State {
98+ moons : [ state[ 0 ] , state[ 1 ] , state[ 2 ] , state[ 3 ] ] ,
99+ } ;
46100
47101 let part1 = {
48- let mut moons = moons . clone ( ) ;
102+ let mut state = state . clone ( ) ;
49103 for _ in 0 ..1000 {
50- // Gravity
51- for ( a, b) in ( 0 ..moons. len ( ) ) . tuple_combinations ( ) {
52- moons[ a] . vx += ( moons[ b] . x - moons[ a] . x ) . signum ( ) ;
53- moons[ a] . vy += ( moons[ b] . y - moons[ a] . y ) . signum ( ) ;
54- moons[ a] . vz += ( moons[ b] . z - moons[ a] . z ) . signum ( ) ;
55- moons[ b] . vx += ( moons[ a] . x - moons[ b] . x ) . signum ( ) ;
56- moons[ b] . vy += ( moons[ a] . y - moons[ b] . y ) . signum ( ) ;
57- moons[ b] . vz += ( moons[ a] . z - moons[ b] . z ) . signum ( ) ;
58- }
59-
60- // Velocity
61- for m in & mut moons {
62- m. x += m. vx ;
63- m. y += m. vy ;
64- m. z += m. vz ;
65- }
104+ state. step ( ) ;
66105 }
67-
68- moons
69- . iter ( )
70- . map ( |& m| ( m. x . abs ( ) + m. y . abs ( ) + m. z . abs ( ) ) * ( m. vx . abs ( ) + m. vy . abs ( ) + m. vz . abs ( ) ) )
71- . sum :: < i32 > ( )
106+ state. moons . iter ( ) . map ( Moon :: energy) . sum :: < i32 > ( )
72107 } ;
73108
74109 let part2 = {
75- // Make sure the size is known at compile time so the compiler has a better shot at
76- // optimizing
77- let mut m = [ moons[ 0 ] , moons[ 1 ] , moons[ 2 ] , moons[ 3 ] ] ;
78- macro_rules! find_cycle {
79- ( $pos: ident, $vel: ident) => {
80- ' block: {
81- let mut states = FxHashSet :: <( [ i32 ; 4 ] , [ i32 ; 4 ] ) >:: default ( ) ;
82-
83- for i in 0 .. {
84- if !states. insert( ( [ m[ 0 ] . $pos, m[ 1 ] . $pos, m[ 2 ] . $pos, m[ 3 ] . $pos] , [ m[ 0 ] . $vel, m[ 1 ] . $vel, m[ 2 ] . $vel, m[ 3 ] . $vel] ) ) {
85- break ' block i as u128
86- }
87-
88- for a in 0 ..4 {
89- for b in ( a+1 ) ..4 {
90- m[ a] . $vel += ( m[ b] . $pos - m[ a] . $pos) . signum( ) ;
91- m[ b] . $vel += ( m[ a] . $pos - m[ b] . $pos) . signum( ) ;
92- }
93- }
94-
95- for a in 0 ..4 {
96- m[ a] . $pos += m[ a] . $vel;
97- }
98- }
99-
100- unreachable!( )
101- }
102- } ;
103- }
104- let x_cycle = find_cycle ! ( x, vx) ;
105- let y_cycle = find_cycle ! ( y, vy) ;
106- let z_cycle = find_cycle ! ( z, vz) ;
110+ let x_cycle = state. cycle :: < 0 > ( ) ;
111+ let y_cycle = state. cycle :: < 1 > ( ) ;
112+ let z_cycle = state. cycle :: < 2 > ( ) ;
107113
108114 let xy_cycle = x_cycle. lcm ( & y_cycle) ;
109115 z_cycle * xy_cycle / z_cycle. gcd ( & xy_cycle)
110116 } ;
111117
112118 Ok ( ( part1. to_string ( ) , part2. to_string ( ) ) )
113119}
114-
0 commit comments