use shared::intcode::{IntCode, SimulateStep}; use std::collections::{HashMap, HashSet}; #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] pub enum Direction { Up, Right, Down, Left, } impl Direction { pub fn turn_right(self) -> Self { match self { Self::Up => Self::Right, Self::Right => Self::Down, Self::Down => Self::Left, Self::Left => Self::Up, } } pub fn turn_left(self) -> Self { match self { Self::Up => Self::Left, Self::Right => Self::Up, Self::Down => Self::Right, Self::Left => Self::Down, } } } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] pub struct Position { pub x: isize, pub y: isize, } impl std::ops::Add for Position { type Output = Position; fn add(mut self, rhs: Direction) -> Self::Output { match rhs { Direction::Up => self.y -= 1, Direction::Right => self.x += 1, Direction::Down => self.y += 1, Direction::Left => self.x -= 1, } self } } fn paint(mut ic: IntCode, start_white: bool) -> HashMap { let mut painted = HashMap::new(); let mut pos = Position { x: 0, y: 0 }; let mut direction = Direction::Up; if start_white { painted.insert(pos, true); } loop { let is_white = painted.get(&pos).cloned().unwrap_or(false); ic.next_input = Some(if is_white { 1 } else { 0 }); match ic.simulate_step() { SimulateStep::WaitForInput => panic!("no further input until paint and movement done"), SimulateStep::Finished => break, SimulateStep::Output(n) => { match n { 0 => { painted.insert(pos, false); }, 1 => { painted.insert(pos, true); }, _ => panic!("invalid paint: {}", n), } } } match ic.simulate_step().expect_output() { 0 => direction = direction.turn_left(), 1 => direction = direction.turn_right(), n => panic!("invalid rotation: {}", n), } pos = pos + direction; } painted } fn visualize(painted: HashMap) { let painted_white: HashSet = painted.into_iter().filter_map(|(k, v)| if v { Some(k) } else { None }).collect(); let left = painted_white.iter().map(|p| p.x).min().unwrap(); let right = painted_white.iter().map(|p| p.x).max().unwrap(); let top = painted_white.iter().map(|p| p.y).min().unwrap(); let bottom = painted_white.iter().map(|p| p.y).max().unwrap(); for y in top..=bottom { for x in left..=right { if painted_white.contains(&Position { x, y }) { print!("#"); } else { print!(" "); } } println!(""); } } fn main() { let ic = include_str!("input.txt").parse::().unwrap(); let painted = paint(ic.clone(), false); println!("First try: Painted {} tiles.", painted.len()); let painted = paint(ic, true); visualize(painted); }