Re-implement day 11.1 with graphs

This commit is contained in:
Tristan Daniël Maat 2020-12-12 21:42:16 +00:00
parent 6dd5d1a04c
commit d8a562145a
Signed by: tlater
GPG key ID: 49670FD774E43268
3 changed files with 129 additions and 104 deletions

39
day-11/Cargo.lock generated
View file

@ -1,10 +1,39 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
[[package]]
name = "autocfg"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]] [[package]]
name = "day-11" name = "day-11"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"indoc", "indoc",
"petgraph",
]
[[package]]
name = "fixedbitset"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d"
[[package]]
name = "hashbrown"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
[[package]]
name = "indexmap"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55e2e4c765aa53a0424761bf9f41aa7a6ac1efa87238f59560640e27fca028f2"
dependencies = [
"autocfg",
"hashbrown",
] ]
[[package]] [[package]]
@ -30,6 +59,16 @@ dependencies = [
"unindent", "unindent",
] ]
[[package]]
name = "petgraph"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7"
dependencies = [
"fixedbitset",
"indexmap",
]
[[package]] [[package]]
name = "proc-macro-hack" name = "proc-macro-hack"
version = "0.5.19" version = "0.5.19"

View file

@ -8,3 +8,4 @@ edition = "2018"
[dependencies] [dependencies]
indoc = "0.3" indoc = "0.3"
petgraph = "0.5"

View file

@ -1,5 +1,8 @@
use std::fs; use std::fs;
use petgraph::graph::{DiGraph, Graph};
use petgraph::visit::IntoNodeIdentifiers;
fn main() -> Result<(), Box<dyn std::error::Error>> { fn main() -> Result<(), Box<dyn std::error::Error>> {
let input = fs::read_to_string("input")?; let input = fs::read_to_string("input")?;
let layout = parse_layout(&input)?; let layout = parse_layout(&input)?;
@ -11,6 +14,20 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
Ok(()) Ok(())
} }
type Layout = DiGraph<Seating, Direction>;
#[derive(Copy, Clone, Debug)]
enum Direction {
NorthWest,
North,
NorthEast,
West,
East,
SouthWest,
South,
SouthEast,
}
#[derive(Copy, Clone, Debug, PartialEq)] #[derive(Copy, Clone, Debug, PartialEq)]
enum Seating { enum Seating {
Occupied, Occupied,
@ -29,124 +46,92 @@ impl Seating {
} }
} }
fn parse_layout(input: &str) -> Result<Vec<Vec<Seating>>, String> { fn parse_layout(input: &str) -> Result<Layout, String> {
input let mut output: Layout = Graph::new();
let grid: Vec<Vec<_>> = input
.lines() .lines()
.map(|line| line.chars().map(Seating::new).collect()) .map(|line| {
line.chars()
.map(|c| Ok(output.add_node(Seating::new(c)?)))
.collect() .collect()
}
fn print_layout(layout: &Vec<Vec<Seating>>) {
let output: String = layout
.iter()
.map(|row| {
let mut row: String = row
.iter()
.map(|c| match c {
Seating::Occupied => '#',
Seating::Empty => 'L',
Seating::Floor => '.',
}) })
.collect(); .collect::<Result<_, String>>()?;
row.push('\n');
row
})
.collect();
println!("{}", output); 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)) {
fn get_adjacent(layout: &Vec<Vec<Seating>>, i: usize, j: usize) -> Vec<Option<&Seating>> { for ((c, r), direction) in [
let adjacent: [[usize; 2]; 8] = [ ((0, 0), Direction::NorthWest),
[0, 0], ((0, 1), Direction::North),
[0, 1], ((0, 2), Direction::NorthEast),
[0, 2], ((1, 0), Direction::West),
[1, 0], ((1, 2), Direction::East),
[1, 2], ((2, 0), Direction::SouthWest),
[2, 0], ((2, 1), Direction::South),
[2, 1], ((2, 2), Direction::SouthEast),
[2, 2], ]
];
adjacent
.iter() .iter()
.map(|[nudge_row, nudge_col]| { {
if let Some(row) = (i + nudge_row).checked_sub(1) { if let (Some(c), Some(r)) = ((i + c).checked_sub(1), (j + r).checked_sub(1)) {
if let Some(row) = layout.get(row) { if let Some(target) = grid.get(c).and_then(|row| row.get(r)) {
if let Some(col) = (j + nudge_col).checked_sub(1) { output.add_edge(*node, *target, *direction);
row.get(col) }
} else { }
None
} }
} else {
None
} }
} else {
None
} }
})
.collect()
} }
fn simulate_people(layout: &Vec<Vec<Seating>>) -> (Vec<Vec<Seating>>, usize) { Ok(output)
}
fn count_eventually_occupied_seats(layout: &Layout) -> usize {
let mut layout = layout.clone();
loop {
let mut changes = 0; let mut changes = 0;
let layout = layout layout = layout.map(
.iter() |node, seat| match seat {
.enumerate()
.map(|(i, row)| {
row.iter()
.enumerate()
.map(|(j, seat)| match seat {
Seating::Occupied => { Seating::Occupied => {
if get_adjacent(layout, i, j) if layout
.iter() .neighbors(node)
.filter(|seat| **seat == Some(&Seating::Occupied)) .filter(|seat| layout[*seat] == Seating::Occupied)
.count() .count()
>= 4 >= 4
{ {
changes += 1; changes += 1;
Seating::Empty Seating::Empty
} else { } else {
Seating::Occupied *seat
} }
} }
Seating::Empty => { Seating::Empty => {
if get_adjacent(layout, i, j) if !layout
.iter() .neighbors(node)
.any(|seat| *seat == Some(&Seating::Occupied)) .any(|seat| layout[seat] == Seating::Occupied)
{ {
Seating::Empty
} else {
changes += 1; changes += 1;
Seating::Occupied Seating::Occupied
} else {
*seat
} }
} }
Seating::Floor => Seating::Floor, Seating::Floor => Seating::Floor,
}) },
.collect() |_, direction| *direction,
}) );
.collect();
(layout, changes)
}
fn count_eventually_occupied_seats(layout: &Vec<Vec<Seating>>) -> usize {
let mut loop_layout = layout.clone();
loop {
let (res, changes) = simulate_people(&loop_layout);
loop_layout = res;
if changes == 0 { if changes == 0 {
break; break;
} }
} }
loop_layout layout
.iter() .node_identifiers()
.flatten() .map(|id| layout[id])
.filter(|seat| **seat == Seating::Occupied) .filter(|seat| *seat == Seating::Occupied)
.count() .count()
} }