Implementation day 24.

This commit is contained in:
2020-12-24 18:58:28 +01:00
parent d5f35db4ed
commit 11ceb0b316
3 changed files with 462 additions and 2 deletions

View File

@@ -1,12 +1,139 @@
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 {
todo!()
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);
}
}