diff --git a/day-15/Cargo.lock b/day-15/Cargo.lock
new file mode 100644
index 0000000..1135a55
--- /dev/null
+++ b/day-15/Cargo.lock
@@ -0,0 +1,78 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "day-15"
+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-15/Cargo.toml b/day-15/Cargo.toml
new file mode 100644
index 0000000..5d876d5
--- /dev/null
+++ b/day-15/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "day-15"
+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-15/src/main.rs b/day-15/src/main.rs
new file mode 100644
index 0000000..8aa0f24
--- /dev/null
+++ b/day-15/src/main.rs
@@ -0,0 +1,121 @@
+use std::collections::HashMap;
+
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+    // Part 1
+    let numbers = parse_numbers("1,20,11,6,12,0")?;
+    let result = play(&numbers, 2020);
+    println!("{}", result);
+
+    // Part 2
+    let numbers = parse_numbers("1,20,11,6,12,0")?;
+    let result = play(&numbers, 30000000);
+    println!("{}", result);
+
+    Ok(())
+}
+
+fn parse_numbers(input: &str) -> Result<Vec<u32>, std::num::ParseIntError> {
+    input.split(',').map(|number| number.parse()).collect()
+}
+
+fn play(numbers: &Vec<u32>, turns: usize) -> u32 {
+    let mut said = HashMap::new();
+    for (turn, number) in numbers.iter().enumerate() {
+        said.insert(*number, (turn + 1, 0));
+    }
+    let mut last = *numbers.last().expect("Must have at least one number");
+
+    for turn in numbers.len()..turns {
+        match said.get(&last) {
+            Some((_, 0)) | None => {
+                last = 0;
+
+                let entry = said.entry(last).or_insert((0, 0));
+                *entry = (turn + 1, entry.0);
+            }
+            Some((last_turn, last_last_turn)) => {
+                last = (last_turn - last_last_turn) as u32;
+
+                let entry = said.entry(last).or_insert((0, 0));
+                *entry = (turn + 1, entry.0);
+            }
+        };
+    }
+
+    last
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_simple() -> Result<(), Box<dyn std::error::Error>> {
+        let input = "0,3,6";
+        let numbers = parse_numbers(input)?;
+        let result = play(&numbers, 2020);
+
+        assert_eq!(result, 436);
+        Ok(())
+    }
+
+    #[test]
+    fn test_simple0() -> Result<(), Box<dyn std::error::Error>> {
+        let input = "1,3,2";
+        let numbers = parse_numbers(input)?;
+        let result = play(&numbers, 2020);
+
+        assert_eq!(result, 1);
+        Ok(())
+    }
+
+    #[test]
+    fn test_simple1() -> Result<(), Box<dyn std::error::Error>> {
+        let input = "2,1,3";
+        let numbers = parse_numbers(input)?;
+        let result = play(&numbers, 2020);
+
+        assert_eq!(result, 10);
+        Ok(())
+    }
+
+    #[test]
+    fn test_simple2() -> Result<(), Box<dyn std::error::Error>> {
+        let input = "1,2,3";
+        let numbers = parse_numbers(input)?;
+        let result = play(&numbers, 2020);
+
+        assert_eq!(result, 27);
+        Ok(())
+    }
+
+    #[test]
+    fn test_simple3() -> Result<(), Box<dyn std::error::Error>> {
+        let input = "2,3,1";
+        let numbers = parse_numbers(input)?;
+        let result = play(&numbers, 2020);
+
+        assert_eq!(result, 78);
+        Ok(())
+    }
+
+    #[test]
+    fn test_simple4() -> Result<(), Box<dyn std::error::Error>> {
+        let input = "3,2,1";
+        let numbers = parse_numbers(input)?;
+        let result = play(&numbers, 2020);
+
+        assert_eq!(result, 438);
+        Ok(())
+    }
+
+    #[test]
+    fn test_simple5() -> Result<(), Box<dyn std::error::Error>> {
+        let input = "3,1,2";
+        let numbers = parse_numbers(input)?;
+        let result = play(&numbers, 2020);
+
+        assert_eq!(result, 1836);
+        Ok(())
+    }
+}