WIP: Re-implement using ndarray

This commit is contained in:
Tristan Daniël Maat 2020-12-14 15:31:05 +00:00
parent 5a7cd20ca6
commit f38ec71c3f
Signed by: tlater
GPG key ID: 49670FD774E43268
3 changed files with 105 additions and 125 deletions
day-11/src

View file

@ -1,32 +1,24 @@
use std::fs;
use std::iter;
use petgraph::graph::{DiGraph, Graph};
use petgraph::visit::IntoNodeIdentifiers;
use ndarray::Array2;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let input = fs::read_to_string("input")?;
let layout = parse_layout(&input)?;
// Part 1
let result = count_eventually_occupied_seats(&layout);
let result = count_with_neighboring_seats(&layout);
println!("{}", result);
// Part 2
let result = count_with_directional_seats(&layout);
println!("{}", result);
Ok(())
}
type Layout = DiGraph<Seating, Direction>;
#[derive(Copy, Clone, Debug)]
enum Direction {
NorthWest,
North,
NorthEast,
West,
East,
SouthWest,
South,
SouthEast,
}
type Layout = Array2<Seating>;
#[derive(Copy, Clone, Debug, PartialEq)]
enum Seating {
@ -47,92 +39,33 @@ impl Seating {
}
fn parse_layout(input: &str) -> Result<Layout, String> {
let mut output: Layout = Graph::new();
let (i, j) = (
input.lines().count(),
input.lines().next().ok_or("Waiting room too small")?.len(),
);
let grid: Vec<Vec<_>> = input
// Padding the input data so that we can later comfortably produce
// a convolution
let grid = input
.lines()
.map(|line| {
line.chars()
.map(|c| Ok(output.add_node(Seating::new(c)?)))
.collect()
.flat_map(|line| {
iter::once(Ok(Seating::Floor))
.chain(line.chars().map(Seating::new))
.chain(iter::once(Ok(Seating::Floor)))
})
.collect::<Result<_, String>>()?;
.collect::<Result<Vec<Seating>, String>>()?;
for i in 0..grid.len() {
for j in 0..grid[0].len() {
if let Some(node) = grid.get(i).and_then(|row| row.get(j)) {
for ((c, r), direction) in [
((0, 0), Direction::NorthWest),
((0, 1), Direction::North),
((0, 2), Direction::NorthEast),
((1, 0), Direction::West),
((1, 2), Direction::East),
((2, 0), Direction::SouthWest),
((2, 1), Direction::South),
((2, 2), Direction::SouthEast),
]
.iter()
{
if let (Some(c), Some(r)) = ((i + c).checked_sub(1), (j + r).checked_sub(1)) {
if let Some(target) = grid.get(c).and_then(|row| row.get(r)) {
output.add_edge(*node, *target, *direction);
}
}
}
}
}
}
Ok(output)
Array2::from_shape_vec((i, j), grid)
.map_err(|_| "Non-square waiting rooms don't exist".to_string())
}
fn count_eventually_occupied_seats(layout: &Layout) -> usize {
let mut layout = layout.clone();
fn count_with_neighboring_seats(layout: &Layout) -> usize {
unimplemented!()
}
loop {
let mut changes = 0;
layout = layout.map(
|node, seat| match seat {
Seating::Occupied => {
if layout
.neighbors(node)
.filter(|seat| layout[*seat] == Seating::Occupied)
.count()
>= 4
{
changes += 1;
Seating::Empty
} else {
*seat
}
}
Seating::Empty => {
if !layout
.neighbors(node)
.any(|seat| layout[seat] == Seating::Occupied)
{
changes += 1;
Seating::Occupied
} else {
*seat
}
}
Seating::Floor => Seating::Floor,
},
|_, direction| *direction,
);
if changes == 0 {
break;
}
}
layout
.node_identifiers()
.map(|id| layout[id])
.filter(|seat| *seat == Seating::Occupied)
.count()
fn count_with_directional_seats(layout: &Layout) -> usize {
unimplemented!()
}
#[cfg(test)]
@ -157,7 +90,30 @@ mod tests {
);
let layout = parse_layout(&input)?;
let result = count_eventually_occupied_seats(&layout);
let result = count_with_neighboring_seats(&layout);
assert_eq!(result, 37);
Ok(())
}
#[test]
fn test_simple2() -> Result<(), Box<dyn std::error::Error>> {
let input = indoc!(
"L.LL.LL.LL
LLLLLLL.LL
L.L.L..L..
LLLL.LL.LL
L.LL.LL.LL
L.LLLLL.LL
..L.L.....
LLLLLLLLLL
L.LLLLLL.L
L.LLLLL.LL
"
);
let layout = parse_layout(&input)?;
let result = count_with_directional_seats(&layout);
assert_eq!(result, 37);
Ok(())