diff --git a/2019/11/Cargo.toml b/2019/11/Cargo.toml index 5a8b539..3695414 100644 --- a/2019/11/Cargo.toml +++ b/2019/11/Cargo.toml @@ -8,3 +8,4 @@ edition = "2018" [dependencies] intcode = { path = "../intcode" } +itertools = "0.8.2" diff --git a/2019/11/src/main.rs b/2019/11/src/main.rs index db321dd..fb1be78 100644 --- a/2019/11/src/main.rs +++ b/2019/11/src/main.rs @@ -1,4 +1,5 @@ use intcode::*; +use itertools::join; use std::collections::HashMap; enum Direction { @@ -8,83 +9,96 @@ enum Direction { Right, } -fn turn(dir: Direction, turn_value: i64) -> Direction { - match turn_value { - 0 => match dir { - Direction::Up => Direction::Left, - Direction::Right => Direction::Up, - Direction::Down => Direction::Right, - Direction::Left => Direction::Down, - }, - 1 => match dir { - Direction::Up => Direction::Right, - Direction::Right => Direction::Down, - Direction::Down => Direction::Left, - Direction::Left => Direction::Up, - }, - _ => unreachable!("Illegal turn value"), +struct Robot { + direction: Direction, + position: (i64, i64), + visited: HashMap<(i64, i64), i64>, +} + +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) } } -fn mv(pos: (i64, i64), dir: &Direction) -> (i64, i64) { - match dir { - 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), - } +#[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 main() { - let mut positions = HashMap::new(); - let mut pc = IntComputer::new(read_input(), 0, vec![1]); - let mut pos = (0, 0); - let mut direction = Direction::Up; +fn start_with_input(input: Vec, 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]); while let IntComputerResult::Output(o) = pc.run() { - positions.insert(pos, o); + robot.paint(o); let turn_int = pc.run().unwrap(); - direction = turn(direction, turn_int); - pos = mv(pos, &direction); - pc.params.push(*positions.get(&pos).unwrap_or(&0)); + robot.turn(turn_int); + robot.mv(); + pc.params.push(robot.current_color()); } - // - println!("Part 1: {}", positions.len()); - let x_max = positions - .clone() - .keys() - .into_iter() - .max_by_key(|k| k.0) - .unwrap() - .0; - let y_max = positions - .clone() - .keys() - .into_iter() - .max_by_key(|k| k.1) - .unwrap() - .1; - let x_min = positions - .clone() - .keys() - .into_iter() - .min_by_key(|k| k.0) - .unwrap() - .0; - let y_min = positions - .clone() - .keys() - .into_iter() - .min_by_key(|k| k.1) - .unwrap() - .1; - for y in (y_min..y_max+1).rev() { - println!( - "{}", + 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| { (x_min..x_max) - .map(|x| positions.get(&(x, y)).unwrap_or(&0).to_string()) + .map(|x| coordinates.get(&(x, y)).unwrap_or(&0).to_string()) .collect::() .replace('0', " ") .replace('1', "█") - ); - } + }), + "\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)); }