From 6dd5d1a04cd0eadb38f24c391f2d84d2a93343f7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Fri, 11 Dec 2020 23:29:34 +0000
Subject: [PATCH 1/7] Complete day 11.1

---
 day-11/Cargo.lock  |  78 ++++++++++++++++++++
 day-11/Cargo.toml  |  10 +++
 day-11/input       |  93 +++++++++++++++++++++++
 day-11/src/main.rs | 180 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 361 insertions(+)
 create mode 100644 day-11/Cargo.lock
 create mode 100644 day-11/Cargo.toml
 create mode 100644 day-11/input
 create mode 100644 day-11/src/main.rs

diff --git a/day-11/Cargo.lock b/day-11/Cargo.lock
new file mode 100644
index 0000000..5e329eb
--- /dev/null
+++ b/day-11/Cargo.lock
@@ -0,0 +1,78 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "day-11"
+version = "0.1.0"
+dependencies = [
+ "indoc",
+]
+
+[[package]]
+name = "indoc"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "47741a8bc60fb26eb8d6e0238bbb26d8575ff623fdc97b1a2c00c050b9684ed8"
+dependencies = [
+ "indoc-impl",
+ "proc-macro-hack",
+]
+
+[[package]]
+name = "indoc-impl"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce046d161f000fffde5f432a0d034d0341dc152643b2598ed5bfce44c4f3a8f0"
+dependencies = [
+ "proc-macro-hack",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "unindent",
+]
+
+[[package]]
+name = "proc-macro-hack"
+version = "0.5.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
+dependencies = [
+ "unicode-xid",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "syn"
+version = "1.0.54"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a2af957a63d6bd42255c359c93d9bfdb97076bd3b820897ce55ffbfbf107f44"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-xid",
+]
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
+
+[[package]]
+name = "unindent"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f14ee04d9415b52b3aeab06258a3f07093182b88ba0f9b8d203f211a7a7d41c7"
diff --git a/day-11/Cargo.toml b/day-11/Cargo.toml
new file mode 100644
index 0000000..5cf3b01
--- /dev/null
+++ b/day-11/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "day-11"
+version = "0.1.0"
+authors = ["Tristan Daniël Maat <tm@tlater.net>"]
+edition = "2018"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+indoc = "0.3"
diff --git a/day-11/input b/day-11/input
new file mode 100644
index 0000000..7cf41d9
--- /dev/null
+++ b/day-11/input
@@ -0,0 +1,93 @@
+LLLLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLL.LLLLLLLL.LLLLLL.LLLLLLLLLLLLL.LLLLLLLL
+LLLLLLLLLL.LLLL.LLLL.LLLLLLLLLLLLLL.LLLLLLL.LLLLLLL.LLLLLL.LLLLLLLL.LLLLLL.LLLLLLLL.LLLLLLLLLLLLL
+LLLLLLLLLLLLLLLLLLLL.LLLLLLLL.LLLLLLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLL.LLLLLL.LLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLLLLLLL.LLLL.LLLLLLLL.LLLLL.LLLLLLLLLLLLLLL.LLLLLLLLLLLLLLL.LLLLLL.LLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLL.LLLLLL.LL.LLLLLLLL.LLLLL.LLLLLLLLLLLLLLL.LLLLLL.LLLLLLLL.LLLLLLLLLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLLLLLLLLLLLL.LLLLLLLL.LLLLLLLLLLLLL.LLLLL.L.LLLLLLLLLLLLLLL.LLLLLL.LLLLLLLLLLLLL.LLLLLLLL
+LLLLLLLLLL.LLLL.LLLL.LLLLLLLL.LLLLL.LLLLLLL.LLLLLLL.LLLLLLLLLLLLLLL.LLLLLL.LLLLLLLL.LLLL.LLLLLLLL
+..L...L.L..L.LL.....L.L..L...L.L.....L.L...LLL..L....L.L.LL.LL...L.....LLL.....L...L..L..L.......
+LLLLLLLLLLLLLLL.LLLLLLLLLLLLL.LLLLL.LLLLLLL.LLLLLLL.LLLLLLLLLLLLLLL.LLLLLL.LLLLLLLL.LLLLLLLLLLLLL
+LLLLLLLLLL.LLLL.LLLLLLLLLLLLL.LLLLL.LLLLLLLLLLLLLLL.LLLLLLLLLLLLLLL.LLLLLL.LLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLL.LLLL.LLLLLLLLLLLLL.LLLLL.LLLLLLL.LLLLLLL.LLLLLLLLLLLLLLL.LLLLLL.LLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLL.LLLL.LLLL.LLLLLLLLLLLLLLLLLLLLLL.LLLLLLL.LLLLLL.LLLLLLLL.LLLLLL.LLLLLLLLLLLLL.LLLLLLLL
+LLLLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLL.LLLLLLL.LLLLLLLLLLLLLLLLLLLLLL.LLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLL.LLLLLLLLLLLLLLLLLL.LLLLL.LLLLLLL.LLLLLLL.LLLLLL.LLLLLLLL.LLLLLLLLLL.LLLL.LLLLLLLLLLLLL
+.....LLL....L..L.L..L.L..L...L.L.LL.....L...L..LL.LL..L.L.LL...LL....LL.....L.....L.L.LL.L..L.L..
+LLLLLLLLLL.LLLLLLLLL.LLLLLLLL.LLLLLLLLLLLLL.LLLLLLL.LLLLLL.LLLLLLLLLLLLLLL.LLLLLLLL.LLLLLLLLLLLLL
+LLLLLLLLLL.LLLL.L.LLLLLLLLLLL.LLLLL.LLLLLLL.LLLLLLLLLLLLLLLLLLLLLLL.LLLLL..LLLLLLLLLLLLLLLLLLLLLL
+LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LL.LLLL.LLLLLLL.LLLLLL.LLLLLLLL.LLLLLL.LLLLLLLL.LLLLLLLLLLLLL
+LLLLLLLLLLLLLLL.LLL.LLLLLLLLL.LLLLLLLLLLLLL.LLLLLLL.LLLLLLLLLLLLLLL.LLLLLLLLLLLLLLL.LLLLLLLLLLLLL
+..L.L.LL.L..LL..L..LL.L..L................L....L............L.L..L...L...L..LLLL....L.L..LL....L.
+LLLLLL.LLL.LLLL.LLLLLLLLLLLLL.LLLLLLLLLLLLL.LLLLLLLLLLLLLL.LLLLLLLLLLLLLLL.LLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLL.LLLL.LLLL.L.LLLLLL.LLLLL.LLLLLLL.LLLLLLL.LLLLLL.LLLLLLLL.LLLLLL.LLLLLLLL.LLLLLLLLLLLLL
+LLLLLLLLLL.LLLL.LLLL.LLLLLLLL.LLLLLLLLLLLLL.LLLLLLLLLLLLLL.LLLLLLLL.LLLLLLLLLLLLLLL.LLLL.LLL.LLLL
+LLLLLLLLLL.LLLL.LLLL.LLLLLLLL.LLL.L.LLL.LLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLL.LLLLLLLL.LLLL.LLLLLLLL
+LL.L.L.L.....L..L...L.L...L.......L...LLL...L.LL.L.....L.LLL.LL....LLLLL.L....LLL.L..LL..L....L.L
+LLLLLLLLLL.LLLLLLLLL.LLLLLLLL.LLLLL.LLLLLLL.LLLLLLL.LLLLLL.LLLLLLLLLLLLLLLLLLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLLLLLLLLLLLL.LLLLLLLL.LLLLL.LLLLLLLLLLLLLLL.LLLLLL.LLLLLLLL.LLLLLLLLLLLLLLL.LLLLLLLLLLLLL
+LLLLLLLLLL.LLLL.LLLL.LLLLLLLL.LLLLLLLLLLL.LLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLL.LLLLLLLLLLLLLLL.LLLLLL
+LLLLLLLLLLLLLLL.LLLL.LLLLLLLL.LLLLLLLLLLLLL.LLLLLLL.LLLLLL.LLLLLLLLLLLLLLL.L.LLLLLLLLLLLLLLLLLLLL
+LLLLLLLLLL.LLLLLLLLL.LLLLLLLL.LLLLLLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLL.LLLLLL.LLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLL.LLLL.LLLL.LLLLLLLLLLLLLLLLLLLLLL.LLLLLLL.LLLLLL.LLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLLLLLLLL
+LLLLLLLLLL.LLLL.LLLL.LLLLLLLL.LLLLL.LLLLLLL.LLLLLLLLLLLLLL.LLLLLLLL.LLLLLL.LLLLLLLL.LLLLLLLLL.LLL
+.L.LL..LL...L....LL...L.LL.L....LL.LL......L..L........LL..LLL..L...LLL.....LL....L.L...L.....L..
+LLLLLLLLLL.LLLL.LLLLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLL.LLLLLL.LLLLLLLLLLLLLLL.LLL.LLLL.LLLL.LLLLLLLL
+LLLLLLLLLL.LLLLLLLLL.LLLLLLLL.LLLLL.LLLLLLL.LLLLLLL.LLLLLLLLLLLLLLL.LLLLLL.LLLLLL.L.LLLLLLLLLLLLL
+.LLLLLLLLLLLLLL.LLLL.LLLLLLLL.LLLLLLLLLLLLLLLLLLL.L.LLLLLL.LLLLLLLL.LLLLLL.LLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLLLLLLL.LLLL.LLLLLLLL.LLLLL.LLLLLLL.LLLLLLL.LLLLLL.LLLLLLLL.LLLLLLLLLLLLLLL.LLLLLLLLLLLLL
+LLLLLLLLLL.LLLL.LLLLL.LLLLLLL.LLLLLLLLLLLLL.LLLLLLL.LLLLLL.LLLLLLLL.LLLLLL.LLLLLLLLLLLLLLLLLLLLLL
+LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLL.LLLLLL.LLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLL.LLLLLLLLL.LLLLLLLL.LLLLLLLLLLLLL.LLLLLLL.LLLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLLL
+LLLLLLLLLL.LLLL.LLLL.LLLLLLLLLLLLLLLLLLLLLL.LLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLL.LLLLLLLLL.LLLLLLLL.LLLLL.LLLLLLL.LLL.LLL.LLLLLL.LLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLLLL
+..L....LL..LL.LLLL......L..L...LLL.L......L.L.....L....L....LLLL.....L..LL...L....L....LLL....LL.
+LLLLLLLLLLLLLLL.LLLL.LLLLL.LLLLLLLL..LLLLLL.LLLLLLL.LLLLLLLLLLLLLLL.LLLLLL.LLLLLLLL.LLLLLLLLLLLLL
+LLLLLLLLLL.LLLL.LLLLLLLLLLLLL.LLLLL.LLLLLLL.LLLLLLLLLLLLLL.LLLLLLLLLLLLLLL.LLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLLLLLLL.LLLL.LLLLLLLL.LLLL..LLLLLLLLLLLLLLL.LLLLLL.LLLLLLLL.LLLLLLLLLLLLLLL.LLLLLLLLLLLLL
+LLLLLLLLLL.LLLL.LLLL.LLLLLLLL.LLLLL.LLLLLLL.LLL.LLLLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLL.LLLLLLLLLLLLL
+LLLLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLL.LLLLLL..LLLLLL.LLLLLLLLLLLLLLL.LLLLLLLLLLLLL.LLLLL.LL
+LLLLLLLLLLLLLLL.LLL..LLLLLLLL.LL.LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLL.LLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLL.LLLLLLLLL.LLLLLLLL.LLLLL.LLLLLLLLLLLLL.LLLLLLLL.LLLLLLLLLLLLLLL.LLLLLLLLLLLLL.LLLLLLLL
+...LL.LL.....LL..LLL.....LL....LL....L.LL.L.LL....L........LLLL..LLLLLL.L..L..LLL......L....L....
+LLL.LLLLLLLLLLLLLLLL.LLLLLLLL.LLLLL.LLLLLLL.LLLLLLL.LLLLLL.LLLLLLLL.LLLLLL.LLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLL.LLLLLLL.LLLLLLL.LLLLLL.LLLLLLLL.LL.LLL.LLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLLLLLLL.LLLLLLLLLLLLL.LLLLL.LLLLLLL.LLLLLLL.LLLLLLLLLLLLLLL.LLLLLL.LLLLLLLLLLLLLLLLLLLLLL
+LLLLLLLLLL.LLLL.LLLLLLLLLLLLLLLLLLL.LLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLLL.LLLLLLLLLLLLL
+LLLLLLLLLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLL.LLLLLLLL.LLLLLL.LLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLL.LLLL.LLLL.LLLLLLLL.LLLLL.LLLLLLLLLLLLLLL.LLLLLLLLLLLLLLL.LLLLLL.LLLLLLLL.LLLLLLLLLLLLL
+.....L.L..LL..LL..L.L.L.....LLLLL.....L..L...L.....L.L..L..L....LL....L...........L.L.......L.LLL
+LLLLLLLLLL.LLLL.LLLLLLLLLLLLLLLLLLL.LLLLLLL.LLLLLLL.LLLLLL.LLLLLLLLLLLLLLL.LLLLLLLLLLLLL.LLLLLLLL
+LLL.LLLLLL.LLLL.LLLL.LLLLLLLL.LLLLL.LLLLLLL.LLLLLLL.LLLLLL.LLLLLLLL.LLLLLL..LLLLLLL.LLLLLLLLLLLLL
+LLLLLLLLLL.LLLL.LLLLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLLLL.LLLLLLLLLLL.LLLLLLLL
+LLLLLLLLLL.LLLL.LLLL.LLLLLLLLLLLLLL.LLLLLLL.L.LLLLLLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLL.LLLLLLLLLLLLL
+LLLL.L.LLL.LLLL.LLLL.LLLLLLLLLLLLLL.LLLLLLL.LLLLLLL.LLLLLL.LLLLLLLLLLLLLLL.LLLLLLLL.LL.L.LLLLLLLL
+L.LLL.................LLL....L...LL..........L.L.L.......L.....L.....LLLLLL......L.......L...L.LL
+LLLLLLLLLLLLLLL.LLLLLLLLLLLLL.LLLLL.LLLLLLL.LLLLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLL.LLLLLLLLL.LLLLLLLL.LLLLL.LL.LLLL.LLLLLLL.LLLLLL.LLLLLLLL.LLLLLLLLLLLLLLL.LLLLLLLLLLLLL
+LLLLLLLLLL.LLLL.LLLL.LLLLLLLL.LLLLL.LLLLLLL.LLLLLLLLLLLLLLLLLLLLLLL.LLLLLL.LLLLLLLL.LLLL.LLLLL.LL
+LLLLLLLLLL.LLLL.LLLLLLLLLLLLLLLLLLL.LLL.LLL.LLLLLLL.LLLLLL.LLLLLLLL.LLLLLLLLLLLLLLLLLLLL.LLLLLLLL
+LLLLLLLLLLLLLLL.LLLLLLLLLLLLLLLLLLL.LLLLLLL.LLLLLLLLLLLLLL.LLLLLLLL.LLLLLL.LLLLLLLL.LLLLLLLLLLLLL
+LLLLLLLLLLLLLLL.LLLL.LLLLLLLL.LLLLLLLLLLLLLLLLLLLLL.LLLLLL.LLLLLLLLLLL.LLL.LLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLLLLLLL.LLL..LLLLLLLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLL.LLLLLLLLLLLLLLL.LLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLL.LLLL.LLLL.LLLLLLLL.LLLLLLLLLLLLL.LLLLLLL.LLLLLL.LLLLLLLL.LLLLLLLLLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLL.LLLL.LLLL.LLLLLLLLLLLLLLLLLLLLLL.LLLLLLL.LLLLLL.LLLLLLLL.LLLLLLLLLLLLLLL.LLLL.LLLLLLLL
+..L...LL.LLL.LLL.......LL..LL.L...LLL.....L....LLLL.L..........L.....L.L....L..............LL.L..
+LLLLLLLLLL.LLLL.LLL..LLLLLLLLLLLLLL.LLLLLLLLLLLLLLL.LLLLLLLLLLLLLLL.LLLLLLLLLLLLLLL.LLLLLLLLLLLLL
+LLLLLLLLLLLLLLLLLLLLLL.LLLLLL.LLLLL.LLLLLLLLLLLLLLLLLLLLLL.LLLLLLLL.LLLLLL.LLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLL.LLLLLLLLL.LLL.LLLLLLLLLLLLLLLLLL.LLLLLLL.LLLLLL.LLLLLLLL.LLLLLLLLLLLLLLLLLLLL.LLLLLLLL
+LLLLLLLLLL.LLLL.LLL.LLLLLLLLL.LLLLL.LLLLLLL.LLLLLLL.LLLLLL.LLLLLLLL.LLLLLLLLLLLLLLLLL.LL.LLLLLLLL
+LLLLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLL.LLLLLL.LLLLLLLLLLLL.LLLLL.LLLLL.LLLL.LLLLLLLL
+LLLLLLLLLL.LLLL.LLLLLLLLLLLLL.LL.LL.LLLLLLLLLLLLLLLLLLLLLL.LLLLLLLL.LLLLLL.LLLLLLLL.LLLL.LLLLLLLL
+LL.L.L..LL..L.......L.L..LL....L.L.L...L.L..LL....LL.LL....L....LL..L....L............L.......L..
+LLLLLLLLLL.LLLL.LLLL.LLLLLLLLLLLLLLLLLLLLLL.LLLLLLL.LLLLLL.LLLLLLLLLLLLLLL.LLLLLLLLLLLLL.LLLLLLLL
+LLLLLLLLLL.LLLL.LLLL.LLLLLLLLLLLLLL.LLLLLLL.LLLLLLL.LLLLLL.LLLLLLLL.LLLLLL.LLLLLLLLLLLLLLLLLLLLLL
+LLLLLLLLLL.LLLLLLLLL.LLLLLLLL.LLLLLLLLLLLLL.LLLLLLL.LLLLLL.LLLLLLLLLLLLLLLLLLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLL.LLLLLLLLLLLLLLLLLL.LLLLL.LLLLLLLLLLLLLLL.LLLLLLLLLLLLLLL.LLLLLL.LLLLLL.L.LLLL.LLLLLLLL
+LLLLLLLLLL.LLLL.LLLL.LLLLLLLL.LLLLL.LLLLLLL.LLLLLLL.LLLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
+..L.L.....L......L..L.....L.......L..L....LL...L.L.L...LLL.L.L..L..L..L......LLL.....L..L..L.....
+LLLLLLLLLLLLLLL.LLLLLL.LLLLLL.LLLLL.LLLLLLL.LLLLLLL.LLLLLL.LLLLLLLL.LLLLLL.LLLLLLLLLLLLL.LLLLLLLL
+LLLLLLLLLL.LLLLLLLLL.LLLLLLLLLLLLLL.LLLLLLLLLLLLLLLLLLLLLL.LLLLLLLL.LLLLLL.LLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLL.LLLL.LLLLLLLLLLLLL.LLLLLLLLLLLLL.LLLLLLLLLL.LLLLLLLLLLLL.LLLLLL.L.LLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLL.LLLL.LLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLL.LLLLLLLLLLLLLLL..LLLLLLLLLLLL.LLLLLLLL
+LLLLLLLLLL.LLLL.LLLLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLL.LLLLLL.LLLLLLLL.LLLLLL.LLLLLLLLLLLLL.LLLLLLLL
+LLLLLLLLLL.LLLLLLLLL.LL.LLLLL.LLLLLLLLLLLLL.LLLLLLL.LLLLLL.LLLLLLLL.LLLLLLLLLLLLLLL.LLLLLLLLLLLLL
diff --git a/day-11/src/main.rs b/day-11/src/main.rs
new file mode 100644
index 0000000..886261d
--- /dev/null
+++ b/day-11/src/main.rs
@@ -0,0 +1,180 @@
+use std::fs;
+
+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);
+    println!("{}", result);
+
+    Ok(())
+}
+
+#[derive(Copy, Clone, Debug, PartialEq)]
+enum Seating {
+    Occupied,
+    Empty,
+    Floor,
+}
+
+impl Seating {
+    fn new(symbol: char) -> Result<Self, String> {
+        match symbol {
+            '#' => Ok(Seating::Occupied),
+            'L' => Ok(Seating::Empty),
+            '.' => Ok(Seating::Floor),
+            rubbish => Err(format!("Found some rubbish on the floor, area must be clean to conserve human behavior: {}", rubbish))
+        }
+    }
+}
+
+fn parse_layout(input: &str) -> Result<Vec<Vec<Seating>>, String> {
+    input
+        .lines()
+        .map(|line| line.chars().map(Seating::new).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();
+            row.push('\n');
+            row
+        })
+        .collect();
+
+    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
+        .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<Seating>>) -> (Vec<Vec<Seating>>, 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,
+                })
+                .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;
+
+        if changes == 0 {
+            break;
+        }
+    }
+
+    loop_layout
+        .iter()
+        .flatten()
+        .filter(|seat| **seat == Seating::Occupied)
+        .count()
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use indoc::indoc;
+
+    #[test]
+    fn test_simple() -> 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_eventually_occupied_seats(&layout);
+
+        assert_eq!(result, 37);
+        Ok(())
+    }
+}

