From b733d05353bd38afa0b00e6d9115901d4820b9fd Mon Sep 17 00:00:00 2001 From: kageru Date: Wed, 22 Dec 2021 00:41:17 +0100 Subject: [PATCH] 21/2 optimizations --- 2021/src/bin/day21.rs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/2021/src/bin/day21.rs b/2021/src/bin/day21.rs index a310853..cb8b90c 100644 --- a/2021/src/bin/day21.rs +++ b/2021/src/bin/day21.rs @@ -10,8 +10,8 @@ fn part1((p1, p2): Parsed) -> usize { .cycle() .skip(1) .step_by(3) - .scan(GameState { odd_round: false, scores: [(p1, 0), (p2, 0)] }, |mut game, die| { - advance_game(&mut game, die * 3); + .scan(GameState { odd_round: false, scores: [(p1, 0), (p2, 0)] }, |game, die| { + advance_game(game, die * 3); Some((game.scores[0].1, game.scores[1].1)) }) .zip(1..) @@ -31,23 +31,27 @@ struct GameState { const POSSIBLE_ROLLS: [(u16, usize); 7] = [(6, 7), (5, 6), (7, 6), (4, 3), (8, 3), (3, 1), (9, 1)]; fn part2((p1, p2): Parsed) -> usize { - let start = GameState { odd_round: false, scores: [(p1, 0), (p2, 0)] }; let mut games = FnvHashMap::default(); - games.insert(start, 1); + games.insert(GameState { odd_round: false, scores: [(p1, 0), (p2, 0)] }, 1); let mut wins = [0, 0]; + let mut storage = Vec::with_capacity(100_000); while !games.is_empty() { - for k in games.clone().keys() { - let (start, count) = games.remove_entry(k).unwrap(); + for (start, count) in games.drain() { for &(die, count2) in &POSSIBLE_ROLLS { let mut new_state = start; advance_game(&mut new_state, die); if new_state.scores[start.odd_round as usize].1 >= 21 { wins[new_state.odd_round as usize] += count * count2; } else { - *games.entry(new_state).or_insert(0) += count * count2; + storage.push((new_state, count * count2)); } } } + // Of all the versions I’ve tried, temporarily storing in a vector and then sorting back + // into the map was by far the fastest. + for (k, v) in storage.drain(..) { + *games.entry(k).or_insert(0) += v; + } } wins[0].max(wins[1]) }