diff --git a/Cargo.lock b/Cargo.lock index a5ddce5..08638a6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -34,6 +34,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "day1" version = "0.1.0" +[[package]] +name = "day10" +version = "0.1.0" +dependencies = [ + "itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "day11" +version = "0.1.0" +dependencies = [ + "shared 0.1.0", +] + [[package]] name = "day2" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 22d3d1f..81ada48 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,5 +9,7 @@ members = [ "day7", "day8", "day9", + "day10", + "day11", "shared", ] diff --git a/day10/Cargo.toml b/day10/Cargo.toml new file mode 100644 index 0000000..f25f0cf --- /dev/null +++ b/day10/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "day10" +version = "0.1.0" +authors = ["Stefan Bühler "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +itertools = "0.8.2" diff --git a/day10/src/input.txt b/day10/src/input.txt new file mode 100644 index 0000000..defc148 --- /dev/null +++ b/day10/src/input.txt @@ -0,0 +1,26 @@ +#.#.###.#.#....#..##.#.... +.....#..#..#..#.#..#.....# +.##.##.##.##.##..#...#...# +#.#...#.#####...###.#.#.#. +.#####.###.#.#.####.#####. +#.#.#.##.#.##...####.#.##. +##....###..#.#..#..#..###. +..##....#.#...##.#.#...### +#.....#.#######..##.##.#.. +#.###.#..###.#.#..##.....# +##.#.#.##.#......#####..## +#..##.#.##..###.##.###..## +#..#.###...#.#...#..#.##.# +.#..#.#....###.#.#..##.#.# +#.##.#####..###...#.###.## +#...##..#..##.##.#.##..### +#.#.###.###.....####.##..# +######....#.##....###.#..# +..##.#.####.....###..##.#. +#..#..#...#.####..######.. +#####.##...#.#....#....#.# +.#####.##.#.#####..##.#... +#..##..##.#.##.##.####..## +.##..####..#..####.####### +#.#..#.##.#.######....##.. +.#.##.##.####......#.##.## diff --git a/day10/src/main.rs b/day10/src/main.rs new file mode 100644 index 0000000..1847618 --- /dev/null +++ b/day10/src/main.rs @@ -0,0 +1,107 @@ +use itertools::Itertools; + +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +pub struct Position { + pub x: usize, + pub y: usize, +} + +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +pub struct Field { + rows: usize, + columns: usize, + astroids: Vec, +} + +fn gcd(mut x: isize, mut y: isize) -> isize { + loop { + if y == 0 { return x; } + x = x % y; + if x == 0 { return y; } + y = y % x; + } +} + +impl Field { + pub fn parse(input: &str) -> Self { + let lines = input.lines().collect::>(); + let rows = lines.len(); + let columns = lines[0].len(); + let mut astroids = Vec::new(); + for line in lines { + assert_eq!(columns, line.len()); + for cell in line.chars() { + astroids.push(match cell { + '#' => true, + '.' => false, + _ => panic!("Unexpected cell: {:?}", cell), + }) + } + } + + Self { + rows, + columns, + astroids, + } + } + + pub fn sees(&self, a: Position, b: Position) -> bool { + if a == b { return true; } + let diff_x = b.x as isize - a.x as isize; + let diff_y = b.y as isize - a.y as isize; + let d = gcd(diff_x, diff_y).abs(); + let diff_x = diff_x / d; + let diff_y = diff_y / d; + let mut pos = a; + loop { + pos.x = (pos.x as isize + diff_x) as usize; + pos.y = (pos.y as isize + diff_y) as usize; + if pos == b { return true; } + if self[pos] { return false; } + } + } + + pub fn all_astroids(&self) -> impl Iterator + '_ { + (0..self.columns).cartesian_product(0..self.rows).map(|(x, y)| Position { x, y }).filter(move |pos| self[*pos]) + } + + pub fn best_monitoring_station(&self) -> (Position, usize) { + self.all_astroids().map(|monitor| { + // can see itself, but only count "others" + (monitor, self.all_astroids().filter(|astroid| self.sees(monitor, *astroid)).count() - 1) + }).max_by_key(|(_, n)| *n).unwrap() + } +} + +impl std::ops::Index for Field { + type Output = bool; + + fn index(&self, index: Position) -> &Self::Output { + assert!(index.x < self.columns); + assert!(index.y < self.rows); + &self.astroids[index.y * self.columns + index.x] + } +} + +fn main() { + let input = include_str!("input.txt"); + println!("Best monitoring station sees astroids: {}", Field::parse(input).best_monitoring_station().1); +} + +#[cfg(test)] +mod day10test { + use super::*; + + #[test] + fn examples1() { + assert_eq!( + Field::parse(".#..# +..... +##### +....# +...##").best_monitoring_station(), + (Position { x: 3, y: 4 }, 8), + ); + } +} \ No newline at end of file diff --git a/day11/Cargo.toml b/day11/Cargo.toml new file mode 100644 index 0000000..f50d1ba --- /dev/null +++ b/day11/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "day11" +version = "0.1.0" +authors = ["Stefan Bühler "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +shared = { path = "../shared" } diff --git a/day11/src/input.txt b/day11/src/input.txt new file mode 100644 index 0000000..864e55e --- /dev/null +++ b/day11/src/input.txt @@ -0,0 +1 @@ +3,8,1005,8,309,1106,0,11,0,0,0,104,1,104,0,3,8,102,-1,8,10,101,1,10,10,4,10,1008,8,1,10,4,10,1001,8,0,29,3,8,102,-1,8,10,101,1,10,10,4,10,1008,8,0,10,4,10,102,1,8,51,3,8,102,-1,8,10,1001,10,1,10,4,10,108,0,8,10,4,10,1002,8,1,72,1,1104,8,10,2,1105,15,10,2,1106,0,10,3,8,1002,8,-1,10,1001,10,1,10,4,10,1008,8,1,10,4,10,101,0,8,107,3,8,102,-1,8,10,1001,10,1,10,4,10,108,1,8,10,4,10,101,0,8,128,2,6,8,10,3,8,102,-1,8,10,101,1,10,10,4,10,1008,8,0,10,4,10,102,1,8,155,1006,0,96,2,108,10,10,1,101,4,10,3,8,1002,8,-1,10,101,1,10,10,4,10,1008,8,0,10,4,10,1002,8,1,188,2,1,5,10,3,8,102,-1,8,10,101,1,10,10,4,10,1008,8,0,10,4,10,102,1,8,214,2,6,18,10,1006,0,78,1,105,1,10,3,8,1002,8,-1,10,1001,10,1,10,4,10,1008,8,1,10,4,10,102,1,8,247,2,103,8,10,2,1002,10,10,2,106,17,10,1,1006,15,10,3,8,102,-1,8,10,101,1,10,10,4,10,1008,8,1,10,4,10,101,0,8,285,1,1101,18,10,101,1,9,9,1007,9,992,10,1005,10,15,99,109,631,104,0,104,1,21102,387507921664,1,1,21102,1,326,0,1106,0,430,21102,932826591260,1,1,21102,337,1,0,1106,0,430,3,10,104,0,104,1,3,10,104,0,104,0,3,10,104,0,104,1,3,10,104,0,104,1,3,10,104,0,104,0,3,10,104,0,104,1,21101,206400850983,0,1,21101,0,384,0,1105,1,430,21102,3224464603,1,1,21102,395,1,0,1106,0,430,3,10,104,0,104,0,3,10,104,0,104,0,21102,838433657700,1,1,21102,418,1,0,1106,0,430,21101,825012007272,0,1,21101,429,0,0,1106,0,430,99,109,2,21202,-1,1,1,21101,40,0,2,21101,461,0,3,21102,1,451,0,1105,1,494,109,-2,2105,1,0,0,1,0,0,1,109,2,3,10,204,-1,1001,456,457,472,4,0,1001,456,1,456,108,4,456,10,1006,10,488,1102,1,0,456,109,-2,2106,0,0,0,109,4,1202,-1,1,493,1207,-3,0,10,1006,10,511,21101,0,0,-3,21202,-3,1,1,21201,-2,0,2,21102,1,1,3,21102,1,530,0,1106,0,535,109,-4,2106,0,0,109,5,1207,-3,1,10,1006,10,558,2207,-4,-2,10,1006,10,558,22101,0,-4,-4,1106,0,626,22102,1,-4,1,21201,-3,-1,2,21202,-2,2,3,21101,0,577,0,1106,0,535,22102,1,1,-4,21101,1,0,-1,2207,-4,-2,10,1006,10,596,21102,0,1,-1,22202,-2,-1,-2,2107,0,-3,10,1006,10,618,21201,-1,0,1,21102,618,1,0,105,1,493,21202,-2,-1,-2,22201,-4,-2,-4,109,-5,2105,1,0 diff --git a/day11/src/main.rs b/day11/src/main.rs new file mode 100644 index 0000000..52f273b --- /dev/null +++ b/day11/src/main.rs @@ -0,0 +1,107 @@ +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); +}