From 279e9d8cc7bd95c87e7dc834d070fe4599099fa7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Sat, 12 Dec 2020 21:42:16 +0000
Subject: [PATCH 2/7] 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<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())
-        .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();
-
-    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
-        .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<Seating>>) -> (Vec<Vec<Seating>>, 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::<Result<_, String>>()?;
 
-    (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<Vec<Seating>>) -> 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()
 }
 

From a3b9b63181f3f5344c930ec1bee8bde5fb904422 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Sun, 13 Dec 2020 22:26:46 +0000
Subject: [PATCH 3/7] Complete day 13

---
 day-13/Cargo.lock  |  78 ++++++++++++++++++++
 day-13/Cargo.toml  |  10 +++
 day-13/input       |   2 +
 day-13/src/main.rs | 172 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 262 insertions(+)
 create mode 100644 day-13/Cargo.lock
 create mode 100644 day-13/Cargo.toml
 create mode 100644 day-13/input
 create mode 100644 day-13/src/main.rs

diff --git a/day-13/Cargo.lock b/day-13/Cargo.lock
new file mode 100644
index 0000000..d0515ae
--- /dev/null
+++ b/day-13/Cargo.lock
@@ -0,0 +1,78 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "day-13"
+version = "0.1.0"
+dependencies = [
+ "indoc",
+]
+
+[[package]]
+name = "indoc"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "47741a8bc60fb26eb8d6e0238bbb26d8575ff623fdc97b1a2c00c050b9684ed8"
+dependencies = [
+ "indoc-impl",
+ "proc-macro-hack",
+]
+
+[[package]]
+name = "indoc-impl"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce046d161f000fffde5f432a0d034d0341dc152643b2598ed5bfce44c4f3a8f0"
+dependencies = [
+ "proc-macro-hack",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "unindent",
+]
+
+[[package]]
+name = "proc-macro-hack"
+version = "0.5.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
+dependencies = [
+ "unicode-xid",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "syn"
+version = "1.0.54"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a2af957a63d6bd42255c359c93d9bfdb97076bd3b820897ce55ffbfbf107f44"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-xid",
+]
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
+
+[[package]]
+name = "unindent"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f14ee04d9415b52b3aeab06258a3f07093182b88ba0f9b8d203f211a7a7d41c7"
diff --git a/day-13/Cargo.toml b/day-13/Cargo.toml
new file mode 100644
index 0000000..a4e1f5b
--- /dev/null
+++ b/day-13/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "day-13"
+version = "0.1.0"
+authors = ["Tristan Daniël Maat <tm@tlater.net>"]
+edition = "2018"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+indoc = "0.3"
diff --git a/day-13/input b/day-13/input
new file mode 100644
index 0000000..e614056
--- /dev/null
+++ b/day-13/input
@@ -0,0 +1,2 @@
+1000391
+19,x,x,x,x,x,x,x,x,x,x,x,x,37,x,x,x,x,x,383,x,x,x,x,x,x,x,23,x,x,x,x,13,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,29,x,457,x,x,x,x,x,x,x,x,x,41,x,x,x,x,x,x,17
diff --git a/day-13/src/main.rs b/day-13/src/main.rs
new file mode 100644
index 0000000..be4bd15
--- /dev/null
+++ b/day-13/src/main.rs
@@ -0,0 +1,172 @@
+use std::fs;
+
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+    let input = fs::read_to_string("input")?;
+    let (time, ids) = parse_notes(&input)?;
+
+    // Part 1
+    let (earliest, arrival) = find_closest_bus(time, &ids);
+    println!("{}", (arrival - time) * earliest);
+
+    // Part 2
+    let timestamp = find_gauss(&ids);
+    println!("{}", timestamp);
+
+    Ok(())
+}
+
+fn parse_notes(input: &str) -> Result<(u32, Vec<u32>), &str> {
+    let mut lines = input.lines();
+
+    let estimate = lines
+        .next()
+        .ok_or("Input too short")?
+        .parse()
+        .map_err(|_| "Estimate is not a number")?;
+
+    let ids = lines
+        .next()
+        .ok_or("Input too short")?
+        .split(',')
+        .map(|id| id.parse().unwrap_or(1))
+        .collect();
+
+    Ok((estimate, ids))
+}
+
+fn find_closest_bus(time: u32, ids: &Vec<u32>) -> (u32, u32) {
+    ids.iter()
+        .filter(|id| **id != 1)
+        .map(|id| {
+            let mut arrival = *id;
+
+            while arrival < time {
+                arrival += id
+            }
+
+            (*id, arrival)
+        })
+        .min_by_key(|id| id.1)
+        .expect("Must have at least one bus ID")
+}
+
+fn find_gauss(ids: &Vec<u32>) -> u128 {
+    let ids: Vec<u128> = ids.iter().map(|id| *id as u128).collect();
+    let product: u128 = ids.iter().product();
+
+    let gauss = |mut n: u128, mut d: u128, m: u128| -> u128 {
+        while d != 1 {
+            if m == 1 {
+                return 0;
+            };
+
+            let multiplier = if m > d {
+                m / d + (m % d != 0) as u128
+            } else {
+                1
+            };
+
+            n = (n * multiplier) % m;
+            d = (d * multiplier) % m;
+        }
+
+        n / d
+    };
+
+    (0..ids.len())
+        .map(|a| {
+            let b = product / ids[a];
+            let bi = gauss(1, b, ids[a]);
+            let a = (ids[a] * a as u128 - a as u128) % ids[a] as u128;
+
+            a * b * bi
+        })
+        .sum::<u128>()
+        % product
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use indoc::indoc;
+
+    #[test]
+    fn test_simple() -> Result<(), Box<dyn std::error::Error>> {
+        let input = indoc!(
+            "939
+             7,13,x,x,59,x,31,19
+            "
+        );
+
+        let (time, ids) = parse_notes(input)?;
+        let (earliest, arrival) = find_closest_bus(time, &ids);
+
+        assert_eq!(arrival, 944);
+
+        Ok(())
+    }
+
+    #[test]
+    fn test_simple2() -> Result<(), Box<dyn std::error::Error>> {
+        let input = indoc!(
+            "939
+             17,x,13,19
+            "
+        );
+
+        let (time, ids) = parse_notes(input)?;
+        let timestamp = find_gauss(&ids);
+
+        assert_eq!(timestamp, 3417);
+
+        Ok(())
+    }
+
+    #[test]
+    fn test_simple3() -> Result<(), Box<dyn std::error::Error>> {
+        let input = indoc!(
+            "939
+             7,13,x,x,59,x,31,19
+            "
+        );
+
+        let (time, ids) = parse_notes(input)?;
+        let timestamp = find_gauss(&ids);
+
+        assert_eq!(timestamp, 1068781);
+
+        Ok(())
+    }
+
+    #[test]
+    fn test_simple4() -> Result<(), Box<dyn std::error::Error>> {
+        let input = indoc!(
+            "939
+             67,7,59,61
+            "
+        );
+
+        let (time, ids) = parse_notes(input)?;
+        let timestamp = find_gauss(&ids);
+
+        assert_eq!(timestamp, 754018);
+
+        Ok(())
+    }
+
+    #[test]
+    fn test_simple5() -> Result<(), Box<dyn std::error::Error>> {
+        let input = indoc!(
+            "939
+             67,x,7,59,61
+            "
+        );
+
+        let (time, ids) = parse_notes(input)?;
+        let timestamp = find_gauss(&ids);
+
+        assert_eq!(timestamp, 779210);
+
+        Ok(())
+    }
+}

