2021: day21: part 1
This commit is contained in:
parent
5ffa2012be
commit
c92553fa40
2
aoc2021/input/day21.txt
Normal file
2
aoc2021/input/day21.txt
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
Player 1 starting position: 4
|
||||||
|
Player 2 starting position: 2
|
2
aoc2021/input/day21_provided.txt
Normal file
2
aoc2021/input/day21_provided.txt
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
Player 1 starting position: 4
|
||||||
|
Player 2 starting position: 8
|
109
aoc2021/src/day21.rs
Normal file
109
aoc2021/src/day21.rs
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
use std::fmt::Write;
|
||||||
|
use std::iter;
|
||||||
|
use std::ops::RangeInclusive;
|
||||||
|
|
||||||
|
use anyhow::{Context, Result};
|
||||||
|
|
||||||
|
const INPUT: &str = include_str!("../input/day21.txt");
|
||||||
|
|
||||||
|
pub fn run() -> Result<String> {
|
||||||
|
let mut res = String::with_capacity(128);
|
||||||
|
|
||||||
|
writeln!(res, "part 1: {}", part1(INPUT)?)?;
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part1(input: &str) -> Result<usize> {
|
||||||
|
let mut lines = input.lines();
|
||||||
|
let mut player1_pos: PlayerPos = lines
|
||||||
|
.next()
|
||||||
|
.and_then(|line| line.trim().strip_prefix("Player 1 starting position: "))
|
||||||
|
.and_then(|pos| pos.parse().ok())
|
||||||
|
.map(PlayerPos::new)
|
||||||
|
.context("couldn't find player 1 pos")?;
|
||||||
|
let mut player2_pos: PlayerPos = lines
|
||||||
|
.next()
|
||||||
|
.and_then(|line| line.trim().strip_prefix("Player 2 starting position: "))
|
||||||
|
.and_then(|pos| pos.parse().ok())
|
||||||
|
.map(PlayerPos::new)
|
||||||
|
.context("couldn't find player 2 pos")?;
|
||||||
|
|
||||||
|
let mut player1_score = 0;
|
||||||
|
let mut player2_score = 0;
|
||||||
|
let mut dice = DeterministicDice::new();
|
||||||
|
|
||||||
|
while player2_score < 1000 {
|
||||||
|
let mv = dice.next_3_sum();
|
||||||
|
|
||||||
|
player1_pos.advance_by(mv);
|
||||||
|
player1_score += player1_pos.pos();
|
||||||
|
|
||||||
|
std::mem::swap(&mut player1_pos, &mut player2_pos);
|
||||||
|
std::mem::swap(&mut player1_score, &mut player2_score);
|
||||||
|
}
|
||||||
|
|
||||||
|
let loser_score = player1_score;
|
||||||
|
|
||||||
|
Ok(loser_score * dice.rolls())
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PlayerPos(usize);
|
||||||
|
|
||||||
|
impl PlayerPos {
|
||||||
|
fn new(pos: usize) -> Self {
|
||||||
|
debug_assert!((1..=10).contains(&pos));
|
||||||
|
|
||||||
|
// represented from 0 to 9 for modulo ease of use
|
||||||
|
Self(pos - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn advance_by(&mut self, mv: usize) {
|
||||||
|
self.0 = (self.0 + mv) % 10
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pos(&self) -> usize {
|
||||||
|
self.0 + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DeterministicDice {
|
||||||
|
iter: iter::Cycle<RangeInclusive<usize>>,
|
||||||
|
rolls: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DeterministicDice {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
iter: (1..=100).cycle(),
|
||||||
|
rolls: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_3_sum(&mut self) -> usize {
|
||||||
|
self.rolls += 3;
|
||||||
|
|
||||||
|
self.iter.next().unwrap() + self.iter.next().unwrap() + self.iter.next().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rolls(&self) -> usize {
|
||||||
|
self.rolls
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const PROVIDED: &str = include_str!("../input/day21_provided.txt");
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part1_provided() {
|
||||||
|
assert_eq!(part1(PROVIDED).unwrap(), 739785);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part1_real() {
|
||||||
|
assert_eq!(part1(INPUT).unwrap(), 908595);
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,3 +17,5 @@ pub mod day14;
|
||||||
pub mod day15;
|
pub mod day15;
|
||||||
pub mod day16;
|
pub mod day16;
|
||||||
pub mod day17;
|
pub mod day17;
|
||||||
|
|
||||||
|
pub mod day21;
|
||||||
|
|
|
@ -20,6 +20,8 @@ use aoc2021::day15;
|
||||||
use aoc2021::day16;
|
use aoc2021::day16;
|
||||||
use aoc2021::day17;
|
use aoc2021::day17;
|
||||||
|
|
||||||
|
use aoc2021::day21;
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
let days: &[DayFunc] = &[
|
let days: &[DayFunc] = &[
|
||||||
day01::run,
|
day01::run,
|
||||||
|
@ -39,6 +41,7 @@ fn main() -> Result<()> {
|
||||||
day15::run,
|
day15::run,
|
||||||
day16::run,
|
day16::run,
|
||||||
day17::run,
|
day17::run,
|
||||||
|
day21::run,
|
||||||
];
|
];
|
||||||
|
|
||||||
aoc::run(days)
|
aoc::run(days)
|
||||||
|
|
Loading…
Reference in a new issue