diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 404cfc8..cdc0b41 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -103,3 +103,8 @@ day-20: stage: build script: - cd day20; cargo run --release ./input + +day-21: + stage: build + script: + - cd day21; cargo run --release ./input diff --git a/day21/Cargo.toml b/day21/Cargo.toml new file mode 100644 index 0000000..ea8752e --- /dev/null +++ b/day21/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "day21" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/day21/input b/day21/input new file mode 100644 index 0000000..20724a0 --- /dev/null +++ b/day21/input @@ -0,0 +1,2 @@ +Player 1 starting position: 1 +Player 2 starting position: 2 diff --git a/day21/src/main.rs b/day21/src/main.rs new file mode 100644 index 0000000..dca58e2 --- /dev/null +++ b/day21/src/main.rs @@ -0,0 +1,100 @@ +use std::{fs, env, collections::HashMap}; + +struct Dice { + n: u32, + i: u32 +} + +impl Dice { + fn new() -> Dice { Dice { n: 0, i: 0 } } + + fn get_nb_draw(&self) -> u32 { return self.n; } + + fn get_next(&mut self) -> u32 { + self.n += 1; + self.i = (self.i + 1) % 100; + if self.i == 0 { self.i = 100; } + return self.i; + } +} + +fn read_input(path: &str) -> String { + return fs::read_to_string(path).expect("Cannot read file."); +} + +fn parse_input(s: &str) -> (u8, u8) { + let p = s.lines() + .map(|l| l.split_once(": ").unwrap().1.parse::().unwrap()) + .collect::>(); + return (p[0], p[1]); +} + +fn play_classic(mut v: (u8, u8)) -> (u32, u32) { + let mut d = Dice::new(); + let mut s = (0, 0); + let mut p = true; + while s.0 < 1000 && s.1 < 1000 { + let a = d.get_next() + d.get_next() + d.get_next(); + let mut x = (if p { v.0 } else { v.1 } as u32 + a) % 10; + if x == 0 { x = 10; } + if p { + v.0 = x as u8; + s.0 += x; + if s.0 >= 1000 { return (d.get_nb_draw(), s.1); } + } else { + v.1 = x as u8; + s.1 += x; + if s.1 >= 1000 { return (d.get_nb_draw(), s.0); } + } + p = !p; + } + return (d.get_nb_draw(), std::cmp::min(s.0, s.1)); +} + +fn play_quantum(v: (u8, u8), s: (u8, u8), p: bool, c: &mut HashMap<((u8, u8), (u8, u8), bool), (u128, u128)>) { + if s.0 >= 21 { + c.insert((v, s, p), (1, 0)); + return; + } + if s.1 >= 21 { + c.insert((v, s, p), (0, 1)); + return; + } + for i in 1..=3 { + for j in 1..=3 { + for k in 1..=3 { + let mut a = v; + let mut b = s; + if p { + a.0 = (a.0 + i + j + k) % 10; + if a.0 == 0 { a.0 = 10; } + b.0 += a.0; + } else { + a.1 = (a.1 + i + j + k) % 10; + if a.1 == 0 { a.1 = 10; } + b.1 += a.1; + } + if !c.contains_key(&(a, b, !p)) { play_quantum(a, b, !p, c); } + let r = *c.get(&(a, b, !p)).unwrap(); + let x = *c.get(&(v, s, p)).unwrap_or(&(0, 0)); + c.insert((v, s, p), (r.0 + x.0, r.1 + x.1)); + } + } + } +} + +fn main() { + let args: Vec = env::args().collect(); + for arg in args.iter().skip(1) { + let input = read_input(&arg); + let vec_in = parse_input(&input); + let c = play_classic(vec_in); + let mut w = HashMap::new(); + play_quantum(vec_in, (0, 0), true, &mut w); + let w = w.get(&(vec_in, (0, 0), true)).unwrap(); + println!("[{}]", &arg); + println!("\t[Part 1] => Answer is '{}'.", c.0 * c.1); + println!("\t[Part 2] => Answer is '{}'.", std::cmp::max(w.0, w.1)); + } +} +