From 04dcd76a2275f80a1da558bb4e497f3c4577412f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Mon, 14 Dec 2020 15:31:05 +0000
Subject: [PATCH 4/7] WIP: Re-implement using ndarray

---
 day-11/Cargo.lock  |  80 +++++++++++++++---------
 day-11/Cargo.toml  |   2 +-
 day-11/src/main.rs | 148 ++++++++++++++++-----------------------------
 3 files changed, 105 insertions(+), 125 deletions(-)

diff --git a/day-11/Cargo.lock b/day-11/Cargo.lock
index 097af7b..edc61df 100644
--- a/day-11/Cargo.lock
+++ b/day-11/Cargo.lock
@@ -11,29 +11,7 @@ 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",
+ "ndarray",
 ]
 
 [[package]]
@@ -60,13 +38,53 @@ dependencies = [
 ]
 
 [[package]]
-name = "petgraph"
-version = "0.5.1"
+name = "matrixmultiply"
+version = "0.2.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7"
+checksum = "916806ba0031cd542105d916a97c8572e1fa6dd79c9c51e7eb43a09ec2dd84c1"
 dependencies = [
- "fixedbitset",
- "indexmap",
+ "rawpointer",
+]
+
+[[package]]
+name = "ndarray"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c0d5c9540a691d153064dc47a4db2504587a75eae07bf1d73f7a596ebc73c04"
+dependencies = [
+ "matrixmultiply",
+ "num-complex",
+ "num-integer",
+ "num-traits",
+ "rawpointer",
+]
+
+[[package]]
+name = "num-complex"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "747d632c0c558b87dbabbe6a82f3b4ae03720d0646ac5b7b4dae89394be5f2c5"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "num-integer"
+version = "0.1.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
+dependencies = [
+ "autocfg",
+ "num-traits",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
+dependencies = [
+ "autocfg",
 ]
 
 [[package]]
@@ -93,6 +111,12 @@ dependencies = [
  "proc-macro2",
 ]
 
+[[package]]
+name = "rawpointer"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
+
 [[package]]
 name = "syn"
 version = "1.0.54"
diff --git a/day-11/Cargo.toml b/day-11/Cargo.toml
index 115407c..1a7f7d8 100644
--- a/day-11/Cargo.toml
+++ b/day-11/Cargo.toml
@@ -8,4 +8,4 @@ edition = "2018"
 
 [dependencies]
 indoc = "0.3"
-petgraph = "0.5"
+ndarray = "0.14"
diff --git a/day-11/src/main.rs b/day-11/src/main.rs
index 813bb24..cc2c6ac 100644
--- a/day-11/src/main.rs
+++ b/day-11/src/main.rs
@@ -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(())

From 3ec82e117e55409ec7381ed9098802b4022c84ff Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Fri, 11 Dec 2020 23:29:34 +0000
Subject: [PATCH 5/7] Complete day 11.1

---
 day-11/Cargo.lock  |  78 ++++++++++++++++++++
 day-11/Cargo.toml  |  10 +++
 day-11/input       |  93 +++++++++++++++++++++++
 day-11/src/main.rs | 180 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 361 insertions(+)
 create mode 100644 day-11/Cargo.lock
 create mode 100644 day-11/Cargo.toml
 create mode 100644 day-11/input
 create mode 100644 day-11/src/main.rs

diff --git a/day-11/Cargo.lock b/day-11/Cargo.lock
new file mode 100644
index 0000000..5e329eb
--- /dev/null
+++ b/day-11/Cargo.lock
@@ -0,0 +1,78 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "day-11"
+version = "0.1.0"
+dependencies = [
+ "indoc",
+]
+
+[[package]]
+name = "indoc"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "47741a8bc60fb26eb8d6e0238bbb26d8575ff623fdc97b1a2c00c050b9684ed8"
+dependencies = [
+ "indoc-impl",
+ "proc-macro-hack",
+]
+
+[[package]]
+name = "indoc-impl"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce046d161f000fffde5f432a0d034d0341dc152643b2598ed5bfce44c4f3a8f0"
+dependencies = [
+ "proc-macro-hack",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "unindent",
+]
+
+[[package]]
+name = "proc-macro-hack"
+version = "0.5.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
+dependencies = [
+ "unicode-xid",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "syn"
+version = "1.0.54"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a2af957a63d6bd42255c359c93d9bfdb97076bd3b820897ce55ffbfbf107f44"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-xid",
+]
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
+
+[[package]]
+name = "unindent"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f14ee04d9415b52b3aeab06258a3f07093182b88ba0f9b8d203f211a7a7d41c7"
diff --git a/day-11/Cargo.toml b/day-11/Cargo.toml
new file mode 100644
index 0000000..5cf3b01
--- /dev/null
+++ b/day-11/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "day-11"
+version = "0.1.0"
+authors = ["Tristan Daniël Maat <tm@tlater.net>"]
+edition = "2018"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+indoc = "0.3"
diff --git a/day-11/input b/day-11/input
new file mode 100644
index 0000000..7cf41d9
--- /dev/null
+++ b/day-11/input
@@ -0,0 +1,93 @@
+LLLLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLL.LLLLLLLL.LLLLLL.LLLLLLLLLLLLL.LLLLLLLL
+LLLLLLLLLL.LLLL.LLLL.LLLLLLLLLLLLLL.LLLLLLL.LLLLLLL.LLLLLL.LLLLLLLL.LLLLLL.LLLLLLLL.LLLLLLLLLLLLL
+LLLLLLLLLLLLLLLLLLLL.LLLLLLLL.LLLLLLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLL.LLLLLL.LLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLLLLLLL.LLLL.LLLLLLLL.LLLLL.LLLLLLLLLLLLLLL.LLLLLLLLLLLLLLL.LLLLLL.LLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLL.LLLLLL.LL.LLLLLLLL.LLLLL.LLLLLLLLLLLLLLL.LLLLLL.LLLLLLLL.LLLLLLLLLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLLLLLLLLLLLL.LLLLLLLL.LLLLLLLLLLLLL.LLLLL.L.LLLLLLLLLLLLLLL.LLLLLL.LLLLLLLLLLLLL.LLLLLLLL
+LLLLLLLLLL.LLLL.LLLL.LLLLLLLL.LLLLL.LLLLLLL.LLLLLLL.LLLLLLLLLLLLLLL.LLLLLL.LLLLLLLL.LLLL.LLLLLLLL
+..L...L.L..L.LL.....L.L..L...L.L.....L.L...LLL..L....L.L.LL.LL...L.....LLL.....L...L..L..L.......
+LLLLLLLLLLLLLLL.LLLLLLLLLLLLL.LLLLL.LLLLLLL.LLLLLLL.LLLLLLLLLLLLLLL.LLLLLL.LLLLLLLL.LLLLLLLLLLLLL
+LLLLLLLLLL.LLLL.LLLLLLLLLLLLL.LLLLL.LLLLLLLLLLLLLLL.LLLLLLLLLLLLLLL.LLLLLL.LLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLL.LLLL.LLLLLLLLLLLLL.LLLLL.LLLLLLL.LLLLLLL.LLLLLLLLLLLLLLL.LLLLLL.LLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLL.LLLL.LLLL.LLLLLLLLLLLLLLLLLLLLLL.LLLLLLL.LLLLLL.LLLLLLLL.LLLLLL.LLLLLLLLLLLLL.LLLLLLLL
+LLLLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLL.LLLLLLL.LLLLLLLLLLLLLLLLLLLLLL.LLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLL.LLLLLLLLLLLLLLLLLL.LLLLL.LLLLLLL.LLLLLLL.LLLLLL.LLLLLLLL.LLLLLLLLLL.LLLL.LLLLLLLLLLLLL
+.....LLL....L..L.L..L.L..L...L.L.LL.....L...L..LL.LL..L.L.LL...LL....LL.....L.....L.L.LL.L..L.L..
+LLLLLLLLLL.LLLLLLLLL.LLLLLLLL.LLLLLLLLLLLLL.LLLLLLL.LLLLLL.LLLLLLLLLLLLLLL.LLLLLLLL.LLLLLLLLLLLLL
+LLLLLLLLLL.LLLL.L.LLLLLLLLLLL.LLLLL.LLLLLLL.LLLLLLLLLLLLLLLLLLLLLLL.LLLLL..LLLLLLLLLLLLLLLLLLLLLL
+LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LL.LLLL.LLLLLLL.LLLLLL.LLLLLLLL.LLLLLL.LLLLLLLL.LLLLLLLLLLLLL
+LLLLLLLLLLLLLLL.LLL.LLLLLLLLL.LLLLLLLLLLLLL.LLLLLLL.LLLLLLLLLLLLLLL.LLLLLLLLLLLLLLL.LLLLLLLLLLLLL
+..L.L.LL.L..LL..L..LL.L..L................L....L............L.L..L...L...L..LLLL....L.L..LL....L.
+LLLLLL.LLL.LLLL.LLLLLLLLLLLLL.LLLLLLLLLLLLL.LLLLLLLLLLLLLL.LLLLLLLLLLLLLLL.LLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLL.LLLL.LLLL.L.LLLLLL.LLLLL.LLLLLLL.LLLLLLL.LLLLLL.LLLLLLLL.LLLLLL.LLLLLLLL.LLLLLLLLLLLLL
+LLLLLLLLLL.LLLL.LLLL.LLLLLLLL.LLLLLLLLLLLLL.LLLLLLLLLLLLLL.LLLLLLLL.LLLLLLLLLLLLLLL.LLLL.LLL.LLLL
+LLLLLLLLLL.LLLL.LLLL.LLLLLLLL.LLL.L.LLL.LLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLL.LLLLLLLL.LLLL.LLLLLLLL
+LL.L.L.L.....L..L...L.L...L.......L...LLL...L.LL.L.....L.LLL.LL....LLLLL.L....LLL.L..LL..L....L.L
+LLLLLLLLLL.LLLLLLLLL.LLLLLLLL.LLLLL.LLLLLLL.LLLLLLL.LLLLLL.LLLLLLLLLLLLLLLLLLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLLLLLLLLLLLL.LLLLLLLL.LLLLL.LLLLLLLLLLLLLLL.LLLLLL.LLLLLLLL.LLLLLLLLLLLLLLL.LLLLLLLLLLLLL
+LLLLLLLLLL.LLLL.LLLL.LLLLLLLL.LLLLLLLLLLL.LLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLL.LLLLLLLLLLLLLLL.LLLLLL
+LLLLLLLLLLLLLLL.LLLL.LLLLLLLL.LLLLLLLLLLLLL.LLLLLLL.LLLLLL.LLLLLLLLLLLLLLL.L.LLLLLLLLLLLLLLLLLLLL
+LLLLLLLLLL.LLLLLLLLL.LLLLLLLL.LLLLLLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLL.LLLLLL.LLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLL.LLLL.LLLL.LLLLLLLLLLLLLLLLLLLLLL.LLLLLLL.LLLLLL.LLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLLLLLLLL
+LLLLLLLLLL.LLLL.LLLL.LLLLLLLL.LLLLL.LLLLLLL.LLLLLLLLLLLLLL.LLLLLLLL.LLLLLL.LLLLLLLL.LLLLLLLLL.LLL
+.L.LL..LL...L....LL...L.LL.L....LL.LL......L..L........LL..LLL..L...LLL.....LL....L.L...L.....L..
+LLLLLLLLLL.LLLL.LLLLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLL.LLLLLL.LLLLLLLLLLLLLLL.LLL.LLLL.LLLL.LLLLLLLL
+LLLLLLLLLL.LLLLLLLLL.LLLLLLLL.LLLLL.LLLLLLL.LLLLLLL.LLLLLLLLLLLLLLL.LLLLLL.LLLLLL.L.LLLLLLLLLLLLL
+.LLLLLLLLLLLLLL.LLLL.LLLLLLLL.LLLLLLLLLLLLLLLLLLL.L.LLLLLL.LLLLLLLL.LLLLLL.LLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLLLLLLL.LLLL.LLLLLLLL.LLLLL.LLLLLLL.LLLLLLL.LLLLLL.LLLLLLLL.LLLLLLLLLLLLLLL.LLLLLLLLLLLLL
+LLLLLLLLLL.LLLL.LLLLL.LLLLLLL.LLLLLLLLLLLLL.LLLLLLL.LLLLLL.LLLLLLLL.LLLLLL.LLLLLLLLLLLLLLLLLLLLLL
+LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLL.LLLLLL.LLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLL.LLLLLLLLL.LLLLLLLL.LLLLLLLLLLLLL.LLLLLLL.LLLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLLL
+LLLLLLLLLL.LLLL.LLLL.LLLLLLLLLLLLLLLLLLLLLL.LLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLL.LLLLLLLLL.LLLLLLLL.LLLLL.LLLLLLL.LLL.LLL.LLLLLL.LLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLLLL
+..L....LL..LL.LLLL......L..L...LLL.L......L.L.....L....L....LLLL.....L..LL...L....L....LLL....LL.
+LLLLLLLLLLLLLLL.LLLL.LLLLL.LLLLLLLL..LLLLLL.LLLLLLL.LLLLLLLLLLLLLLL.LLLLLL.LLLLLLLL.LLLLLLLLLLLLL
+LLLLLLLLLL.LLLL.LLLLLLLLLLLLL.LLLLL.LLLLLLL.LLLLLLLLLLLLLL.LLLLLLLLLLLLLLL.LLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLLLLLLL.LLLL.LLLLLLLL.LLLL..LLLLLLLLLLLLLLL.LLLLLL.LLLLLLLL.LLLLLLLLLLLLLLL.LLLLLLLLLLLLL
+LLLLLLLLLL.LLLL.LLLL.LLLLLLLL.LLLLL.LLLLLLL.LLL.LLLLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLL.LLLLLLLLLLLLL
+LLLLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLL.LLLLLL..LLLLLL.LLLLLLLLLLLLLLL.LLLLLLLLLLLLL.LLLLL.LL
+LLLLLLLLLLLLLLL.LLL..LLLLLLLL.LL.LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLL.LLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLL.LLLLLLLLL.LLLLLLLL.LLLLL.LLLLLLLLLLLLL.LLLLLLLL.LLLLLLLLLLLLLLL.LLLLLLLLLLLLL.LLLLLLLL
+...LL.LL.....LL..LLL.....LL....LL....L.LL.L.LL....L........LLLL..LLLLLL.L..L..LLL......L....L....
+LLL.LLLLLLLLLLLLLLLL.LLLLLLLL.LLLLL.LLLLLLL.LLLLLLL.LLLLLL.LLLLLLLL.LLLLLL.LLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLL.LLLLLLL.LLLLLLL.LLLLLL.LLLLLLLL.LL.LLL.LLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLLLLLLL.LLLLLLLLLLLLL.LLLLL.LLLLLLL.LLLLLLL.LLLLLLLLLLLLLLL.LLLLLL.LLLLLLLLLLLLLLLLLLLLLL
+LLLLLLLLLL.LLLL.LLLLLLLLLLLLLLLLLLL.LLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLLL.LLLLLLLLLLLLL
+LLLLLLLLLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLL.LLLLLLLL.LLLLLL.LLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLL.LLLL.LLLL.LLLLLLLL.LLLLL.LLLLLLLLLLLLLLL.LLLLLLLLLLLLLLL.LLLLLL.LLLLLLLL.LLLLLLLLLLLLL
+.....L.L..LL..LL..L.L.L.....LLLLL.....L..L...L.....L.L..L..L....LL....L...........L.L.......L.LLL
+LLLLLLLLLL.LLLL.LLLLLLLLLLLLLLLLLLL.LLLLLLL.LLLLLLL.LLLLLL.LLLLLLLLLLLLLLL.LLLLLLLLLLLLL.LLLLLLLL
+LLL.LLLLLL.LLLL.LLLL.LLLLLLLL.LLLLL.LLLLLLL.LLLLLLL.LLLLLL.LLLLLLLL.LLLLLL..LLLLLLL.LLLLLLLLLLLLL
+LLLLLLLLLL.LLLL.LLLLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLLLL.LLLLLLLLLLL.LLLLLLLL
+LLLLLLLLLL.LLLL.LLLL.LLLLLLLLLLLLLL.LLLLLLL.L.LLLLLLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLL.LLLLLLLLLLLLL
+LLLL.L.LLL.LLLL.LLLL.LLLLLLLLLLLLLL.LLLLLLL.LLLLLLL.LLLLLL.LLLLLLLLLLLLLLL.LLLLLLLL.LL.L.LLLLLLLL
+L.LLL.................LLL....L...LL..........L.L.L.......L.....L.....LLLLLL......L.......L...L.LL
+LLLLLLLLLLLLLLL.LLLLLLLLLLLLL.LLLLL.LLLLLLL.LLLLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLL.LLLLLLLLL.LLLLLLLL.LLLLL.LL.LLLL.LLLLLLL.LLLLLL.LLLLLLLL.LLLLLLLLLLLLLLL.LLLLLLLLLLLLL
+LLLLLLLLLL.LLLL.LLLL.LLLLLLLL.LLLLL.LLLLLLL.LLLLLLLLLLLLLLLLLLLLLLL.LLLLLL.LLLLLLLL.LLLL.LLLLL.LL
+LLLLLLLLLL.LLLL.LLLLLLLLLLLLLLLLLLL.LLL.LLL.LLLLLLL.LLLLLL.LLLLLLLL.LLLLLLLLLLLLLLLLLLLL.LLLLLLLL
+LLLLLLLLLLLLLLL.LLLLLLLLLLLLLLLLLLL.LLLLLLL.LLLLLLLLLLLLLL.LLLLLLLL.LLLLLL.LLLLLLLL.LLLLLLLLLLLLL
+LLLLLLLLLLLLLLL.LLLL.LLLLLLLL.LLLLLLLLLLLLLLLLLLLLL.LLLLLL.LLLLLLLLLLL.LLL.LLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLLLLLLL.LLL..LLLLLLLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLL.LLLLLLLLLLLLLLL.LLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLL.LLLL.LLLL.LLLLLLLL.LLLLLLLLLLLLL.LLLLLLL.LLLLLL.LLLLLLLL.LLLLLLLLLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLL.LLLL.LLLL.LLLLLLLLLLLLLLLLLLLLLL.LLLLLLL.LLLLLL.LLLLLLLL.LLLLLLLLLLLLLLL.LLLL.LLLLLLLL
+..L...LL.LLL.LLL.......LL..LL.L...LLL.....L....LLLL.L..........L.....L.L....L..............LL.L..
+LLLLLLLLLL.LLLL.LLL..LLLLLLLLLLLLLL.LLLLLLLLLLLLLLL.LLLLLLLLLLLLLLL.LLLLLLLLLLLLLLL.LLLLLLLLLLLLL
+LLLLLLLLLLLLLLLLLLLLLL.LLLLLL.LLLLL.LLLLLLLLLLLLLLLLLLLLLL.LLLLLLLL.LLLLLL.LLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLL.LLLLLLLLL.LLL.LLLLLLLLLLLLLLLLLL.LLLLLLL.LLLLLL.LLLLLLLL.LLLLLLLLLLLLLLLLLLLL.LLLLLLLL
+LLLLLLLLLL.LLLL.LLL.LLLLLLLLL.LLLLL.LLLLLLL.LLLLLLL.LLLLLL.LLLLLLLL.LLLLLLLLLLLLLLLLL.LL.LLLLLLLL
+LLLLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLL.LLLLLL.LLLLLLLLLLLL.LLLLL.LLLLL.LLLL.LLLLLLLL
+LLLLLLLLLL.LLLL.LLLLLLLLLLLLL.LL.LL.LLLLLLLLLLLLLLLLLLLLLL.LLLLLLLL.LLLLLL.LLLLLLLL.LLLL.LLLLLLLL
+LL.L.L..LL..L.......L.L..LL....L.L.L...L.L..LL....LL.LL....L....LL..L....L............L.......L..
+LLLLLLLLLL.LLLL.LLLL.LLLLLLLLLLLLLLLLLLLLLL.LLLLLLL.LLLLLL.LLLLLLLLLLLLLLL.LLLLLLLLLLLLL.LLLLLLLL
+LLLLLLLLLL.LLLL.LLLL.LLLLLLLLLLLLLL.LLLLLLL.LLLLLLL.LLLLLL.LLLLLLLL.LLLLLL.LLLLLLLLLLLLLLLLLLLLLL
+LLLLLLLLLL.LLLLLLLLL.LLLLLLLL.LLLLLLLLLLLLL.LLLLLLL.LLLLLL.LLLLLLLLLLLLLLLLLLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLL.LLLLLLLLLLLLLLLLLL.LLLLL.LLLLLLLLLLLLLLL.LLLLLLLLLLLLLLL.LLLLLL.LLLLLL.L.LLLL.LLLLLLLL
+LLLLLLLLLL.LLLL.LLLL.LLLLLLLL.LLLLL.LLLLLLL.LLLLLLL.LLLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
+..L.L.....L......L..L.....L.......L..L....LL...L.L.L...LLL.L.L..L..L..L......LLL.....L..L..L.....
+LLLLLLLLLLLLLLL.LLLLLL.LLLLLL.LLLLL.LLLLLLL.LLLLLLL.LLLLLL.LLLLLLLL.LLLLLL.LLLLLLLLLLLLL.LLLLLLLL
+LLLLLLLLLL.LLLLLLLLL.LLLLLLLLLLLLLL.LLLLLLLLLLLLLLLLLLLLLL.LLLLLLLL.LLLLLL.LLLLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLL.LLLL.LLLLLLLLLLLLL.LLLLLLLLLLLLL.LLLLLLLLLL.LLLLLLLLLLLL.LLLLLL.L.LLLLLL.LLLL.LLLLLLLL
+LLLLLLLLLL.LLLL.LLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLL.LLLLLLLLLLLLLLL..LLLLLLLLLLLL.LLLLLLLL
+LLLLLLLLLL.LLLL.LLLLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLL.LLLLLL.LLLLLLLL.LLLLLL.LLLLLLLLLLLLL.LLLLLLLL
+LLLLLLLLLL.LLLLLLLLL.LL.LLLLL.LLLLLLLLLLLLL.LLLLLLL.LLLLLL.LLLLLLLL.LLLLLLLLLLLLLLL.LLLLLLLLLLLLL
diff --git a/day-11/src/main.rs b/day-11/src/main.rs
new file mode 100644
index 0000000..886261d
--- /dev/null
+++ b/day-11/src/main.rs
@@ -0,0 +1,180 @@
+use std::fs;
+
+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);
+    println!("{}", result);
+
+    Ok(())
+}
+
+#[derive(Copy, Clone, Debug, PartialEq)]
+enum Seating {
+    Occupied,
+    Empty,
+    Floor,
+}
+
+impl Seating {
+    fn new(symbol: char) -> Result<Self, String> {
+        match symbol {
+            '#' => Ok(Seating::Occupied),
+            'L' => Ok(Seating::Empty),
+            '.' => Ok(Seating::Floor),
+            rubbish => Err(format!("Found some rubbish on the floor, area must be clean to conserve human behavior: {}", rubbish))
+        }
+    }
+}
+
+fn parse_layout(input: &str) -> Result<Vec<Vec<Seating>>, String> {
+    input
+        .lines()
+        .map(|line| line.chars().map(Seating::new).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();
+            row.push('\n');
+            row
+        })
+        .collect();
+
+    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
+        .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<Seating>>) -> (Vec<Vec<Seating>>, 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,
+                })
+                .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;
+
+        if changes == 0 {
+            break;
+        }
+    }
+
+    loop_layout
+        .iter()
+        .flatten()
+        .filter(|seat| **seat == Seating::Occupied)
+        .count()
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use indoc::indoc;
+
+    #[test]
+    fn test_simple() -> 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_eventually_occupied_seats(&layout);
+
+        assert_eq!(result, 37);
+        Ok(())
+    }
+}

