2021: day21: part 1

This commit is contained in:
Antoine Martin 2021-12-21 14:07:22 +01:00
parent 5ffa2012be
commit c92553fa40
5 changed files with 118 additions and 0 deletions

2
aoc2021/input/day21.txt Normal file
View file

@ -0,0 +1,2 @@
Player 1 starting position: 4
Player 2 starting position: 2

View file

@ -0,0 +1,2 @@
Player 1 starting position: 4
Player 2 starting position: 8

109
aoc2021/src/day21.rs Normal file
View 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);
}
}

View file

@ -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;

View file

@ -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)