2019-12-17 10:32:15 +01:00
use grid ::* ;
use intcode ::* ;
use std ::char ;
2019-12-17 21:20:22 +01:00
use std ::collections ::{ HashMap , HashSet } ;
2019-12-17 12:38:58 +01:00
use std ::fmt ;
2019-12-17 21:20:22 +01:00
use itertools ::Itertools ;
2019-12-17 12:38:58 +01:00
2019-12-17 14:48:46 +01:00
#[ derive(Debug, PartialEq, Eq, Hash, Clone) ]
2019-12-17 12:38:58 +01:00
struct Movement {
rotation : i8 ,
distance : u8 ,
}
impl fmt ::Display for Movement {
fn fmt ( & self , f : & mut fmt ::Formatter ) -> Result < ( ) , fmt ::Error > {
let dir_char = if self . rotation = = 1 { 'R' } else { 'L' } ;
write! ( f , " {}{} " , dir_char , self . distance )
}
}
#[ rustfmt::skip ]
fn find_commands ( field : & HashMap < Position2D , char > ) -> Vec < Movement > {
let mut robot_position = field . iter ( ) . find ( | ( _ , c ) | * c = = & '^' ) . unwrap ( ) . 0. to_owned ( ) ;
let mut robot_direction = Direction ::Up ;
let mut commands = Vec ::new ( ) ;
loop {
let mut steps = 0 ;
2019-12-17 21:20:22 +01:00
let turn = ( ( field . get ( & ( robot_position + ( robot_direction + 1 ) ) ) = = Some ( & '#' ) ) as i8 ) * 2 - 1 ;
2019-12-17 12:38:58 +01:00
robot_direction + = turn ;
while field . get ( & ( robot_position + robot_direction ) ) = = Some ( & '#' ) {
robot_position + = robot_direction ;
steps + = 1 ;
}
commands . push ( Movement {
distance : steps ,
rotation : turn ,
} ) ;
if robot_position . neighbors ( ) . iter ( ) . filter ( | ( _ , p ) | field . get ( p ) = = Some ( & '#' ) ) . count ( ) = = 1 {
break ;
}
}
commands
}
fn test_input ( ) -> HashMap < Position2D , char > {
" #######...#####
#.. .. . #.. . #.. . #
#.. .. . #.. . #.. . #
.. .. .. #.. . #.. . #
.. .. .. #.. . ###. #
.. .. .. #.. .. . #. #
^ ########.. . #. #
.. .. .. #. #.. . #. #
.. .. .. #########
.. .. .. .. #.. . #..
.. .. #########..
.. .. #.. . #.. .. ..
.. .. #.. . #.. .. ..
.. .. #.. . #.. .. ..
.. .. #####.. .. .. "
. lines ( )
2019-12-17 14:48:46 +01:00
. rev ( )
2019-12-17 12:38:58 +01:00
. enumerate ( )
. flat_map ( move | ( y , s ) | s . chars ( ) . enumerate ( ) . map ( move | ( x , c ) | ( ( x , y ) . into ( ) , c ) ) )
. collect ( )
}
2019-12-17 10:32:15 +01:00
fn main ( ) {
// The main reason I use a hashmap here (instead of a 2D vector) is that my abstractions for
// ascii stuff all use maps ヽ( ゚ヮ・)ノ
2019-12-17 14:48:46 +01:00
let mut input = read_input ( ) ;
let field : HashMap < Position2D , char > = IntComputer ::without_params ( input . clone ( ) )
2019-12-17 10:32:15 +01:00
. get_all_outputs ( )
. iter ( )
. map ( | n | char ::from_u32 ( * n as u32 ) . unwrap ( ) )
. collect ::< String > ( )
. lines ( )
2019-12-17 14:48:46 +01:00
// this rev breaks part 1 but is necessary for part 2
. rev ( )
2019-12-17 10:32:15 +01:00
. enumerate ( )
. flat_map ( move | ( y , s ) | s . chars ( ) . enumerate ( ) . map ( move | ( x , c ) | ( ( x , y ) . into ( ) , c ) ) )
. collect ( ) ;
2019-12-17 21:20:22 +01:00
// let field = test_input();
2019-12-17 10:32:15 +01:00
let p1 = field
2019-12-17 12:38:58 +01:00
. iter ( )
. filter ( | ( pos , obj ) | {
* obj = = & '#'
& & pos
. neighbors ( )
. iter ( )
. all ( | ( _ , p ) | field . get ( & p ) = = Some ( & '#' ) )
} )
. fold ( 0 , | acc , ( pos , _ ) | acc + pos . x * pos . y ) ;
2019-12-17 10:32:15 +01:00
println! ( " Part 1: {} " , p1 ) ;
2019-12-17 12:38:58 +01:00
println! ( " {} " , draw_ascii ( & field , '.' ) ) ;
let commands = find_commands ( & field ) ;
2019-12-17 14:48:46 +01:00
println! ( " Commands: {} " , commands . len ( ) ) ;
2019-12-17 21:20:22 +01:00
for c in commands . iter ( ) {
println! ( " {} " , c ) ;
}
2019-12-17 14:48:46 +01:00
let mut pos = 0 ;
2019-12-17 21:20:22 +01:00
let mut segments = Vec ::new ( ) ;
/* let segments = vec![
2019-12-17 14:48:46 +01:00
vec! [
Movement { rotation : - 1 , distance : 8 } ,
Movement { rotation : 1 , distance : 12 } ,
Movement { rotation : 1 , distance : 12 } ,
Movement { rotation : 1 , distance : 10 } ,
] ,
vec! [
Movement { rotation : 1 , distance : 10 } ,
Movement { rotation : 1 , distance : 12 } ,
Movement { rotation : 1 , distance : 10 } ,
] ,
vec! [
Movement { rotation : - 1 , distance : 10 } ,
Movement { rotation : 1 , distance : 10 } ,
Movement { rotation : - 1 , distance : 6 } ,
]
2019-12-17 21:20:22 +01:00
] ; * /
while pos < commands . len ( ) - 4 {
if let Some ( ( n , mov ) ) = ( 2 ..= 4 )
2019-12-17 14:48:46 +01:00
. filter_map ( | i | {
let reference = commands [ pos .. ] . windows ( i ) . next ( ) ;
2019-12-17 21:20:22 +01:00
if segments . contains ( & reference . unwrap ( ) ) {
Some ( ( ( i , 99 ) , reference ) )
2019-12-17 14:48:46 +01:00
} else {
2019-12-17 21:20:22 +01:00
let dupes = commands [ pos .. ]
. windows ( i )
. filter ( | & w | Some ( w ) = = reference )
. count ( ) ;
if dupes > 0 {
Some ( ( ( i , dupes ) , reference ) )
} else {
None
}
2019-12-17 14:48:46 +01:00
}
} )
2019-12-17 21:20:22 +01:00
. inspect ( | _ | println! ( " hit for {} " , pos ) )
. max_by_key ( | ( ( x , y ) , _ ) | x * y )
2019-12-17 14:48:46 +01:00
{
pos + = n . 0 ;
segments . push ( mov . unwrap ( ) ) ;
2019-12-17 21:20:22 +01:00
} else {
//panic!("nothing found at position {}", pos);
2019-12-17 14:48:46 +01:00
}
}
2019-12-17 21:20:22 +01:00
let filtered : HashSet < _ > = segments
. clone ( )
. into_iter ( )
/*
. map ( | mut curr | {
for s in & segments {
if curr . len ( ) < = s . len ( ) {
continue ;
}
let index_after = curr . len ( ) - s . len ( ) ;
if s = = & & curr [ index_after .. ] {
curr = & curr [ .. index_after ] ;
}
if s = = & & curr [ .. index_after ] {
curr = & curr [ index_after .. ] ;
}
2019-12-17 14:48:46 +01:00
}
2019-12-17 21:20:22 +01:00
curr
} )
. filter ( | s | ! s . is_empty ( ) )
* /
. collect ( ) ;
let mut filtered : Vec < _ > = filtered
. into_iter ( )
. zip ( [ 'A' , 'B' , 'C' ] . iter ( ) )
. collect ( ) ;
filtered . sort_by_key ( | ( _ , c ) | c . to_owned ( ) ) ;
dbg! ( & segments , segments . len ( ) ) ;
2019-12-17 14:48:46 +01:00
dbg! ( filtered . len ( ) ) ;
println! (
" {} " ,
filtered
. iter ( )
2019-12-17 21:20:22 +01:00
. map ( | s | s . 0. iter ( ) . map ( | m | m . to_string ( ) ) . collect ::< String > ( ) + " \n " )
2019-12-17 14:48:46 +01:00
. collect ::< String > ( )
) ;
2019-12-17 21:20:22 +01:00
//let filtered = segments;
2019-12-17 14:48:46 +01:00
let mut instructions = Vec ::new ( ) ;
let mut pos = 0 ;
while pos < commands . len ( ) {
2019-12-17 21:20:22 +01:00
println! ( " searching " ) ;
2019-12-17 14:48:46 +01:00
for i in 1 .. {
2019-12-17 21:20:22 +01:00
if filtered . iter ( ) . any ( | ( c , _ ) | c = = & & commands [ pos .. pos + i ] ) {
instructions . push ( & commands [ pos .. pos + i ] ) ;
2019-12-17 14:48:46 +01:00
pos + = i ;
println! ( " match for {} .. {} " , pos , i ) ;
break ;
} else {
println! ( " no match for {} .. {} " , pos , i ) ;
}
}
}
2019-12-17 21:20:22 +01:00
fn dir ( rotation : i8 ) -> char {
if rotation = = 1 { 'R' } else { 'L' }
2019-12-17 12:38:58 +01:00
}
2019-12-17 14:48:46 +01:00
input [ 0 ] = 2 ;
2019-12-17 21:20:22 +01:00
let raw_path = ( instructions . iter ( ) . map ( | i | filtered . iter ( ) . find ( | ( f , c ) | i = = f ) . unwrap ( ) . 1 ) . join ( " , " )
+ " \n "
+ & filtered . into_iter ( ) . map ( | ( f , _ ) | f . iter ( ) . map ( | m | format! ( " {} , {} " , dir ( m . rotation ) , m . distance ) ) . join ( " , " ) ) . join ( " \n " )
+ " \n n \n " ) ;
let path : Vec < i64 > = raw_path
. chars ( )
. map ( | c | c as i64 )
. rev ( )
. collect ( ) ;
println! (
" Part 2: {:?} " ,
IntComputer ::new ( input , 0 , path ) . get_all_outputs ( ) . pop ( )
) ;
2019-12-17 10:32:15 +01:00
}