From 3c3ef92ff8ecc7823de679d72a91f7a8833b6aa7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Sat, 12 Dec 2020 21:42:16 +0000
Subject: [PATCH 6/7] 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<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())
-        .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();
-
-    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
-        .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<Seating>>) -> (Vec<Vec<Seating>>, 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::<Result<_, String>>()?;
 
-    (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<Vec<Seating>>) -> 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()
 }
 

From 85bbc6e9d83d49d87ff58e7e2022630f09b980c9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Mon, 14 Dec 2020 15:31:05 +0000
Subject: [PATCH 7/7] WIP: Re-implement using ndarray

---
 day-11/Cargo.lock  |  80 +++++++++++++++---------
 day-11/Cargo.toml  |   2 +-
 day-11/src/main.rs | 148 ++++++++++++++++-----------------------------
 3 files changed, 105 insertions(+), 125 deletions(-)

diff --git a/day-11/Cargo.lock b/day-11/Cargo.lock
index 097af7b..edc61df 100644
--- a/day-11/Cargo.lock
+++ b/day-11/Cargo.lock
@@ -11,29 +11,7 @@ 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",
+ "ndarray",
 ]
 
 [[package]]
@@ -60,13 +38,53 @@ dependencies = [
 ]
 
 [[package]]
-name = "petgraph"
-version = "0.5.1"
+name = "matrixmultiply"
+version = "0.2.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7"
+checksum = "916806ba0031cd542105d916a97c8572e1fa6dd79c9c51e7eb43a09ec2dd84c1"
 dependencies = [
- "fixedbitset",
- "indexmap",
+ "rawpointer",
+]
+
+[[package]]
+name = "ndarray"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c0d5c9540a691d153064dc47a4db2504587a75eae07bf1d73f7a596ebc73c04"
+dependencies = [
+ "matrixmultiply",
+ "num-complex",
+ "num-integer",
+ "num-traits",
+ "rawpointer",
+]
+
+[[package]]
+name = "num-complex"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "747d632c0c558b87dbabbe6a82f3b4ae03720d0646ac5b7b4dae89394be5f2c5"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "num-integer"
+version = "0.1.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
+dependencies = [
+ "autocfg",
+ "num-traits",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
+dependencies = [
+ "autocfg",
 ]
 
 [[package]]
@@ -93,6 +111,12 @@ dependencies = [
  "proc-macro2",
 ]
 
+[[package]]
+name = "rawpointer"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
+
 [[package]]
 name = "syn"
 version = "1.0.54"
diff --git a/day-11/Cargo.toml b/day-11/Cargo.toml
index 115407c..1a7f7d8 100644
--- a/day-11/Cargo.toml
+++ b/day-11/Cargo.toml
@@ -8,4 +8,4 @@ edition = "2018"
 
 [dependencies]
 indoc = "0.3"
-petgraph = "0.5"
+ndarray = "0.14"
diff --git a/day-11/src/main.rs b/day-11/src/main.rs
index 813bb24..cc2c6ac 100644
--- a/day-11/src/main.rs
+++ b/day-11/src/main.rs
@@ -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(())