From 3c3ef92ff8ecc7823de679d72a91f7a8833b6aa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= Date: Sat, 12 Dec 2020 21:42:16 +0000 Subject: [PATCH] Re-implement day 11.1 with graphs This is to have a potentially nicer way to iterate neighbours, as well as recursive directions. While the former is neater than it was previously, the latter sadly wasn't possible after all, and it's very inefficient. --- day-11/Cargo.lock | 39 +++++++++ day-11/Cargo.toml | 1 + day-11/src/main.rs | 193 +++++++++++++++++++++------------------------ 3 files changed, 129 insertions(+), 104 deletions(-) diff --git a/day-11/Cargo.lock b/day-11/Cargo.lock index 5e329eb..097af7b 100644 --- a/day-11/Cargo.lock +++ b/day-11/Cargo.lock @@ -1,10 +1,39 @@ # This file is automatically @generated by Cargo. # 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]] name = "day-11" version = "0.1.0" dependencies = [ "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]] @@ -30,6 +59,16 @@ dependencies = [ "unindent", ] +[[package]] +name = "petgraph" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7" +dependencies = [ + "fixedbitset", + "indexmap", +] + [[package]] name = "proc-macro-hack" version = "0.5.19" diff --git a/day-11/Cargo.toml b/day-11/Cargo.toml index 5cf3b01..115407c 100644 --- a/day-11/Cargo.toml +++ b/day-11/Cargo.toml @@ -8,3 +8,4 @@ edition = "2018" [dependencies] indoc = "0.3" +petgraph = "0.5" diff --git a/day-11/src/main.rs b/day-11/src/main.rs index 886261d..813bb24 100644 --- a/day-11/src/main.rs +++ b/day-11/src/main.rs @@ -1,5 +1,8 @@ use std::fs; +use petgraph::graph::{DiGraph, Graph}; +use petgraph::visit::IntoNodeIdentifiers; + fn main() -> Result<(), Box> { let input = fs::read_to_string("input")?; let layout = parse_layout(&input)?; @@ -11,6 +14,20 @@ fn main() -> Result<(), Box> { Ok(()) } +type Layout = DiGraph; + +#[derive(Copy, Clone, Debug)] +enum Direction { + NorthWest, + North, + NorthEast, + West, + East, + SouthWest, + South, + SouthEast, +} + #[derive(Copy, Clone, Debug, PartialEq)] enum Seating { Occupied, @@ -29,124 +46,92 @@ impl Seating { } } -fn parse_layout(input: &str) -> Result>, String> { - input +fn parse_layout(input: &str) -> Result { + let mut output: Layout = Graph::new(); + + let grid: Vec> = input .lines() - .map(|line| line.chars().map(Seating::new).collect()) - .collect() -} - -fn print_layout(layout: &Vec>) { - 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(); - row.push('\n'); - row - }) - .collect(); - - println!("{}", output); -} - -fn get_adjacent(layout: &Vec>, i: usize, j: usize) -> Vec> { - let adjacent: [[usize; 2]; 8] = [ - [0, 0], - [0, 1], - [0, 2], - [1, 0], - [1, 2], - [2, 0], - [2, 1], - [2, 2], - ]; - - adjacent - .iter() - .map(|[nudge_row, nudge_col]| { - if let Some(row) = (i + nudge_row).checked_sub(1) { - if let Some(row) = layout.get(row) { - if let Some(col) = (j + nudge_col).checked_sub(1) { - row.get(col) - } else { - None - } - } else { - None - } - } else { - None - } - }) - .collect() -} - -fn simulate_people(layout: &Vec>) -> (Vec>, usize) { - let mut changes = 0; - - let layout = layout - .iter() - .enumerate() - .map(|(i, row)| { - row.iter() - .enumerate() - .map(|(j, seat)| match seat { - Seating::Occupied => { - if get_adjacent(layout, i, j) - .iter() - .filter(|seat| **seat == Some(&Seating::Occupied)) - .count() - >= 4 - { - changes += 1; - Seating::Empty - } else { - Seating::Occupied - } - } - Seating::Empty => { - if get_adjacent(layout, i, j) - .iter() - .any(|seat| *seat == Some(&Seating::Occupied)) - { - Seating::Empty - } else { - changes += 1; - Seating::Occupied - } - } - Seating::Floor => Seating::Floor, - }) + .map(|line| { + line.chars() + .map(|c| Ok(output.add_node(Seating::new(c)?))) .collect() }) - .collect(); + .collect::>()?; - (layout, changes) + 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) } -fn count_eventually_occupied_seats(layout: &Vec>) -> usize { - let mut loop_layout = layout.clone(); +fn count_eventually_occupied_seats(layout: &Layout) -> usize { + let mut layout = layout.clone(); loop { - let (res, changes) = simulate_people(&loop_layout); - loop_layout = res; + 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; } } - loop_layout - .iter() - .flatten() - .filter(|seat| **seat == Seating::Occupied) + layout + .node_identifiers() + .map(|id| layout[id]) + .filter(|seat| *seat == Seating::Occupied) .count() }