use std::env::args; use std::fs::File; use std::io::BufRead; use std::io::BufReader; fn get_data() -> (u8, u8) { let path = args().nth(1).unwrap(); let file = File::open(path).unwrap(); let mut state = 0; let mut player1 = 0; let mut player2 = 0; for line in BufReader::new(file).lines() { match state { 0 => { player1 = line.unwrap()[28..].parse::().unwrap(); state = 1; }, 1 => { player2 = line.unwrap()[28..].parse::().unwrap(); state = 2; }, _ => unreachable!(), } } return (player1 - 1, player2 - 1); } fn index(pos1: u8, pos2: u8, score1: u8, score2: u8) -> usize { return usize::from(pos1) + usize::from(pos2) * 10 + usize::from(score1) * 10 * 10 + usize::from(score2) * 10 * 10 * 21; } fn play_dirac(pos1: u8, pos2: u8, score1: u8, score2: u8, mut cache: &mut [Option<(u64, u64)>; 10 * 10 * 21 * 21]) -> (u64, u64) { // https://neddit.ce9e.org/r/adventofcode/comments/rl6p8y/2021_day_21_solutions/hpeokw2/ if score2 >= 21 { return (0, 1); } let i = index(pos1, pos2, score1, score2); match cache[i] { None => {}, Some(v) => return v, } let mut wins1 = 0; let mut wins2 = 0; for a in [1, 2, 3].iter() { for b in [1, 2, 3].iter() { for c in [1, 2, 3].iter() { let pos = (pos1 + a + b + c) % 10; let score = score1 + (pos + 1); // switch players let (w2, w1) = play_dirac(pos2, pos, score2, score, &mut cache); wins1 += w1; wins2 += w2; } } } cache[i] = Some((wins1, wins2)); return (wins1, wins2); } fn main() { let (pos1, pos2) = get_data(); let mut cache = [None; 10 * 10 * 21 * 21]; let (wins1, wins2) = play_dirac(pos1, pos2, 0, 0, &mut cache); if wins1 > wins2 { println!("{}", wins1); } else { println!("{}", wins2); } }