@ -0,0 +1,10 @@ | |||
[package] | |||
name = "day10" | |||
version = "0.1.0" | |||
authors = ["Stefan Bühler <stbuehler@web.de>"] | |||
edition = "2018" | |||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | |||
[dependencies] | |||
itertools = "0.8.2" |
@ -0,0 +1,26 @@ | |||
#.#.###.#.#....#..##.#.... | |||
.....#..#..#..#.#..#.....# | |||
.##.##.##.##.##..#...#...# | |||
#.#...#.#####...###.#.#.#. | |||
.#####.###.#.#.####.#####. | |||
#.#.#.##.#.##...####.#.##. | |||
##....###..#.#..#..#..###. | |||
..##....#.#...##.#.#...### | |||
#.....#.#######..##.##.#.. | |||
#.###.#..###.#.#..##.....# | |||
##.#.#.##.#......#####..## | |||
#..##.#.##..###.##.###..## | |||
#..#.###...#.#...#..#.##.# | |||
.#..#.#....###.#.#..##.#.# | |||
#.##.#####..###...#.###.## | |||
#...##..#..##.##.#.##..### | |||
#.#.###.###.....####.##..# | |||
######....#.##....###.#..# | |||
..##.#.####.....###..##.#. | |||
#..#..#...#.####..######.. | |||
#####.##...#.#....#....#.# | |||
.#####.##.#.#####..##.#... | |||
#..##..##.#.##.##.####..## | |||
.##..####..#..####.####### | |||
#.#..#.##.#.######....##.. | |||
.#.##.##.####......#.##.## |
@ -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<bool>, | |||
} | |||
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::<Vec<_>>(); | |||
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<Item = Position> + '_ { | |||
(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<Position> 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), | |||
); | |||
} | |||
} |
@ -0,0 +1,10 @@ | |||
[package] | |||
name = "day11" | |||
version = "0.1.0" | |||
authors = ["Stefan Bühler <stbuehler@web.de>"] | |||
edition = "2018" | |||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | |||
[dependencies] | |||
shared = { path = "../shared" } |
@ -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 |
@ -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<Direction> 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<Position, bool> { | |||
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<Position, bool>) { | |||
let painted_white: HashSet<Position> = 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::<IntCode>().unwrap(); | |||
let painted = paint(ic.clone(), false); | |||
println!("First try: Painted {} tiles.", painted.len()); | |||
let painted = paint(ic, true); | |||
visualize(painted); | |||
} |