From 7abd632567481041802e3cd4e85530b5163a093e Mon Sep 17 00:00:00 2001 From: jazzpi Date: Fri, 23 Dec 2022 12:28:17 +0100 Subject: [PATCH] Day 23, part 1 --- src/bin/d23p1.rs | 19 ++++++++ src/day23.rs | 112 +++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + src/util.rs | 10 +++++ 4 files changed, 142 insertions(+) create mode 100644 src/bin/d23p1.rs create mode 100644 src/day23.rs diff --git a/src/bin/d23p1.rs b/src/bin/d23p1.rs new file mode 100644 index 0000000..b592d78 --- /dev/null +++ b/src/bin/d23p1.rs @@ -0,0 +1,19 @@ +use aoc22::{ + day23::{self, empty_ground}, + util, +}; + +const N_ROUNDS: usize = 10; + +pub fn main() { + let mut elves = day23::parse_map(&util::parse_input()); + + for i in 0..N_ROUNDS { + let elves_too_close = day23::do_round(&mut elves, i); + if !elves_too_close { + break; + } + } + + println!("Elves cover {} empty tiles", empty_ground(&elves)); +} diff --git a/src/day23.rs b/src/day23.rs new file mode 100644 index 0000000..4d474c3 --- /dev/null +++ b/src/day23.rs @@ -0,0 +1,112 @@ +use std::collections::{HashMap, HashSet}; + +use itertools::Itertools; + +use crate::util::{self, SignedCoord}; + +pub fn parse_map(input: &str) -> HashSet { + let mut result = HashSet::new(); + for (y, row) in input.lines().enumerate() { + for (x, c) in row.chars().enumerate() { + if c == '#' { + result.insert((y as isize, x as isize)); + } + } + } + result +} + +const NUM_DIRS: usize = 4; + +pub fn do_round(elves: &mut HashSet, it: usize) -> bool { + let mut proposals: HashMap> = HashMap::new(); + + let mut elves_too_close = false; + for elf in elves.iter() { + if noone_adjacent(elves, elf) { + continue; + } + elves_too_close = true; + for offset in 0..NUM_DIRS { + let dir = (it + offset) % NUM_DIRS; + if let Some(new_loc) = propose(elves, elf, dir) { + proposals.entry(new_loc).or_insert_with(Vec::new).push(*elf); + break; + } + } + } + + for (target, interested) in proposals { + if interested.len() == 1 { + elves.remove(&interested[0]); + elves.insert(target); + } + } + + elves_too_close +} + +fn noone_adjacent(elves: &HashSet, elf: &SignedCoord) -> bool { + !(elves.contains(&(elf.0, elf.1 + 1)) + || elves.contains(&(elf.0, elf.1 - 1)) + || elves.contains(&(elf.0 + 1, elf.1)) + || elves.contains(&(elf.0 + 1, elf.1 + 1)) + || elves.contains(&(elf.0 + 1, elf.1 - 1)) + || elves.contains(&(elf.0 - 1, elf.1)) + || elves.contains(&(elf.0 - 1, elf.1 + 1)) + || elves.contains(&(elf.0 - 1, elf.1 - 1))) +} + +fn propose(elves: &HashSet, elf: &SignedCoord, dir: usize) -> Option { + let (moved, other) = match dir { + 0 => ( + (elf.0 - 1, elf.1), + ((elf.0 - 1, elf.1 - 1), (elf.0 - 1, elf.1 + 1)), + ), // N + 1 => ( + (elf.0 + 1, elf.1), + ((elf.0 + 1, elf.1 - 1), (elf.0 + 1, elf.1 + 1)), + ), // S + 2 => ( + (elf.0, elf.1 - 1), + ((elf.0 - 1, elf.1 - 1), (elf.0 + 1, elf.1 - 1)), + ), // E + 3 => ( + (elf.0, elf.1 + 1), + ((elf.0 - 1, elf.1 + 1), (elf.0 + 1, elf.1 + 1)), + ), // W + _ => panic!("Unknown direction {}", dir), + }; + if elves.contains(&moved) || elves.contains(&other.0) || elves.contains(&other.1) { + None + } else { + Some(moved) + } +} + +pub fn print_map(elves: &HashSet) { + let (y_min, y_max) = util::minmax_unwrap(&elves.iter().map(|c| c.0).minmax()); + let (x_min, x_max) = util::minmax_unwrap(&elves.iter().map(|c| c.1).minmax()); + + println!("({}, {})", y_min, x_min); + for y in y_min..(y_max + 1) { + for x in x_min..(x_max + 1) { + if elves.contains(&(y, x)) { + print!("#"); + } else { + print!("."); + } + } + print!("\n"); + } + print!("\n"); +} + +pub fn empty_ground(elves: &HashSet) -> usize { + let (y_min, y_max) = util::minmax_unwrap(&elves.iter().map(|c| c.0).minmax()); + let (x_min, x_max) = util::minmax_unwrap(&elves.iter().map(|c| c.1).minmax()); + let y_dim = (y_max + 1 - y_min) as usize; + let x_dim = (x_max + 1 - x_min) as usize; + + y_dim * x_dim - elves.len() +} diff --git a/src/lib.rs b/src/lib.rs index 00d4a16..b29a5ad 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,6 +13,7 @@ pub mod day2; pub mod day20; pub mod day21; pub mod day22; +pub mod day23; pub mod day3; pub mod day4; pub mod day5; diff --git a/src/util.rs b/src/util.rs index 8f7d517..52d89cb 100644 --- a/src/util.rs +++ b/src/util.rs @@ -3,6 +3,8 @@ use std::env; use std::fs; use std::hash::Hash; +use itertools::MinMaxResult; + pub fn parse_input() -> String { let args: Vec = env::args().collect(); let input_path = args @@ -153,3 +155,11 @@ impl Dir { Self::from_usize((d + 3) % 4).unwrap() } } + +pub fn minmax_unwrap(mm: &MinMaxResult) -> (T, T) { + match mm { + MinMaxResult::NoElements => panic!("No elements"), + MinMaxResult::OneElement(a) => (a.clone(), a.clone()), + MinMaxResult::MinMax(a, b) => (a.clone(), b.clone()), + } +}