day11: performance
This commit is contained in:
		
							
								
								
									
										46
									
								
								11/Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										46
									
								
								11/Cargo.lock
									
									
									
										generated
									
									
									
								
							@@ -2,11 +2,37 @@
 | 
				
			|||||||
# It is not intended for manual editing.
 | 
					# It is not intended for manual editing.
 | 
				
			||||||
version = 3
 | 
					version = 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "crossbeam-deque"
 | 
				
			||||||
 | 
					version = "0.8.5"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "crossbeam-epoch",
 | 
				
			||||||
 | 
					 "crossbeam-utils",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "crossbeam-epoch"
 | 
				
			||||||
 | 
					version = "0.9.18"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "crossbeam-utils",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "crossbeam-utils"
 | 
				
			||||||
 | 
					version = "0.8.20"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "day11"
 | 
					name = "day11"
 | 
				
			||||||
version = "0.1.0"
 | 
					version = "0.1.0"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "itertools",
 | 
					 "itertools",
 | 
				
			||||||
 | 
					 "rayon",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
@@ -23,3 +49,23 @@ checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
 | 
				
			|||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "either",
 | 
					 "either",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "rayon"
 | 
				
			||||||
 | 
					version = "1.10.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "either",
 | 
				
			||||||
 | 
					 "rayon-core",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "rayon-core"
 | 
				
			||||||
 | 
					version = "1.12.1"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "crossbeam-deque",
 | 
				
			||||||
 | 
					 "crossbeam-utils",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,3 +5,4 @@ edition = "2021"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
[dependencies]
 | 
					[dependencies]
 | 
				
			||||||
itertools = "0.13.0"
 | 
					itertools = "0.13.0"
 | 
				
			||||||
 | 
					rayon = "1.10.0"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
use std::collections::HashMap;
 | 
					use std::collections::HashMap;
 | 
				
			||||||
use std::fs::File;
 | 
					use std::fs::File;
 | 
				
			||||||
use std::io::{BufRead, BufReader, Lines};
 | 
					use std::io::{BufRead, BufReader, Lines};
 | 
				
			||||||
 | 
					use std::iter::repeat;
 | 
				
			||||||
use std::time::{Duration, Instant};
 | 
					use std::time::{Duration, Instant};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use itertools::Itertools;
 | 
					use itertools::Itertools;
 | 
				
			||||||
