Hello!
I'm new to rust, and I'm learning it through Advent of code. Day 6 involves the counting of an exponentially growing number of fish. The fish have a timer that ticks down, and when it's 0 it reverts to 6 and creates a new fish with a timer of 8.
I've come up with a solution that uses a map. However, I was rather stumped by random behavior that appears when a Hashmap is used, but the code works with a BTreeMap. Below is my (bad) code with a BTreeMap (feel free to offer constructive criticism).
use std::{collections::BTreeMap, collections::HashMap, fs};
fn main() {
let filename = "src/data.txt";
let contents = fs::read_to_string(filename).expect("Something went wrong reading the file");
let state: Vec<i64> = contents
.split(",")
.map(|fish| fish.trim().parse().unwrap())
.collect();
// For some reason, Hash map has strange random behaviors and doesn't work?
let mut map: BTreeMap<i64, i64> = BTreeMap::new();
//Create initial hash map based on contents of file
for i in state {
if map.contains_key(&i) {
let old = map.get_mut(&i).unwrap();
*old += 1;
} else {
map.insert(i, 1);
}
}
// Laternfish in the ocean reproduce every 6 days. A new laternfish reproduces after 8 days.
//How many lanternfish are there after 80 and 256 days?
for i in 0..256 {
let mut temp_map: BTreeMap<i64, i64> = BTreeMap::new();
for fish_days in map.keys() {
if *fish_days == 0 {
// If fish has timer of zero days, set back to 6
if temp_map.contains_key(&6) {
let old_6 = temp_map.get_mut(&6).unwrap();
*old_6 = *map.get(&6).unwrap() + *old_6;
} else {
temp_map.insert(6, *map.get(fish_days).unwrap());
}
// Also make a new fish with a timer of 8
if temp_map.contains_key(&8) {
let old_8 = temp_map.get_mut(&8).unwrap();
*old_8 = *map.get(&8).unwrap() + *old_8;
} else {
temp_map.insert(8, *map.get(fish_days).unwrap());
}
} else {
// Insert the fish into the new map with a decremented timer
if temp_map.contains_key(&(*fish_days - 1)) {
let old = temp_map.get_mut(&(fish_days - 1)).unwrap();
*old = *map.get(fish_days).unwrap() + *old;
} else {
temp_map.insert(fish_days - 1, *map.get(fish_days).unwrap());
}
}
}
map = temp_map.clone();
if i == 79 {
println!(
"There are {} Fish after {} days",
map.values().sum::<i64>(),
i + 1
);
}
// println!("Day {}: {}",i+1, rtn)
}
println!(
"There are {} Fish after {} days",
map.values().sum::<i64>(),
256
);
}
where the data.txt is a single line of 3,4,3,1,2
. The expected correct values are 5934 for 80 days and 26984457539 for 256 days. Replacing the BTree map with HashMap results in random results. When debugging, it seems as though value updates will randomly drop or duplicate.
The below snippet from the documentation seems to apply
It is a logic error for a key to be modified in such a way that the key’s hash, as determined by the [
Hash
] trait, or its equality, as determined by the [Eq
] trait, changes while it is in the map. This is normally only possible through [Cell
], [RefCell
] global state, I/O, or unsafe code. The behavior resulting from such a logic error is not specified, but will not result in undefined behavior. This could include panics, incorrect results, aborts, memory leaks, and non-termination.
But I don't see how this would apply, because I'm putting the keys into a new map (unless it does, due to my still poor understanding of pointers). If it does apply, how would I modify my code to decrement the key in the new map without changing the key in the old map?