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
6dd5d1a04c
commit
279e9d8cc7
39
day-11/Cargo.lock
generated
39
day-11/Cargo.lock
generated
|
@ -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"
|
||||||
|
|
|
@ -8,3 +8,4 @@ edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
indoc = "0.3"
|
indoc = "0.3"
|
||||||
|
petgraph = "0.5"
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue