summaryrefslogtreecommitdiff
path: root/2021/day21
diff options
context:
space:
mode:
Diffstat (limited to '2021/day21')
-rw-r--r--2021/day21/Cargo.toml9
-rw-r--r--2021/day21/resources/input.txt2
-rw-r--r--2021/day21/src/main.rs98
3 files changed, 109 insertions, 0 deletions
diff --git a/2021/day21/Cargo.toml b/2021/day21/Cargo.toml
new file mode 100644
index 0000000..c2bd70c
--- /dev/null
+++ b/2021/day21/Cargo.toml
@@ -0,0 +1,9 @@
1[package]
2name = "day21"
3version = "0.1.0"
4authors = ["Federico Igne <git@federicoigne.com>"]
5edition = "2018"
6
7# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8
9[dependencies]
diff --git a/2021/day21/resources/input.txt b/2021/day21/resources/input.txt
new file mode 100644
index 0000000..085f690
--- /dev/null
+++ b/2021/day21/resources/input.txt
@@ -0,0 +1,2 @@
1Player 1 starting position: 4
2Player 2 starting position: 10
diff --git a/2021/day21/src/main.rs b/2021/day21/src/main.rs
new file mode 100644
index 0000000..55e70f6
--- /dev/null
+++ b/2021/day21/src/main.rs
@@ -0,0 +1,98 @@
1use std::fs;
2use std::path::Path;
3use std::collections::HashMap;
4
5const ROLLS: [(u64,u64);7] = [(3,1),(4,3),(5,6),(6,7),(7,6),(8,3),(9,1)];
6
7struct Player {
8 pos: u32,
9 score: u32
10}
11
12struct QPlayer {
13 plays: HashMap<(u8,u64,u64),u64>,
14 wins: HashMap<u8,u64>,
15 turn: u8
16}
17
18impl QPlayer {
19 fn new(pos: u64) -> QPlayer {
20 let mut plays = HashMap::new();
21 plays.insert((0,pos,0), 1);
22 QPlayer { plays, wins: HashMap::new(), turn: 0}
23 }
24
25 /// Return true if any current state advanced
26 fn quantum_roll(&mut self) -> bool {
27 let mut ret = false;
28 // Compute update
29 let mut plays = vec![];
30 let mut wins = vec![];
31 self.plays.iter().for_each(|(&(t,p,s), &n)| {
32 if t == self.turn {
33 if s > 20 {
34 wins.push((t,n));
35 } else {
36 ret = true;
37 for (roll,card) in ROLLS.iter() {
38 let pos = (p + roll) % 10;
39 plays.push((t+1,pos,s+pos+1,n*card));
40 }
41 }
42 }
43 });
44 // Apply update
45 plays.iter().for_each(|&(t,p,s,n)| *self.plays.entry((t,p,s)).or_default() += n);
46 wins.iter().for_each(|&(t,n)| *self.wins.entry(t).or_default() += n);
47 self.turn += 1;
48 ret
49 }
50}
51
52/* AOC21 Day 21: https://adventofcode.com/2021/day/21 */
53fn main() {
54 let input = Path::new("resources").join("input.txt");
55 let content = fs::read_to_string(input).expect("Unable to read input file");
56 println!("Ex1: the result is {}", ex1(&content));
57 println!("Ex2: the result is {}", ex2(&content));
58}
59
60fn parse_input(input: &str) -> Vec<Player> {
61 input.lines().map(|l| {
62 let (_,pos) = l.split_once(": ").expect("Malformed input");
63 Player { pos: pos.parse::<u32>().unwrap() - 1, score: 0 }
64 }).collect()
65}
66
67fn ex1(input: &str) -> u32 {
68 let mut players = parse_input(input);
69 let mut p = players.len()-1;
70 let mut turn = 0;
71 while players[p].score < 1000 {
72 p = (p+1) % players.len();
73 players[p].pos = (players[p].pos + 9*turn + 6) % 10;
74 players[p].score += players[p].pos + 1;
75 turn += 1;
76 }
77 players[(p+1) % players.len()].score * turn * 3
78}
79
80fn ex2(input: &str) -> u64 {
81 let mut p1 = {
82 let (_,pos) = input.lines().nth(0).unwrap().split_once(": ").expect("Malformed input");
83 QPlayer::new(pos.parse::<u64>().unwrap() - 1)
84 };
85 let mut p2 = {
86 let (_,pos) = input.lines().nth(1).unwrap().split_once(": ").expect("Malformed input");
87 QPlayer::new(pos.parse::<u64>().unwrap() - 1)
88 };
89 while p1.quantum_roll() { }
90 while p2.quantum_roll() { }
91 let p1wins = p1.wins.iter().map(|(&t1,&n1)| {
92 p2.plays.iter().filter_map(|(&(t2,_,s2),&n2)| if t1 == t2+1 && s2 < 21 { Some(n1*n2) } else { None }).sum::<u64>()
93 }).sum();
94 let p2wins = p2.wins.iter().map(|(&t2,&n2)|
95 p1.plays.iter().filter_map(|(&(t1,_,s1),&n1)| if t1 == t2 && s1 < 21 { Some(n1*n2) } else { None }).sum::<u64>()
96 ).sum();
97 u64::max(p1wins, p2wins)
98}