mirror of
https://github.com/bertptrs/adventofcode.git
synced 2025-12-25 21:00:31 +01:00
140 lines
2.9 KiB
Rust
140 lines
2.9 KiB
Rust
use std::collections::HashMap;
|
|
use std::collections::HashSet;
|
|
use std::io::Read;
|
|
use std::mem::swap;
|
|
|
|
use crate::common::Lines;
|
|
use crate::Solution;
|
|
|
|
type Pos = (i32, i32);
|
|
|
|
const DIRECTIONS: [Pos; 6] = [(-2, 0), (2, 0), (-1, -1), (-1, 1), (1, -1), (1, 1)];
|
|
|
|
fn convert_pos(s: &str) -> Pos {
|
|
let mut s = s.chars();
|
|
|
|
let mut x = 0;
|
|
let mut y = 0;
|
|
|
|
while let Some(c) = s.next() {
|
|
match c {
|
|
'e' => x += 2,
|
|
'w' => x -= 2,
|
|
'n' | 's' => {
|
|
if c == 'n' {
|
|
y += 1;
|
|
} else {
|
|
y -= 1;
|
|
}
|
|
|
|
match s.next() {
|
|
Some('e') => x += 1,
|
|
Some('w') => x -= 1,
|
|
_ => panic!(),
|
|
}
|
|
}
|
|
_ => panic!(),
|
|
}
|
|
}
|
|
|
|
(x, y)
|
|
}
|
|
|
|
fn step(current: &HashSet<Pos>, target: &mut HashSet<Pos>) {
|
|
let mut black_count: HashMap<Pos, u32> = current.iter().map(|&pos| (pos, 0)).collect();
|
|
|
|
for &(x, y) in current {
|
|
for &(dx, dy) in &DIRECTIONS {
|
|
let pos = (x + dx, y + dy);
|
|
|
|
*black_count.entry(pos).or_default() += 1;
|
|
}
|
|
}
|
|
|
|
target.clear();
|
|
|
|
for (pos, neighbours) in black_count {
|
|
let is_black = current.contains(&pos);
|
|
|
|
let going_black = match neighbours {
|
|
1 | 2 if is_black => true,
|
|
2 if !is_black => true,
|
|
_ => false,
|
|
};
|
|
|
|
if going_black {
|
|
target.insert(pos);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn get_black_tiles(input: &mut dyn Read) -> HashSet<Pos> {
|
|
let mut black = HashSet::new();
|
|
|
|
for line in Lines::new(input) {
|
|
let pos = convert_pos(&line);
|
|
|
|
if !black.insert(pos) {
|
|
black.remove(&pos);
|
|
}
|
|
}
|
|
|
|
black
|
|
}
|
|
|
|
#[derive(Default)]
|
|
pub struct Day24;
|
|
|
|
impl Solution for Day24 {
|
|
fn part1(&mut self, input: &mut dyn Read) -> String {
|
|
get_black_tiles(input).len().to_string()
|
|
}
|
|
|
|
fn part2(&mut self, input: &mut dyn Read) -> String {
|
|
let mut state = get_black_tiles(input);
|
|
let mut scratch_pad = state.clone();
|
|
|
|
for _ in 0..100 {
|
|
step(&state, &mut scratch_pad);
|
|
swap(&mut state, &mut scratch_pad);
|
|
}
|
|
|
|
state.len().to_string()
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use crate::test_implementation;
|
|
|
|
use super::*;
|
|
|
|
const SAMPLE: &[u8] = include_bytes!("../samples/24.txt");
|
|
|
|
#[test]
|
|
fn test_convert_pos() {
|
|
assert_eq!((1, -1), convert_pos("esew"));
|
|
assert_eq!((0, 0), convert_pos("nwwswee"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_step() {
|
|
let state = get_black_tiles(&mut SAMPLE.clone());
|
|
let mut target = state.clone();
|
|
|
|
step(&state, &mut target);
|
|
|
|
assert_eq!(15, target.len());
|
|
}
|
|
|
|
#[test]
|
|
fn sample_part1() {
|
|
test_implementation(Day24, 1, SAMPLE, 10);
|
|
}
|
|
|
|
#[test]
|
|
fn sample_part2() {
|
|
test_implementation(Day24, 2, SAMPLE, 2208);
|
|
}
|
|
}
|