2019-12-11 19:28:40 +01:00
use intcode ::* ;
2019-12-11 20:09:22 +01:00
use itertools ::join ;
2019-12-11 19:28:40 +01:00
use std ::collections ::HashMap ;
enum Direction {
Up ,
Down ,
Left ,
Right ,
}
2019-12-11 20:09:22 +01:00
struct Robot {
direction : Direction ,
position : ( i64 , i64 ) ,
visited : HashMap < ( i64 , i64 ) , i64 > ,
2019-12-11 19:28:40 +01:00
}
2019-12-11 20:09:22 +01:00
impl Robot {
fn turn ( & mut self , turn_value : i64 ) {
self . direction = match turn_value {
0 = > match self . direction {
Direction ::Up = > Direction ::Left ,
Direction ::Right = > Direction ::Up ,
Direction ::Down = > Direction ::Right ,
Direction ::Left = > Direction ::Down ,
} ,
1 = > match self . direction {
Direction ::Up = > Direction ::Right ,
Direction ::Right = > Direction ::Down ,
Direction ::Down = > Direction ::Left ,
Direction ::Left = > Direction ::Up ,
} ,
_ = > unreachable! ( " Illegal turn value " ) ,
}
}
fn mv ( & mut self ) {
let pos = self . position ;
self . position = match self . direction {
Direction ::Up = > ( pos . 0 , pos . 1 + 1 ) ,
Direction ::Right = > ( pos . 0 + 1 , pos . 1 ) ,
Direction ::Left = > ( pos . 0 - 1 , pos . 1 ) ,
Direction ::Down = > ( pos . 0 , pos . 1 - 1 ) ,
}
}
fn paint ( & mut self , color : i64 ) {
self . visited . insert ( self . position , color ) ;
}
fn current_color ( & self ) -> i64 {
* self . visited . get ( & self . position ) . unwrap_or ( & 0 )
2019-12-11 19:28:40 +01:00
}
}
2019-12-11 20:09:22 +01:00
#[ rustfmt::skip ]
fn get_boundaries ( positions : & HashMap < ( i64 , i64 ) , i64 > ) -> ( i64 , i64 , i64 , i64 ) {
let keys = positions . keys ( ) ;
let x_max = keys . clone ( ) . into_iter ( ) . max_by_key ( | k | k . 0 ) . unwrap ( ) . 0 ;
let y_max = keys . clone ( ) . into_iter ( ) . max_by_key ( | k | k . 1 ) . unwrap ( ) . 1 ;
let x_min = keys . clone ( ) . into_iter ( ) . min_by_key ( | k | k . 0 ) . unwrap ( ) . 0 ;
let y_min = keys . clone ( ) . into_iter ( ) . min_by_key ( | k | k . 1 ) . unwrap ( ) . 1 ;
( x_min , x_max , y_min , y_max )
}
fn start_with_input ( input : Vec < i64 > , color : i64 ) -> Robot {
let mut robot = Robot {
position : ( 0 , 0 ) ,
visited : HashMap ::new ( ) ,
direction : Direction ::Up ,
} ;
let mut pc = IntComputer ::new ( input , 0 , vec! [ color ] ) ;
2019-12-11 19:28:40 +01:00
while let IntComputerResult ::Output ( o ) = pc . run ( ) {
2019-12-11 20:09:22 +01:00
robot . paint ( o ) ;
2019-12-11 19:28:40 +01:00
let turn_int = pc . run ( ) . unwrap ( ) ;
2019-12-11 20:09:22 +01:00
robot . turn ( turn_int ) ;
robot . mv ( ) ;
pc . params . push ( robot . current_color ( ) ) ;
2019-12-11 19:28:40 +01:00
}
2019-12-11 20:09:22 +01:00
robot
}
fn draw_ascii_text ( coordinates : & HashMap < ( i64 , i64 ) , i64 > ) -> String {
let ( x_min , x_max , y_min , y_max ) = get_boundaries ( & coordinates ) ;
join (
( y_min .. y_max + 1 ) . rev ( ) . map ( | y | {
2019-12-11 19:40:22 +01:00
( x_min .. x_max )
2019-12-11 20:09:22 +01:00
. map ( | x | coordinates . get ( & ( x , y ) ) . unwrap_or ( & 0 ) . to_string ( ) )
2019-12-11 19:40:22 +01:00
. collect ::< String > ( )
. replace ( '0' , " " )
. replace ( '1' , " █ " )
2019-12-11 20:09:22 +01:00
} ) ,
" \n " ,
)
}
fn main ( ) {
let input = read_input ( ) ;
let part1_robot = start_with_input ( input . clone ( ) , 0 ) ;
println! ( " Part 1: {} " , part1_robot . visited . len ( ) ) ;
let part2_robot = start_with_input ( input . clone ( ) , 1 ) ;
println! ( " Part 2: \n {} " , draw_ascii_text ( & part2_robot . visited ) ) ;
2019-12-11 19:28:40 +01:00
}