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.
This commit is contained in:
parent
3ec82e117e
commit
3c3ef92ff8
39
day-11/Cargo.lock
generated
39
day-11/Cargo.lock
generated
|
@ -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"
|
||||
|
|
|
@ -8,3 +8,4 @@ edition = "2018"
|
|||
|
||||
[dependencies]
|
||||
indoc = "0.3"
|
||||
petgraph = "0.5"
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
use std::fs;
|
||||
|
||||
use petgraph::graph::{DiGraph, Graph};
|
||||
use petgraph::visit::IntoNodeIdentifiers;
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let input = fs::read_to_string("input")?;
|
||||
let layout = parse_layout(&input)?;
|
||||
|
@ -11,6 +14,20 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
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)]
|
||||
enum Seating {
|
||||
Occupied,
|
||||
|
@ -29,124 +46,92 @@ impl Seating {
|
|||
}
|
||||
}
|
||||
|
||||
fn parse_layout(input: &str) -> Result<Vec<Vec<Seating>>, String> {
|
||||
input
|
||||
fn parse_layout(input: &str) -> Result<Layout, String> {
|
||||
let mut output: Layout = Graph::new();
|
||||
|
||||
let grid: Vec<Vec<_>> = input
|
||||
.lines()
|
||||
.map(|line| line.chars().map(Seating::new).collect())
|
||||
.map(|line| {
|
||||
line.chars()
|
||||
.map(|c| Ok(output.add_node(Seating::new(c)?)))
|
||||
.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();
|
||||
row.push('\n');
|
||||
row
|
||||
})
|
||||
.collect();
|
||||
.collect::<Result<_, String>>()?;
|
||||
|
||||
println!("{}", output);
|
||||
}
|
||||
|
||||
fn get_adjacent(layout: &Vec<Vec<Seating>>, i: usize, j: usize) -> Vec<Option<&Seating>> {
|
||||
let adjacent: [[usize; 2]; 8] = [
|
||||
[0, 0],
|
||||
[0, 1],
|
||||
[0, 2],
|
||||
[1, 0],
|
||||
[1, 2],
|
||||
[2, 0],
|
||||
[2, 1],
|
||||
[2, 2],
|
||||
];
|
||||
|
||||
adjacent
|
||||
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()
|
||||
.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
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
} 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 layout = layout
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, row)| {
|
||||
row.iter()
|
||||
.enumerate()
|
||||
.map(|(j, seat)| match seat {
|
||||
layout = layout.map(
|
||||
|node, seat| match seat {
|
||||
Seating::Occupied => {
|
||||
if get_adjacent(layout, i, j)
|
||||
.iter()
|
||||
.filter(|seat| **seat == Some(&Seating::Occupied))
|
||||
if layout
|
||||
.neighbors(node)
|
||||
.filter(|seat| layout[*seat] == Seating::Occupied)
|
||||
.count()
|
||||
>= 4
|
||||
{
|
||||
changes += 1;
|
||||
Seating::Empty
|
||||
} else {
|
||||
Seating::Occupied
|
||||
*seat
|
||||
}
|
||||
}
|
||||
Seating::Empty => {
|
||||
if get_adjacent(layout, i, j)
|
||||
.iter()
|
||||
.any(|seat| *seat == Some(&Seating::Occupied))
|
||||
if !layout
|
||||
.neighbors(node)
|
||||
.any(|seat| layout[seat] == Seating::Occupied)
|
||||
{
|
||||
Seating::Empty
|
||||
} else {
|
||||
changes += 1;
|
||||
Seating::Occupied
|
||||
} else {
|
||||
*seat
|
||||
}
|
||||
}
|
||||
Seating::Floor => Seating::Floor,
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
.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;
|
||||
},
|
||||
|_, 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()
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue