From 3b877bf4cc667eb8bcc787d145203600a4dba2d2 Mon Sep 17 00:00:00 2001
From: Prefetch
Date: Sat, 25 Feb 2023 11:41:27 +0100
Subject: Initial commit

---
 d19/Cargo.toml  |  6 ++++
 d19/src/main.rs | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 91 insertions(+)
 create mode 100644 d19/Cargo.toml
 create mode 100644 d19/src/main.rs

(limited to 'd19')

diff --git a/d19/Cargo.toml b/d19/Cargo.toml
new file mode 100644
index 0000000..92c186c
--- /dev/null
+++ b/d19/Cargo.toml
@@ -0,0 +1,6 @@
+[package]
+name = "d19"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
diff --git a/d19/src/main.rs b/d19/src/main.rs
new file mode 100644
index 0000000..91d9524
--- /dev/null
+++ b/d19/src/main.rs
@@ -0,0 +1,85 @@
+// Find the next Elf still in the game, to the left of `i'
+fn next_elf(elves: &[bool], i: usize) -> usize {
+    let mut n = (i + 1) % elves.len();
+    while !elves[n] {
+        n = (n + 1) % elves.len();
+    }
+    n
+}
+
+fn solve_puzzle(
+    num_elves: usize,
+    victim1: usize,
+    next_victim: fn(&[bool], usize, usize, usize) -> usize,
+) -> usize {
+    // We only need to store whether an Elf is still in the game;
+    // we don't care how many presents each one has.
+    let mut elves = [true].repeat(num_elves);
+
+    // Thief and victim indices, respectively
+    let mut t = 0;
+    let mut v = victim1;
+
+    let mut rem = num_elves;
+    while rem > 1 {
+        // Perform the act of stealing
+        elves[v] = false;
+        rem -= 1;
+
+        // Who does the stealing next?
+        t = next_elf(&elves, t);
+
+        // Who gets stolen from next?
+        v = next_victim(&elves, rem, t, v);
+    }
+
+    // Elves should be numbered from 1 instead of 0
+    t + 1
+}
+
+// Part 1: victim is always to the left of thief.
+fn next_victim_part1(elves: &[bool], _rem: usize, nthief: usize, _victim: usize) -> usize {
+    next_elf(elves, nthief)
+}
+
+// Part 2: victim is always across from thief.
+// It's less clear that this function is correct, but it is!
+fn next_victim_part2(elves: &[bool], rem: usize, _nthief: usize, victim: usize) -> usize {
+    let mut nv = next_elf(elves, victim);
+    if rem % 2 == 0 {
+        nv = next_elf(elves, nv);
+    }
+    nv
+}
+
+fn main() {
+    // My personal puzzle input
+    let input = 3014603;
+
+    // Part 1 gives 1834903 for me
+    println!(
+        "Part 1 solution: {}",
+        solve_puzzle(input, 1, next_victim_part1)
+    );
+
+    // Part 2 gives 1420280 for me
+    println!(
+        "Part 2 solution: {}",
+        solve_puzzle(input, input / 2, next_victim_part2)
+    );
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn part1_example1() {
+        assert_eq!(solve_puzzle(5, 1, next_victim_part1), 3);
+    }
+
+    #[test]
+    fn part2_example1() {
+        assert_eq!(solve_puzzle(5, 5 / 2, next_victim_part2), 2);
+    }
+}
-- 
cgit v1.2.3