tangled
alpha
login
or
join now
jonas.tngl.sh
/
advent-of-code
0
fork
atom
Advent of Code solutions in Rust
0
fork
atom
overview
issues
pulls
pipelines
feat: part 1 of day 22 of AoC 2020
jonas.tngl.sh
2 months ago
e4a71050
efb38cd8
1/1
rust.yml
success
4m 36s
+105
-2
2 changed files
expand all
collapse all
unified
split
aoc_2020
src
day22.rs
main.rs
+103
aoc_2020/src/day22.rs
···
1
1
+
use std::collections::VecDeque;
2
2
+
3
3
+
use anyhow::Context as _;
4
4
+
use anyhow::bail;
5
5
+
use aoc_companion::prelude::*;
6
6
+
use itertools::Itertools as _;
7
7
+
8
8
+
pub(crate) struct Door {
9
9
+
decks: [Vec<u64>; 2],
10
10
+
}
11
11
+
12
12
+
impl<'input> Solution<'input> for Door {
13
13
+
fn parse(input: &'input str) -> Result<Self> {
14
14
+
let Some((player1, player2)) = input.split_once("\n\n") else {
15
15
+
bail!("missing empty line between player decks");
16
16
+
};
17
17
+
let Some(player1) = player1.strip_prefix("Player 1:\n") else {
18
18
+
bail!("missing introducer of player 1's deck");
19
19
+
};
20
20
+
let Some(player2) = player2.strip_prefix("Player 2:\n") else {
21
21
+
bail!("missing introducer of player 2's deck");
22
22
+
};
23
23
+
aoc_utils::array::try_map([player1, player2], |deck| {
24
24
+
deck.lines()
25
25
+
.map(str::parse)
26
26
+
.try_collect()
27
27
+
.with_context(|| "failed to parse card value")
28
28
+
})
29
29
+
.map(|decks| Door { decks })
30
30
+
}
31
31
+
32
32
+
fn part1(&self) -> u64 {
33
33
+
score(&play_combat(
34
34
+
self.decks.each_ref().map(|deck| deck.clone().into()),
35
35
+
))
36
36
+
}
37
37
+
}
38
38
+
39
39
+
fn play_combat(mut decks: [VecDeque<u64>; 2]) -> Vec<u64> {
40
40
+
while let Ok(top_cards) =
41
41
+
aoc_utils::array::try_map(decks.each_mut(), |deck| deck.front().copied().ok_or(()))
42
42
+
{
43
43
+
for deck in &mut decks {
44
44
+
deck.pop_front();
45
45
+
}
46
46
+
match (top_cards, &mut decks) {
47
47
+
([high, low], [winner, _]) | ([low, high], [_, winner]) if high > low => {
48
48
+
winner.extend([high, low]);
49
49
+
}
50
50
+
_ => unreachable!("same card value must not occur twice"),
51
51
+
}
52
52
+
}
53
53
+
54
54
+
let winner = decks.into_iter().max().unwrap();
55
55
+
winner.into()
56
56
+
}
57
57
+
58
58
+
fn score(deck: &[u64]) -> u64 {
59
59
+
deck.iter()
60
60
+
.rev()
61
61
+
.enumerate()
62
62
+
.map(|(i, card)| (i as u64 + 1) * card)
63
63
+
.sum()
64
64
+
}
65
65
+
66
66
+
#[cfg(test)]
67
67
+
mod tests {
68
68
+
use super::*;
69
69
+
70
70
+
const EXAMPLE_INPUT: &str = "\
71
71
+
Player 1:
72
72
+
9
73
73
+
2
74
74
+
6
75
75
+
3
76
76
+
1
77
77
+
78
78
+
Player 2:
79
79
+
5
80
80
+
8
81
81
+
4
82
82
+
7
83
83
+
10";
84
84
+
85
85
+
const EXAMPLE_DECKS: [[u64; 5]; 2] = [[9, 2, 6, 3, 1], [5, 8, 4, 7, 10]];
86
86
+
const WINNING_DECK: [u64; 10] = [3, 2, 10, 6, 8, 5, 9, 4, 7, 1];
87
87
+
88
88
+
#[test]
89
89
+
fn parse_example_input() {
90
90
+
let Door { decks } = Door::parse(EXAMPLE_INPUT).unwrap();
91
91
+
assert_eq!(decks, EXAMPLE_DECKS);
92
92
+
}
93
93
+
94
94
+
#[test]
95
95
+
fn winning_deck_in_example() {
96
96
+
assert_eq!(play_combat(EXAMPLE_DECKS.map(VecDeque::from)), WINNING_DECK);
97
97
+
}
98
98
+
99
99
+
#[test]
100
100
+
fn winning_score() {
101
101
+
assert_eq!(score(&WINNING_DECK), 306);
102
102
+
}
103
103
+
}
+2
-2
aoc_2020/src/main.rs
···
21
21
mod day19;
22
22
mod day20;
23
23
mod day21;
24
24
-
// mod day22;
24
24
+
mod day22;
25
25
// mod day23;
26
26
// mod day24;
27
27
// mod day25;
···
52
52
door!(2020-12-19 ~> day19),
53
53
door!(2020-12-20 ~> day20),
54
54
door!(2020-12-21 ~> day21),
55
55
-
// door!(2020-12-22 ~> day22),
55
55
+
door!(2020-12-22 ~> day22),
56
56
// door!(2020-12-23 ~> day23),
57
57
// door!(2020-12-24 ~> day24),
58
58
// door!(2020-12-25 ~> day25),