Skip to content

Commit 419eb3c

Browse files
committed
2018 day 9
1 parent d35815a commit 419eb3c

File tree

2 files changed

+82
-0
lines changed

2 files changed

+82
-0
lines changed

crates/year2018/src/day09.rs

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
use std::collections::VecDeque;
2+
use utils::prelude::*;
3+
4+
/// Simulating a marble game.
5+
#[derive(Clone, Debug)]
6+
pub struct Day09 {
7+
players: u32,
8+
marbles: u32,
9+
}
10+
11+
impl Day09 {
12+
pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
13+
let (players, marbles) = parser::number_range(1..=999)
14+
.with_suffix(" players; last marble is worth ")
15+
.then(parser::number_range(1..=99_999))
16+
.with_suffix(" points")
17+
.parse_complete(input)?;
18+
19+
Ok(Self { players, marbles })
20+
}
21+
22+
#[must_use]
23+
pub fn part1(&self) -> u64 {
24+
Self::max_score(self.players, self.marbles)
25+
}
26+
27+
#[must_use]
28+
pub fn part2(&self) -> u64 {
29+
Self::max_score(self.players, self.marbles * 100)
30+
}
31+
32+
fn max_score(players: u32, marbles: u32) -> u64 {
33+
let mut circle = VecDeque::with_capacity(marbles as usize);
34+
circle.push_front(0u32);
35+
let mut scores = vec![0u64; players as usize];
36+
37+
let batches = marbles / 23;
38+
for base in (0..23 * batches).step_by(23) {
39+
// Equivalent to the following operations, which naively add 23 marbles while keeping
40+
// the current marble at the front of dequeue:
41+
// 22x [push_back(pop_front), push_back(pop_front), push_front(i)]
42+
// 7x [push_front(pop_back)]
43+
// [pop_front]
44+
// By eliminating redundant pushes and pops the total number of operations per batch is
45+
// decreased from 125 to 67.
46+
let front = circle.pop_front().unwrap();
47+
circle.push_back(front);
48+
49+
for i in 1..=18 {
50+
let front = circle.pop_front().unwrap();
51+
circle.push_back(front);
52+
circle.push_back(base + i);
53+
}
54+
55+
let f1 = circle.pop_front().unwrap();
56+
let f2 = circle.pop_front().unwrap();
57+
let f3 = circle.pop_front().unwrap();
58+
let f4 = circle.pop_front().unwrap();
59+
60+
circle.push_front(base + 22);
61+
circle.push_front(f4);
62+
circle.push_front(base + 21);
63+
circle.push_front(f3);
64+
circle.push_front(base + 20);
65+
circle.push_front(f2);
66+
circle.push_front(base + 19);
67+
68+
scores[((base + 23) % players) as usize] += (base as u64 + 23) + (f1 as u64);
69+
}
70+
71+
scores.iter().copied().max().unwrap()
72+
}
73+
}
74+
75+
examples!(Day09 -> (u64, u64) [
76+
{input: "10 players; last marble is worth 1618 points", part1: 8317},
77+
{input: "13 players; last marble is worth 7999 points", part1: 146373},
78+
{input: "17 players; last marble is worth 1104 points", part1: 2764},
79+
{input: "21 players; last marble is worth 6111 points", part1: 54718},
80+
{input: "30 players; last marble is worth 5807 points", part1: 37305},
81+
]);

crates/year2018/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ utils::year!(2018 => year2018, ${
1010
6 => day06::Day06,
1111
7 => day07::Day07,
1212
8 => day08::Day08,
13+
9 => day09::Day09,
1314
});

0 commit comments

Comments
 (0)