Skip to content

Instantly share code, notes, and snippets.

@samueltardieu
Created December 24, 2019 19:25
Show Gist options
  • Save samueltardieu/f9066a9b81bbe95c6752eed436007bec to your computer and use it in GitHub Desktop.
Save samueltardieu/f9066a9b81bbe95c6752eed436007bec to your computer and use it in GitHub Desktop.
use pathfinding::prelude::{Matrix, MatrixFormatError};
use std::collections::BTreeSet;
#[aoc_generator(day24)]
fn input_generator(input: &str) -> Result<Matrix<bool>, MatrixFormatError> {
let lines = input.lines().collect::<Vec<_>>();
Matrix::from_rows(lines.iter().map(|l| l.bytes().map(|c| c == b'#')))
}
#[aoc(day24, part1)]
fn part1(board: &Matrix<bool>) -> usize {
let mut cache = BTreeSet::new();
let mut board = board.clone();
loop {
let e = evaluate(&board);
if cache.contains(&e) {
return e;
}
cache.insert(e);
board = mutate(board);
}
}
#[aoc(day24, part2)]
fn part2(board: &Matrix<bool>) -> u32 {
let empty = Matrix::new(5, 5, false);
let mut b = board.clone();
b[&(2, 2)] = false;
let mut boards = vec![
empty.clone(),
empty.clone(),
b,
empty.clone(),
empty.clone(),
];
for _ in 0..200 {
let mut new_boards = vec![empty.clone()];
new_boards.push(Matrix::new(5, 5, false));
new_boards.push(Matrix::new(5, 5, false));
for i in 1..boards.len() - 1 {
new_boards.push(mutate_deep(&boards[i - 1], &boards[i], &boards[i + 1]));
}
new_boards.push(Matrix::new(5, 5, false));
new_boards.push(empty.clone());
boards = new_boards;
}
boards
.into_iter()
.flat_map(|b| b.indices().map(move |p| b[&p] as u32))
.sum()
}
fn mutate_deep(outer: &Matrix<bool>, middle: &Matrix<bool>, inner: &Matrix<bool>) -> Matrix<bool> {
let mut result = Matrix::new(5, 5, false);
for x in 0..5 {
for y in 0..5 {
if x == 2 && y == 2 {
continue;
}
let mut neighbours = result
.neighbours(&(x, y), false)
.map(|p| middle[&p] as u32)
.sum::<u32>();
if x == 0 {
neighbours += outer[&(1, 2)] as u32;
}
if x == 4 {
neighbours += outer[&(3, 2)] as u32;
}
if x == 1 && y == 2 {
for yy in 0..5 {
neighbours += inner[&(0, yy)] as u32;
}
}
if x == 3 && y == 2 {
for yy in 0..5 {
neighbours += inner[&(4, yy)] as u32;
}
}
if x == 2 && y == 1 {
for xx in 0..5 {
neighbours += inner[&(xx, 0)] as u32;
}
}
if x == 2 && y == 3 {
for xx in 0..5 {
neighbours += inner[&(xx, 4)] as u32;
}
}
if y == 0 {
neighbours += outer[&(2, 1)] as u32;
}
if y == 4 {
neighbours += outer[&(2, 3)] as u32;
}
if middle[&(x, y)] {
if neighbours == 1 {
result[&(x, y)] = true;
}
} else {
if neighbours == 1 || neighbours == 2 {
result[&(x, y)] = true;
}
}
}
}
result
}
fn evaluate(board: &Matrix<bool>) -> usize {
board
.indices()
.enumerate()
.map(|(i, p)| if board[&p] { 1 << i } else { 0 })
.sum()
}
fn mutate(board: Matrix<bool>) -> Matrix<bool> {
let mut out = Matrix::new(5, 5, false);
for x in 0..5 {
for y in 0..5 {
let n = board
.neighbours(&(x, y), false)
.filter(|n| board[n])
.count();
if board[&(x, y)] {
if n == 1 {
out[&(x, y)] = true;
}
} else {
if n == 1 || n == 2 {
out[&(x, y)] = true;
}
}
}
}
out
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment