2020-01-02 16:05:45 +01:00
use std ::collections ::HashSet ;
2019-12-27 16:35:28 +01:00
use std ::io ::{ self , BufRead } ;
2020-01-02 16:05:45 +01:00
mod tests ;
2019-12-27 16:35:28 +01:00
2020-01-02 16:05:45 +01:00
#[ derive(Clone, Copy) ]
2019-12-28 13:18:24 +01:00
enum ShuffleOperation {
CutLeft ( usize ) ,
CutRight ( usize ) ,
DealWithIncrement ( usize ) ,
Reverse ,
}
2020-01-02 16:05:45 +01:00
impl < ' a > From < & ' a str > for ShuffleOperation {
fn from ( raw : & ' a str ) -> ShuffleOperation {
let words : Vec < _ > = raw . split ( ' ' ) . collect ( ) ;
match words [ 0 ] {
" cut " = > {
let offset : isize = words [ 1 ] . parse ( ) . expect ( " Not a valid number for cutting " ) ;
if offset < 0 {
ShuffleOperation ::CutRight ( offset . abs ( ) as usize )
} else {
ShuffleOperation ::CutLeft ( offset as usize )
}
2019-12-27 16:35:28 +01:00
}
2020-01-02 16:05:45 +01:00
" deal " = > match words [ 1 ] {
// with increment
" with " = > ShuffleOperation ::DealWithIncrement ( words [ 3 ] . parse ( ) . unwrap ( ) ) ,
// into new stack
" into " = > ShuffleOperation ::Reverse ,
_ = > unreachable! ( " Unknown deal command " ) ,
} ,
_ = > unreachable! ( " Unknown shuffle command " ) ,
2019-12-27 16:35:28 +01:00
}
2019-12-28 13:18:24 +01:00
}
}
2020-01-02 16:05:45 +01:00
fn apply ( deck : & mut Vec < usize > , operation : ShuffleOperation ) {
match operation {
2019-12-28 13:18:24 +01:00
ShuffleOperation ::Reverse = > deck . reverse ( ) ,
ShuffleOperation ::CutLeft ( offset ) = > {
let clone = deck . clone ( ) ;
let ( left , right ) = clone . split_at ( offset as usize ) ;
* deck = right . to_vec ( ) ;
deck . append ( & mut left . to_vec ( ) ) ;
}
ShuffleOperation ::CutRight ( offset ) = > {
let offset = deck . len ( ) - offset ;
let cut : Vec < _ > = deck . drain ( 0 .. offset ) . collect ( ) ;
cut . into_iter ( ) . for_each ( | n | deck . push ( n ) ) ;
}
ShuffleOperation ::DealWithIncrement ( increment ) = > {
let length = deck . len ( ) ;
let old_deck = deck . clone ( ) ;
for i in 0 .. length {
deck [ ( i * increment ) % length ] = old_deck [ i ] ;
}
}
2019-12-27 16:35:28 +01:00
} ;
}
2020-01-02 16:05:45 +01:00
fn get_previous_index ( current : usize , operation : ShuffleOperation , deck_size : usize ) -> usize {
match operation {
2019-12-28 13:18:24 +01:00
ShuffleOperation ::Reverse = > deck_size - current - 1 ,
2020-01-02 16:05:45 +01:00
ShuffleOperation ::CutLeft ( offset ) = > ( current + offset ) % deck_size ,
ShuffleOperation ::CutRight ( offset ) = > ( current + deck_size - offset ) % deck_size ,
2019-12-28 13:18:24 +01:00
ShuffleOperation ::DealWithIncrement ( increment ) = > ( 0 .. )
. filter_map ( | x | {
2020-01-02 16:05:45 +01:00
let old_position = x * deck_size + current ;
if old_position % increment = = 0 {
Some ( old_position / increment )
2019-12-28 13:18:24 +01:00
} else {
None
}
} )
. next ( )
. unwrap ( ) ,
}
}
2019-12-27 16:43:22 +01:00
fn create_deck ( len : usize ) -> Vec < usize > {
let mut deck = Vec ::with_capacity ( len ) ;
( 0 .. len ) . for_each ( | n | deck . push ( n ) ) ;
deck
}
2019-12-28 13:18:24 +01:00
fn get_original_index (
initial : usize ,
2020-01-02 16:05:45 +01:00
iterations : i128 ,
2019-12-28 13:18:24 +01:00
deck_size : usize ,
2020-01-02 16:05:45 +01:00
operations : & [ ShuffleOperation ] ,
) -> i128 {
2019-12-28 13:18:24 +01:00
let mut last = initial ;
for operation in operations . iter ( ) . rev ( ) {
2020-01-02 16:05:45 +01:00
last = get_previous_index ( last , * operation , deck_size ) ;
}
let initial = initial as i128 ;
let deck_size = deck_size as i128 ;
let drift = last as i128 - initial ;
dbg! ( drift ) ;
let new_index = initial + drift * iterations ;
if new_index > = 0 {
new_index % deck_size
} else {
( new_index + deck_size * ( ( new_index . abs ( ) / deck_size ) + 1 ) ) % deck_size
2019-12-28 13:18:24 +01:00
}
}
2019-12-27 16:35:28 +01:00
fn main ( ) {
2020-01-02 16:05:45 +01:00
let input : Vec < ShuffleOperation > = io ::stdin ( )
. lock ( )
. lines ( )
. map ( | l | ShuffleOperation ::from ( l . unwrap ( ) . as_ref ( ) ) )
. collect ( ) ;
const DECK_SIZE : usize = 10007 ;
2019-12-27 16:43:22 +01:00
let mut deck = create_deck ( DECK_SIZE ) ;
2019-12-28 13:18:24 +01:00
for operation in & input {
2020-01-02 16:05:45 +01:00
apply ( & mut deck , * operation ) ;
2019-12-27 16:35:28 +01:00
}
2019-12-28 13:18:24 +01:00
println! ( " Part 1: {} " , deck . iter ( ) . position ( | & x | x = = 2019 ) . unwrap ( ) ) ;
2020-01-02 16:05:45 +01:00
const P2_DECK_SIZE : usize = 119315717514047 ;
const P2_ITERATIONS : i128 = 101_741_582_076_661 ;
const P2_INDEX : usize = 2020 ;
let mut last = P2_INDEX ;
println! ( " Part 2: {} " , last ) ;
2019-12-27 16:35:28 +01:00
}