@@ -42,46 +43,67 @@ struct Stone {
 | 
				
			|||||||
    value: u64,
 | 
					    value: u64,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum BlinkResult {
 | 
				
			||||||
 | 
					    One(Stone),
 | 
				
			||||||
 | 
					    Two(Stone, Stone),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Stone {
 | 
					impl Stone {
 | 
				
			||||||
    fn blink_once(self) -> Vec<Stone> {
 | 
					    fn blink_once(self) -> BlinkResult {
 | 
				
			||||||
        let n_digits = if self.value == 0 { 1 } else { self.value.ilog10() + 1 };
 | 
					        let n_digits = if self.value == 0 { 1 } else { self.value.ilog10() + 1 };
 | 
				
			||||||
        if self.value == 0 {
 | 
					        if self.value == 0 {
 | 
				
			||||||
            vec![Stone { value: 1 }]
 | 
					            BlinkResult::One(Stone { value: 1 })
 | 
				
			||||||
        } else if n_digits % 2 == 0 {
 | 
					        } else if n_digits % 2 == 0 {
 | 
				
			||||||
            let parts = (
 | 
					            let parts = (
 | 
				
			||||||
                self.value / 10u64.pow(n_digits / 2),
 | 
					                self.value / 10u64.pow(n_digits / 2),
 | 
				
			||||||
                self.value % 10u64.pow(n_digits / 2),
 | 
					                self.value % 10u64.pow(n_digits / 2),
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
            vec![Stone { value: parts.0 }, Stone { value: parts.1 }]
 | 
					            BlinkResult::Two(Stone { value: parts.0 }, Stone { value: parts.1 })
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            vec![Stone {
 | 
					            BlinkResult::One(Stone {
 | 
				
			||||||
                value: self.value * 2024,
 | 
					                value: self.value * 2024,
 | 
				
			||||||
            }]
 | 
					            })
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    fn blink(self, times: usize) -> Vec<Stone> {
 | 
					    // #[allow(dead_code)]
 | 
				
			||||||
        let mut stones = vec![self];
 | 
					    // fn blink(self, times: usize) -> Vec<Stone> {
 | 
				
			||||||
        for _ in 0..times {
 | 
					    //     // Used in submitted part 1 solution
 | 
				
			||||||
            stones = stones.iter().flat_map(|stone| stone.blink_once()).collect();
 | 
					    //     let mut stones = vec![self];
 | 
				
			||||||
        }
 | 
					    //     for _ in 0..times {
 | 
				
			||||||
        stones
 | 
					    //         stones = stones.iter().flat_map(|stone| stone.blink_once()).collect();
 | 
				
			||||||
    }
 | 
					    //     }
 | 
				
			||||||
 | 
					    //     stones
 | 
				
			||||||
 | 
					    // }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn count_blinks(stone: Stone, blinks: u64, cache: &mut HashMap<(u64, Stone), u64>) -> u64 {
 | 
					fn count_blinks(stone: Stone, blink: usize, cache: &mut Vec<HashMap<Stone, u64>>) -> u64 {
 | 
				
			||||||
    if cache.contains_key(&(blinks, stone)) {
 | 
					    if cache[blink].contains_key(&stone) {
 | 
				
			||||||
        return cache[&(blinks, stone)];
 | 
					        return cache[blink][&stone];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    let stones = stone.blink_once();
 | 
					    let stones = stone.blink_once();
 | 
				
			||||||
    let result = if blinks == 1 {
 | 
					    let result = if blink == 0 {
 | 
				
			||||||
        stones.len() as u64
 | 
					        match stones {
 | 
				
			||||||
 | 
					            BlinkResult::One(_) => 1,
 | 
				
			||||||
 | 
					            BlinkResult::Two(_, _) => 2,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        stones.iter().map(|s| count_blinks(*s, blinks - 1, cache)).sum()
 | 
					        match stones {
 | 
				
			||||||
 | 
					            BlinkResult::One(s) => count_blinks(s, blink - 1, cache),
 | 
				
			||||||
 | 
					            BlinkResult::Two(s1, s2) => count_blinks(s1, blink - 1, cache) + count_blinks(s2, blink - 1, cache),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    cache.insert((blinks, stone), result);
 | 
					    cache[blink].insert(stone, result);
 | 
				
			||||||
    result
 | 
					    result
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn blink_stones(stones: &[Stone], blinks: usize) -> u64 {
 | 
				
			||||||
 | 
					    let mut cache = Vec::from_iter(repeat(HashMap::new()).take(blinks));
 | 
				
			||||||
 | 
					    stones
 | 
				
			||||||
 | 
					        .iter()
 | 
				
			||||||
 | 
					        .map(|stone| count_blinks(*stone, blinks - 1, &mut cache))
 | 
				
			||||||
 | 
					        .sum()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// PROBLEM 1 solution
 | 
					// PROBLEM 1 solution
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn problem1<T: BufRead>(mut input: Lines<T>) -> u64 {
 | 
					fn problem1<T: BufRead>(mut input: Lines<T>) -> u64 {
 | 
				
			||||||
@@ -94,7 +116,7 @@ fn problem1<T: BufRead>(mut input: Lines<T>) -> u64 {
 | 
				
			|||||||
            value: v.parse().unwrap(),
 | 
					            value: v.parse().unwrap(),
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
        .collect_vec();
 | 
					        .collect_vec();
 | 
				
			||||||
    stones.iter().flat_map(|stone| stone.blink(25)).count() as u64
 | 
					    blink_stones(&stones, 25)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// PROBLEM 2 solution
 | 
					// PROBLEM 2 solution
 | 
				
			||||||
@@ -108,8 +130,7 @@ fn problem2<T: BufRead>(mut input: Lines<T>) -> u64 {
 | 
				
			|||||||
            value: v.parse().unwrap(),
 | 
					            value: v.parse().unwrap(),
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
        .collect_vec();
 | 
					        .collect_vec();
 | 
				
			||||||
    let mut cache = HashMap::new();
 | 
					    blink_stones(&stones, 75)
 | 
				
			||||||
    stones.iter().map(|s| count_blinks(*s, 75, &mut cache)).sum()
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[cfg(test)]
 | 
					#[cfg(test)]
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user