feat: solve day 21 part 1 & 2
This commit is contained in:
parent
4db9c115f6
commit
c59575aa99
2
input/21.txt
Normal file
2
input/21.txt
Normal file
@ -0,0 +1,2 @@
|
||||
Player 1 starting position: 7
|
||||
Player 2 starting position: 8
|
97
src/day21.rs
Normal file
97
src/day21.rs
Normal file
@ -0,0 +1,97 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
|
||||
pub fn parse_input(input: &str) -> (u8, u8) {
|
||||
let players: Vec<u8> = input.lines()
|
||||
.map(|l| l.split_once(": ").unwrap().1.parse().unwrap())
|
||||
.collect();
|
||||
return (players[0], players[1]);
|
||||
}
|
||||
|
||||
pub fn part1(starting_positions: &(u8, u8)) -> u32 {
|
||||
let mut player1_position = starting_positions.0 as u32;
|
||||
let mut player2_position = starting_positions.1 as u32;
|
||||
let mut player1_score: u32 = 0;
|
||||
let mut player2_score: u32 = 0;
|
||||
let mut rolled_count = 0;
|
||||
|
||||
let mut is_player1_turn = true;
|
||||
|
||||
while player1_score < 1000 && player2_score < 1000 {
|
||||
let position;
|
||||
let score;
|
||||
if is_player1_turn {
|
||||
position = &mut player1_position;
|
||||
score = &mut player1_score;
|
||||
} else {
|
||||
position = &mut player2_position;
|
||||
score = &mut player2_score;
|
||||
}
|
||||
|
||||
*position += (rolled_count + 1 - 1) % 100 + 1;
|
||||
*position += (rolled_count + 2 - 1) % 100 + 1;
|
||||
*position += (rolled_count + 3 - 1) % 100 + 1;
|
||||
|
||||
*position = (*position - 1) % 10 + 1;
|
||||
*score += *position as u32;
|
||||
|
||||
rolled_count += 3;
|
||||
is_player1_turn = !is_player1_turn;
|
||||
}
|
||||
|
||||
player1_score.min(player2_score) * rolled_count as u32
|
||||
}
|
||||
|
||||
fn get_wins_amount(starting_pos1: u32, starting_pos2: u32, starting_score1: u32, starting_score2: u32, memo: &mut HashMap<(u32, u32, u32, u32), (u64, u64)>) -> (u64, u64) {
|
||||
let memo_key = (starting_pos1, starting_pos2, starting_score1, starting_score2);
|
||||
if memo.contains_key(&memo_key) {
|
||||
return *memo.get(&memo_key).unwrap()
|
||||
}
|
||||
let mut total_wins1 = 0;
|
||||
let mut total_wins2 = 0;
|
||||
|
||||
for dice1 in 1..=3 {
|
||||
for dice2 in 1..=3 {
|
||||
for dice3 in 1..=3 {
|
||||
let pos1 = (starting_pos1 + dice1 + dice2 + dice3 - 1) % 10 + 1;
|
||||
let score1 = starting_score1 + pos1;
|
||||
if score1 >= 21 {
|
||||
total_wins1 += 1
|
||||
} else {
|
||||
let (wins2, wins1) = get_wins_amount(starting_pos2, pos1, starting_score2, score1, memo);
|
||||
total_wins1 += wins1;
|
||||
total_wins2 += wins2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memo.insert(memo_key, (total_wins1, total_wins2));
|
||||
|
||||
(total_wins1, total_wins2)
|
||||
}
|
||||
|
||||
pub fn part2(positions: &(u8, u8)) -> u64 {
|
||||
let mut memo = HashMap::new();
|
||||
let (wins1, wins2) = get_wins_amount(positions.0 as u32, positions.1 as u32, 0, 0, &mut memo);
|
||||
wins1.max(wins2)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn part1_example() {
|
||||
let input = (4, 8);
|
||||
let result = part1(&input);
|
||||
assert_eq!(result, 739785);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part2_example() {
|
||||
let input = (4, 8);
|
||||
let result = part2(&input);
|
||||
assert_eq!(result, 444356092776315);
|
||||
}
|
||||
}
|
@ -18,6 +18,7 @@ mod day17;
|
||||
mod day18;
|
||||
mod day19;
|
||||
mod day20;
|
||||
mod day21;
|
||||
|
||||
use std::{env, process};
|
||||
use std::fs::File;
|
||||
@ -74,6 +75,8 @@ fn run(day: i32, part: i32, input_filename: &str) {
|
||||
"19.2" => println!("{}", day19::part2(&day19::parse_input(&contents))),
|
||||
"20.1" => println!("{}", day20::part1(&day20::parse_input(&contents))),
|
||||
"20.2" => println!("{}", day20::part2(&day20::parse_input(&contents))),
|
||||
"21.1" => println!("{}", day21::part1(&day21::parse_input(&contents))),
|
||||
"21.2" => println!("{}", day21::part2(&day21::parse_input(&contents))),
|
||||
_ => println!("Day {} part {} not found", day, part)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user