Solve day23
This commit is contained in:
parent
9af717658a
commit
7a214d2591
75
day23/input
Normal file
75
day23/input
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
.#..###.##..##.####.#.....##.##.#..#.##.#..#.#.#.####..#####.#......#...#..
|
||||||
|
###...#.#..##...#.##...#.###.###....##..##..######.#.#..#.#...#.##...#.#.#.
|
||||||
|
.......#.###.....#.##.....##..#.#...##..#####.###.##......#.###.##.#####.##
|
||||||
|
##.##...##..####.##.........#.##.#.#..####.##....#.#####.####.####..##..##.
|
||||||
|
#..#.###...###...#..#..#..#.#.##.######.###..##########.#..#.##.#.#.##....#
|
||||||
|
.#..#..##..#.#.......#.#....#######..#.##.##..##.#.#.#..#.##....#..##.#####
|
||||||
|
.#.##..##.##...#.##.##..##.##.##..##...###..###.#...##..##....#.##....#####
|
||||||
|
.###.###.#.##.###....#..###..###..##.#.#.#.#....#####.###.######...###.###.
|
||||||
|
#...####.###.....#.....###...#..##.##...########.#.#.######...#..#.###....#
|
||||||
|
..###.#.###..#.#.........#....#.#.#####.#.#.#....###.##..###...####.#.#...#
|
||||||
|
###.#.######.##.#.##....##.##..##.#.#..#.#..##..#..##.###..##.########.#.#.
|
||||||
|
.#...##.....###...##..###.#.##.....#.##..#.#.#..##.#...#.#.#.###.#....#.##.
|
||||||
|
..####.#.#.###....###.#.....##...#.##.#...#..#.#..#####...######....#..##.#
|
||||||
|
.##.#..##.###.###..#.#.#####.#.###......###..#.#..#..###..###..#.....#..##.
|
||||||
|
#.#.#####..##.##...#...#...#..#...#.#.#..#........######.##.#...#..#.#..##.
|
||||||
|
.#.####....#.#..##.##..#...##.##...##.....###.###.###..#.#....#.#.####.#..#
|
||||||
|
##.#..#.###..###........#...##.#..##...####.##..#..#.##.#....##..##..#####.
|
||||||
|
...#..##.#..##.####..###...#.#.#.......#####..######....###..#.#..###.###..
|
||||||
|
.#.##...#.#.#........##..#.#####.#####...##......#.##.....#..####..#####...
|
||||||
|
.#.#..#..#.#.#.####.#...###.###.#..###...###.##..##...##..####.#.....#.#.##
|
||||||
|
##...#.#...##..##..##..##.####..######...##..#...##..##.##....##...#.#.....
|
||||||
|
..####.#####..##.####...#...#...#.#.#..##.##..#...###.#..#...#...#.#...#.##
|
||||||
|
..###.#....#.########...##....#..#.#.#..#.##..#...#.##.....#.###..#..#..#.#
|
||||||
|
#.##....###.#..##.#.##..####..###......####.###.##..###....#..#.#.#...####.
|
||||||
|
.######.#....#....#####...#..#..###.#..#...#.###.#.##..#.###..#..###......#
|
||||||
|
#..##.#.#####.#.#.##.#..###.#..#..#.#..#.#..#.#.....##########.#..#..#..#.#
|
||||||
|
###.##....#...####.###..##..#....#.#......#.#.#......#..##.#..####...#..#.#
|
||||||
|
..#.###..#.###.##.#..#....#..#####.#.#.####.#...#....#.##.#.#..###.########
|
||||||
|
..#.#.....##.##...#..##...#.#..##.####.###.#.#..#..####...#..##..##..#.###.
|
||||||
|
.###..#.###....#.####.#..#...###.#....#...#....###.#.######.####..#.#..###.
|
||||||
|
.#.##.##.....#.###.#...#..#.#.##.##..#.#..###.##..#.##....##....#.#...#.##.
|
||||||
|
#.##.#..#.#.#....##...####.#..#.###..######.###.#..##.#.#.#####...##..#.##.
|
||||||
|
#.###.##.#..#...#..##..#.##.....#...#....#...##....#..#..##..##.##....##.##
|
||||||
|
..###..#...#.#..##.##..#####.#..#.#..#...#...##.#.#..#..#.###....#.####.###
|
||||||
|
###.###...####..###..#..#.##..#.#.#.....#....#.#####.#..###.#..####....##.#
|
||||||
|
#.###.#.#.##.###.##.........###.#..#######.####..........#.#.###..#.#.##.#.
|
||||||
|
####.##.#####.##.#.#.##......#...#.#.##..###..#...#...###..###.#####..##...
|
||||||
|
.##...#####.##########.#....##.......#.#.#.#.###..#####....#..#.####..#####
|
||||||
|
####..#..####.###..###..#####.###....#.#.#.....#.####..#..###.#..##.##..##.
|
||||||
|
###.#.#....##..#.##.#.....##..##.##..##.###.##.#.#...####...#.##..####..##.
|
||||||
|
#..#..##.#....###..##.#..#...#.#.#.#.######.##..#...##.#.#.....####..##.##.
|
||||||
|
....####..###.#.##..#...#..##..#####.....##.##..#.##..##...#####.....##..#.
|
||||||
|
.##...##...######..##..#.##..##.#.#..##.##..###.#.####...#######..##....#..
|
||||||
|
.###.##.#......###....#####.#.#.##...#####..#..##.###...##...###.#.##...##.
|
||||||
|
.#....####..#..#..##...##....#.##...###..##.#..#.#.#.#.####.....###...#.###
|
||||||
|
##.###..#....##....#.##..#.#.....#...###..##..###....#.....###...##.....###
|
||||||
|
##......#.##.#.###...##..###.....#.##.#..#.###..###.#.##...#####..###..#.##
|
||||||
|
##.##.#####........#..##........#..##..##......#.###.#.#..##.######.#....##
|
||||||
|
##.....#.##...#.####.####...#.###.#....#.######.#....#.#.##....#...##..##.#
|
||||||
|
#.##.....#####.###.###.##.#.#.#..#....#.....#.#..###.####.#####...#.......#
|
||||||
|
...#######......###.##.#.#.#.....######.#.##.#.#...#..#.#....#.#.#.##..###.
|
||||||
|
#.###..#.##.#####..#.#...##.####.###.#####..#.....#...#.#..##.#.####.##.#..
|
||||||
|
.##..##...##....#####.#...####..#....#..##.#...#####.#.##...#.####.###...##
|
||||||
|
..####.###...##.##.#..#.###.##..#....#.#....###.#..##.#.....#.###....##.#..
|
||||||
|
#.##.#...#..##.####.######.##..#.#......#.###...#..##.#..##..###.#..#.#.#.#
|
||||||
|
..##.##..#..#.####.###.#...##.###.###.##..##.###....##...##.#..##.###...##.
|
||||||
|
.####..#....#####..#..##....#.#.##.#####.#####..#.....###.#..###.####......
|
||||||
|
##...#.#.#..##..##....##.###...#.##..#..#....###....#####.##..##.....####.#
|
||||||
|
#..####...####..##..#..#..#.#.....##.#..#####..#.#.###.#..###.....#.#.###.#
|
||||||
|
.##..####.####...#.#....##..#####..#...#...#..###..##......#...#..#.##.###.
|
||||||
|
#..##..###.###.#.#..##..#.#.###....##..##.###.#..#....#.#.#..#..##.#..####.
|
||||||
|
#.####..##....#...#.#...###..#..##...##.#.#.#.#...#..#...##...#...#.#....#.
|
||||||
|
#..###.###...###.#.###.#....#..##....#.#.#..#.##.###.#####..##.###...#.#...
|
||||||
|
.#..###.#.#..#.#.#...####.#.#.##.###.#..##.##.......#.#.#.#.#...#..#.#...##
|
||||||
|
######.....###...#..#..###.#.#...#...##..##.##.#..#.#...###.##.##....#.#...
|
||||||
|
#..##...#...##...###..#....#...###.#.###.###..#..##.##..####..#.###.##....#
|
||||||
|
..##...#..#.#.#######..#.###..#.#.#.#.##.#..#.....#.##.###.#####.#.######..
|
||||||
|
#.#.#..##.#.###.#....#..#..######.#....##.#..###.####.#......#..##.##.##.##
|
||||||
|
######....##......#..#...####..###..######.#.#.##....#...##.#.#..#.#.#.##..
|
||||||
|
###.####.###.#####.....######..#...#.##.#....##.#.##..#.#.##.#.##..###..###
|
||||||
|
..######....####..###..##..##.##...#.###..#.##..#.#...#.##.##.....#..#..###
|
||||||
|
.##..##..#.##....#...##.###.##..#...##..##.##.#.#..###...##....#.#.#..#...#
|
||||||
|
..#..##.########.##..#####.#....#..##.##.##.#...#.##..##.#..#..###...#.#.##
|
||||||
|
#.##....#..#.#..##.#......#.#..##.#.............#.##.#...##.#..#...##.#.###
|
||||||
|
#..#..###.#.##.#..#....##..#..#..##.##..#.##...###.......#..###..####...##.
|
7
day23/input.test
Normal file
7
day23/input.test
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
....#..
|
||||||
|
..###.#
|
||||||
|
#...#.#
|
||||||
|
.#...##
|
||||||
|
#.###..
|
||||||
|
##.#.##
|
||||||
|
.#..#..
|
|
@ -1,3 +1,257 @@
|
||||||
fn main() {
|
use std::{
|
||||||
println!("Hello, world!");
|
collections::{HashMap, HashSet},
|
||||||
|
fs::File,
|
||||||
|
io::{BufRead, BufReader},
|
||||||
|
ops::Index,
|
||||||
|
};
|
||||||
|
|
||||||
|
type Elf = (isize, isize);
|
||||||
|
|
||||||
|
const ACTIONS: [Dir; 4] = [Dir::North, Dir::South, Dir::West, Dir::East];
|
||||||
|
|
||||||
|
#[derive(Debug, Default, PartialEq, Eq)]
|
||||||
|
enum SolvePuzzle {
|
||||||
|
First,
|
||||||
|
#[default]
|
||||||
|
Second,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Playground {
|
||||||
|
elves: HashSet<Elf>,
|
||||||
|
first_action_index: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Playground {
|
||||||
|
fn parse_input<R: BufRead>(reader: R) -> Self {
|
||||||
|
let elves = reader
|
||||||
|
.lines()
|
||||||
|
.map(Result::unwrap)
|
||||||
|
.enumerate()
|
||||||
|
.flat_map(|(y, line)| {
|
||||||
|
line.into_bytes()
|
||||||
|
.into_iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter_map(move |(x, byte)| {
|
||||||
|
if byte == b'#' {
|
||||||
|
Some((x as isize, y as isize))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
Self {
|
||||||
|
elves,
|
||||||
|
first_action_index: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn simulate_round(&mut self) -> HasMoved {
|
||||||
|
let mut any_moved = false;
|
||||||
|
let proposed_moves: HashMap<Elf, Elf> = self
|
||||||
|
.elves
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.filter_map(|elf| {
|
||||||
|
let surr = Surrounding::for_elf(&self.elves, &elf);
|
||||||
|
// Do nothing if there's noone around
|
||||||
|
if surr.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let mut proposed_move = None;
|
||||||
|
for action_idx in self.first_action_index..self.first_action_index + 4 {
|
||||||
|
let action = ACTIONS[action_idx % ACTIONS.len()];
|
||||||
|
if surr.is_dir_empty(action) {
|
||||||
|
proposed_move = Some(action);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
proposed_move.map(|dir| (elf, dir.apply_to(elf)))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let mut illegal_moves: HashSet<Elf> = HashSet::new();
|
||||||
|
proposed_moves
|
||||||
|
.iter()
|
||||||
|
.fold(HashSet::new(), |mut set, (_from, to)| {
|
||||||
|
if set.contains(&to) {
|
||||||
|
illegal_moves.insert(*to);
|
||||||
|
} else {
|
||||||
|
set.insert(to);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
});
|
||||||
|
proposed_moves
|
||||||
|
.into_iter()
|
||||||
|
.filter(|(_from, to)| !illegal_moves.contains(to))
|
||||||
|
.for_each(|(from, to)| {
|
||||||
|
self.elves.remove(&from);
|
||||||
|
self.elves.insert(to);
|
||||||
|
any_moved = true;
|
||||||
|
});
|
||||||
|
self.first_action_index = (self.first_action_index + 1) % ACTIONS.len();
|
||||||
|
match any_moved {
|
||||||
|
true => HasMoved::Yes,
|
||||||
|
false => HasMoved::No,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn count_empty_tiles(self) -> usize {
|
||||||
|
// Calculate empty tiles
|
||||||
|
let (min_x, max_x, min_y, max_y, total_elf_count) = self.elves.into_iter().fold(
|
||||||
|
(isize::MAX, isize::MIN, isize::MAX, isize::MIN, 0),
|
||||||
|
|(min_x, max_x, min_y, max_y, count), (x, y)| {
|
||||||
|
(
|
||||||
|
min_x.min(x),
|
||||||
|
max_x.max(x),
|
||||||
|
min_y.min(y),
|
||||||
|
max_y.max(y),
|
||||||
|
count + 1,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
((max_x - min_x + 1) * (max_y - min_y + 1) - total_elf_count) as usize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
enum Dir {
|
||||||
|
North,
|
||||||
|
East,
|
||||||
|
South,
|
||||||
|
West,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dir {
|
||||||
|
fn apply_to(&self, (x, y): Elf) -> Elf {
|
||||||
|
match self {
|
||||||
|
Dir::North => (x, y - 1),
|
||||||
|
Dir::East => (x + 1, y),
|
||||||
|
Dir::South => (x, y + 1),
|
||||||
|
Dir::West => (x - 1, y),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
enum DirDiag {
|
||||||
|
North = 0,
|
||||||
|
NorthEast,
|
||||||
|
East,
|
||||||
|
SouthEast,
|
||||||
|
South,
|
||||||
|
SouthWest,
|
||||||
|
West,
|
||||||
|
NorthWest,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Surrounding {
|
||||||
|
raw: [bool; 8],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Surrounding {
|
||||||
|
fn for_elf(elves: &HashSet<Elf>, &(x, y): &Elf) -> Self {
|
||||||
|
let raw = [
|
||||||
|
(x, y - 1),
|
||||||
|
(x + 1, y - 1),
|
||||||
|
(x + 1, y),
|
||||||
|
(x + 1, y + 1),
|
||||||
|
(x, y + 1),
|
||||||
|
(x - 1, y + 1),
|
||||||
|
(x - 1, y),
|
||||||
|
(x - 1, y - 1),
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.map(|(x, y)| elves.get(&(x, y)).is_some())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.try_into()
|
||||||
|
.unwrap();
|
||||||
|
Self { raw }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_empty(&self) -> bool {
|
||||||
|
!self.raw.iter().any(|&b| b)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_dir_empty(&self, action: Dir) -> bool {
|
||||||
|
use DirDiag::*;
|
||||||
|
let any = match action {
|
||||||
|
Dir::North => self[North] || self[NorthWest] || self[NorthEast],
|
||||||
|
Dir::East => self[East] || self[NorthEast] || self[SouthEast],
|
||||||
|
Dir::South => self[South] || self[SouthWest] || self[SouthEast],
|
||||||
|
Dir::West => self[West] || self[NorthWest] || self[SouthWest],
|
||||||
|
};
|
||||||
|
!any
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum HasMoved {
|
||||||
|
Yes,
|
||||||
|
No,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn solve_first_puzzle<R: BufRead>(reader: R) -> usize {
|
||||||
|
let mut playground = Playground::parse_input(reader);
|
||||||
|
for _ in 1..11 {
|
||||||
|
playground.simulate_round();
|
||||||
|
}
|
||||||
|
playground.count_empty_tiles()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn solve_second_puzzle<R: BufRead>(reader: R) -> usize {
|
||||||
|
let mut playground = Playground::parse_input(reader);
|
||||||
|
let mut curr_round = 1;
|
||||||
|
loop {
|
||||||
|
let has_moved = playground.simulate_round();
|
||||||
|
if let HasMoved::No = has_moved {
|
||||||
|
break curr_round;
|
||||||
|
}
|
||||||
|
curr_round += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut args = ::std::env::args().skip(1);
|
||||||
|
let file = args.next().unwrap_or_else(|| String::from("./input"));
|
||||||
|
let solve = args
|
||||||
|
.next()
|
||||||
|
.map(|arg| match arg.as_str() {
|
||||||
|
"first" => SolvePuzzle::First,
|
||||||
|
"second" => SolvePuzzle::Second,
|
||||||
|
_ => unreachable!(),
|
||||||
|
})
|
||||||
|
.unwrap_or_default();
|
||||||
|
let file = BufReader::new(File::open(file).expect("Opening file"));
|
||||||
|
match solve {
|
||||||
|
SolvePuzzle::First => println!("{}", solve_first_puzzle(file)),
|
||||||
|
SolvePuzzle::Second => println!("{}", solve_second_puzzle(file)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Index<DirDiag> for Surrounding {
|
||||||
|
type Output = bool;
|
||||||
|
|
||||||
|
fn index(&self, index: DirDiag) -> &Self::Output {
|
||||||
|
&self.raw[index as usize]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::io::Cursor;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn example_on_first() {
|
||||||
|
let reader = Cursor::new(include_str!("../input.test"));
|
||||||
|
assert_eq!(solve_first_puzzle(reader), 110);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn example_on_second() {
|
||||||
|
let reader = Cursor::new(include_str!("../input.test"));
|
||||||
|
assert_eq!(solve_second_puzzle(reader), 20);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue