From cd519c3bd1d03e37dfc735209691448282c15a76 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Thu, 10 Dec 2020 23:41:34 +0000
Subject: [PATCH 1/2] Complete day 10

---
 day-10/.gitignore  |   1 +
 day-10/Cargo.lock  |  78 ++++++++++++++++
 day-10/Cargo.toml  |  10 ++
 day-10/input       |  95 +++++++++++++++++++
 day-10/src/main.rs | 228 +++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 412 insertions(+)
 create mode 100644 day-10/.gitignore
 create mode 100644 day-10/Cargo.lock
 create mode 100644 day-10/Cargo.toml
 create mode 100644 day-10/input
 create mode 100644 day-10/src/main.rs

diff --git a/day-10/.gitignore b/day-10/.gitignore
new file mode 100644
index 0000000..b83d222
--- /dev/null
+++ b/day-10/.gitignore
@@ -0,0 +1 @@
+/target/
diff --git a/day-10/Cargo.lock b/day-10/Cargo.lock
new file mode 100644
index 0000000..a47b207
--- /dev/null
+++ b/day-10/Cargo.lock
@@ -0,0 +1,78 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "day-10"
+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-10/Cargo.toml b/day-10/Cargo.toml
new file mode 100644
index 0000000..14614ac
--- /dev/null
+++ b/day-10/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "day-10"
+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-10/input b/day-10/input
new file mode 100644
index 0000000..f7374a0
--- /dev/null
+++ b/day-10/input
@@ -0,0 +1,95 @@
+76
+12
+97
+28
+132
+107
+145
+121
+84
+34
+115
+127
+22
+23
+11
+135
+113
+82
+140
+119
+69
+77
+83
+36
+13
+37
+92
+133
+122
+99
+147
+112
+42
+62
+65
+40
+123
+139
+33
+129
+149
+68
+41
+16
+48
+109
+5
+27
+142
+81
+90
+9
+78
+103
+26
+100
+141
+59
+55
+120
+126
+1
+35
+2
+20
+114
+58
+54
+10
+51
+116
+93
+6
+134
+108
+47
+70
+91
+138
+63
+19
+64
+148
+106
+21
+98
+43
+30
+146
+46
+128
+73
+94
+87
+29
diff --git a/day-10/src/main.rs b/day-10/src/main.rs
new file mode 100644
index 0000000..abd40e8
--- /dev/null
+++ b/day-10/src/main.rs
@@ -0,0 +1,228 @@
+use std::convert::TryInto;
+use std::fs;
+
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+    let input = fs::read_to_string("input")?;
+    let jolts = parse_jolts(&input)?;
+
+    // Part 1
+    let result = chain_all(&jolts);
+    println!("{}", result.0 * result.2);
+
+    // Part 2
+    let result = count_possible_chains(&jolts)?;
+    println!("{}", result);
+
+    Ok(())
+}
+
+fn count_possible_chains(jolts: &Vec<u64>) -> Result<u64, std::num::TryFromIntError> {
+    let mut jolts = jolts.to_vec();
+    jolts.push(0);
+    jolts.sort();
+    jolts.push(jolts.last().expect("Need some jolts") + 3);
+
+    let window_lengths: Vec<usize> = jolts
+        .windows(2)
+        .scan(0, |length, window| {
+            if let [previous, current, _empty @ ..] = window {
+                if *current - *previous < 3 {
+                    *length += 1;
+                    Some(None)
+                } else {
+                    let full_length = *length;
+                    *length = 0;
+                    Some(Some(full_length))
+                }
+            } else {
+                unreachable!("Window size is 2");
+            }
+        })
+        .filter_map(|option| option)
+        .collect();
+
+    fn permutations(length: u32) -> u64 {
+        if length == 0 {
+            1
+        } else {
+            2u64.pow(length - 1) - if length > 3 { 2u64.pow(length - 4) } else { 0 }
+        }
+    }
+
+    window_lengths
+        .iter()
+        .map(|length| Ok(permutations((*length).try_into()?)))
+        .product::<Result<u64, _>>()
+}
+
+fn chain_all(jolts: &Vec<u64>) -> (usize, usize, usize) {
+    let mut jolts = jolts.to_vec();
+    // Add input jolts
+    jolts.push(0);
+    // Add output jolts
+    jolts.sort();
+    jolts.push(jolts.last().expect("Need some jolts") + 3);
+
+    let jolt_jumps: Vec<u64> = jolts
+        .windows(2)
+        .map(|window| {
+            if let [first, second, _empty @ ..] = window {
+                second - first
+            } else {
+                unreachable!("Window size is 2");
+            }
+        })
+        .collect();
+
+    let jump_1s = jolt_jumps.iter().filter(|e| **e == 1).count();
+    let jump_2s = jolt_jumps.iter().filter(|e| **e == 2).count();
+    let jump_3s = jolt_jumps.iter().filter(|e| **e == 3).count();
+
+    (jump_1s, jump_2s, jump_3s)
+}
+
+fn parse_jolts(input: &str) -> Result<Vec<u64>, std::num::ParseIntError> {
+    input.lines().map(|line| line.parse()).collect()
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use indoc::indoc;
+
+    #[test]
+    fn test_simple() -> Result<(), Box<dyn std::error::Error>> {
+        let input = indoc!(
+            "16
+             10
+             15
+             5
+             1
+             11
+             7
+             19
+             6
+             12
+             4
+            "
+        );
+
+        let jolts = parse_jolts(input)?;
+        let result = chain_all(&jolts);
+
+        assert_eq!(result.0 * result.2, 7 * 5);
+        Ok(())
+    }
+
+    #[test]
+    fn test_simple2() -> Result<(), Box<dyn std::error::Error>> {
+        let input = indoc!(
+            "28
+             33
+             18
+             42
+             31
+             14
+             46
+             20
+             48
+             47
+             24
+             23
+             49
+             45
+             19
+             38
+             39
+             11
+             1
+             32
+             25
+             35
+             8
+             17
+             7
+             9
+             4
+             2
+             34
+             10
+             3
+            "
+        );
+
+        let jolts = parse_jolts(input)?;
+        let result = chain_all(&jolts);
+
+        assert_eq!(result.0 * result.2, 22 * 10);
+        Ok(())
+    }
+
+    #[test]
+    fn test_simple3() -> Result<(), Box<dyn std::error::Error>> {
+        let input = indoc!(
+            "16
+             10
+             15
+             5
+             1
+             11
+             7
+             19
+             6
+             12
+             4
+            "
+        );
+
+        let jolts = parse_jolts(input)?;
+        let result = count_possible_chains(&jolts)?;
+        assert_eq!(result, 8);
+
+        Ok(())
+    }
+
+    #[test]
+    fn test_simple4() -> Result<(), Box<dyn std::error::Error>> {
+        let input = indoc!(
+            "28
+             33
+             18
+             42
+             31
+             14
+             46
+             20
+             48
+             47
+             24
+             23
+             49
+             45
+             19
+             38
+             39
+             11
+             1
+             32
+             25
+             35
+             8
+             17
+             7
+             9
+             4
+             2
+             34
+             10
+             3
+            "
+        );
+
+        let jolts = parse_jolts(input)?;
+        let result = count_possible_chains(&jolts)?;
+
+        assert_eq!(result, 19208);
+        Ok(())
+    }
+}

From 70184751e65755d1422bcd3884b4e093e698a82f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= <tm@tlater.net>
Date: Thu, 10 Dec 2020 23:41:34 +0000
Subject: [PATCH 2/2] Complete day 10

---
 day-10/.gitignore  |   1 +
 day-10/Cargo.lock  |  78 ++++++++++++++++
 day-10/Cargo.toml  |  10 ++
 day-10/input       |  95 +++++++++++++++++++
 day-10/src/main.rs | 228 +++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 412 insertions(+)
 create mode 100644 day-10/.gitignore
 create mode 100644 day-10/Cargo.lock
 create mode 100644 day-10/Cargo.toml
 create mode 100644 day-10/input
 create mode 100644 day-10/src/main.rs

diff --git a/day-10/.gitignore b/day-10/.gitignore
new file mode 100644
index 0000000..b83d222
--- /dev/null
+++ b/day-10/.gitignore
@@ -0,0 +1 @@
+/target/
diff --git a/day-10/Cargo.lock b/day-10/Cargo.lock
new file mode 100644
index 0000000..a47b207
--- /dev/null
+++ b/day-10/Cargo.lock
@@ -0,0 +1,78 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "day-10"
+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-10/Cargo.toml b/day-10/Cargo.toml
new file mode 100644
index 0000000..14614ac
--- /dev/null
+++ b/day-10/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "day-10"
+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-10/input b/day-10/input
new file mode 100644
index 0000000..f7374a0
--- /dev/null
+++ b/day-10/input
@@ -0,0 +1,95 @@
+76
+12
+97
+28
+132
+107
+145
+121
+84
+34
+115
+127
+22
+23
+11
+135
+113
+82
+140
+119
+69
+77
+83
+36
+13
+37
+92
+133
+122
+99
+147
+112
+42
+62
+65
+40
+123
+139
+33
+129
+149
+68
+41
+16
+48
+109
+5
+27
+142
+81
+90
+9
+78
+103
+26
+100
+141
+59
+55
+120
+126
+1
+35
+2
+20
+114
+58
+54
+10
+51
+116
+93
+6
+134
+108
+47
+70
+91
+138
+63
+19
+64
+148
+106
+21
+98
+43
+30
+146
+46
+128
+73
+94
+87
+29
diff --git a/day-10/src/main.rs b/day-10/src/main.rs
new file mode 100644
index 0000000..cf9c9c7
--- /dev/null
+++ b/day-10/src/main.rs
@@ -0,0 +1,228 @@
+use std::convert::TryInto;
+use std::fs;
+
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+    let input = fs::read_to_string("input")?;
+    let jolts = parse_jolts(&input)?;
+
+    // Part 1
+    let result = chain_all(&jolts);
+    println!("{}", result.0 * result.2);
+
+    // Part 2
+    let result = count_possible_chains(&jolts)?;
+    println!("{}", result);
+
+    Ok(())
+}
+
+fn count_possible_chains(jolts: &Vec<u64>) -> Result<u64, std::num::TryFromIntError> {
+    let mut jolts = jolts.to_vec();
+    jolts.push(0);
+    jolts.sort();
+    jolts.push(jolts.last().expect("Need some jolts") + 3);
+
+    let window_lengths: Vec<usize> = jolts
+        .windows(2)
+        .scan(0, |length, window| {
+            if let [previous, current, _empty @ ..] = window {
+                if *current - *previous < 3 {
+                    *length += 1;
+                    Some(None)
+                } else {
+                    let full_length = *length;
+                    *length = 0;
+                    Some(Some(full_length))
+                }
+            } else {
+                unreachable!("Window size is 2");
+            }
+        })
+        .filter_map(|option| option)
+        .collect();
+
+    fn permutations(length: u32) -> u64 {
+        if length == 0 {
+            1
+        } else {
+            2u64.pow(length - 1) - if length > 3 { 2u64.pow(length - 4) } else { 0 }
+        }
+    }
+
+    window_lengths
+        .iter()
+        .map(|length| Ok(permutations((*length).try_into()?)))
+        .product()
+}
+
+fn chain_all(jolts: &Vec<u64>) -> (usize, usize, usize) {
+    let mut jolts = jolts.to_vec();
+    // Add input jolts
+    jolts.push(0);
+    // Add output jolts
+    jolts.sort();
+    jolts.push(jolts.last().expect("Need some jolts") + 3);
+
+    let jolt_jumps: Vec<u64> = jolts
+        .windows(2)
+        .map(|window| {
+            if let [first, second, _empty @ ..] = window {
+                second - first
+            } else {
+                unreachable!("Window size is 2");
+            }
+        })
+        .collect();
+
+    let jump_1s = jolt_jumps.iter().filter(|e| **e == 1).count();
+    let jump_2s = jolt_jumps.iter().filter(|e| **e == 2).count();
+    let jump_3s = jolt_jumps.iter().filter(|e| **e == 3).count();
+
+    (jump_1s, jump_2s, jump_3s)
+}
+
+fn parse_jolts(input: &str) -> Result<Vec<u64>, std::num::ParseIntError> {
+    input.lines().map(|line| line.parse()).collect()
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use indoc::indoc;
+
+    #[test]
+    fn test_simple() -> Result<(), Box<dyn std::error::Error>> {
+        let input = indoc!(
+            "16
+             10
+             15
+             5
+             1
+             11
+             7
+             19
+             6
+             12
+             4
+            "
+        );
+
+        let jolts = parse_jolts(input)?;
+        let result = chain_all(&jolts);
+
+        assert_eq!(result.0 * result.2, 7 * 5);
+        Ok(())
+    }
+
+    #[test]
+    fn test_simple2() -> Result<(), Box<dyn std::error::Error>> {
+        let input = indoc!(
+            "28
+             33
+             18
+             42
+             31
+             14
+             46
+             20
+             48
+             47
+             24
+             23
+             49
+             45
+             19
+             38
+             39
+             11
+             1
+             32
+             25
+             35
+             8
+             17
+             7
+             9
+             4
+             2
+             34
+             10
+             3
+            "
+        );
+
+        let jolts = parse_jolts(input)?;
+        let result = chain_all(&jolts);
+
+        assert_eq!(result.0 * result.2, 22 * 10);
+        Ok(())
+    }
+
+    #[test]
+    fn test_simple3() -> Result<(), Box<dyn std::error::Error>> {
+        let input = indoc!(
+            "16
+             10
+             15
+             5
+             1
+             11
+             7
+             19
+             6
+             12
+             4
+            "
+        );
+
+        let jolts = parse_jolts(input)?;
+        let result = count_possible_chains(&jolts)?;
+        assert_eq!(result, 8);
+
+        Ok(())
+    }
+
+    #[test]
+    fn test_simple4() -> Result<(), Box<dyn std::error::Error>> {
+        let input = indoc!(
+            "28
+             33
+             18
+             42
+             31
+             14
+             46
+             20
+             48
+             47
+             24
+             23
+             49
+             45
+             19
+             38
+             39
+             11
+             1
+             32
+             25
+             35
+             8
+             17
+             7
+             9
+             4
+             2
+             34
+             10
+             3
+            "
+        );
+
+        let jolts = parse_jolts(input)?;
+        let result = count_possible_chains(&jolts)?;
+
+        assert_eq!(result, 19208);
+        Ok(())
+    }
+}