diff options
Diffstat (limited to '2021/day21')
-rw-r--r-- | 2021/day21/Cargo.toml | 9 | ||||
-rw-r--r-- | 2021/day21/resources/input.txt | 2 | ||||
-rw-r--r-- | 2021/day21/src/main.rs | 98 |
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] | ||
2 | name = "day21" | ||
3 | version = "0.1.0" | ||
4 | authors = ["Federico Igne <git@federicoigne.com>"] | ||
5 | edition = "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 @@ | |||
1 | Player 1 starting position: 4 | ||
2 | Player 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 @@ | |||
1 | use std::fs; | ||
2 | use std::path::Path; | ||
3 | use std::collections::HashMap; | ||
4 | |||
5 | const ROLLS: [(u64,u64);7] = [(3,1),(4,3),(5,6),(6,7),(7,6),(8,3),(9,1)]; | ||
6 | |||
7 | struct Player { | ||
8 | pos: u32, | ||
9 | score: u32 | ||
10 | } | ||
11 | |||
12 | struct QPlayer { | ||
13 | plays: HashMap<(u8,u64,u64),u64>, | ||
14 | wins: HashMap<u8,u64>, | ||
15 | turn: u8 | ||
16 | } | ||
17 | |||
18 | impl 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 */ | ||
53 | fn 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 | |||
60 | fn 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 | |||
67 | fn 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 | |||
80 | fn 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 | } | ||