I've stumbled over a problem when using BTreeMaps; They don't seem to update while the program is running. Here an example:
fn monke_do_monke_bisnis(mut monkes: BTreeMap<i32, Monke>) -> BTreeMap<i32, Monke> {
for mut monke in monkes.to_owned() {
println!("Monkey: {:?}", monke.0);
let mut new_prio: f32 = 0.0;
for i in monke.1.inventory.to_owned() {
println!("Inventory length: {:?}", monke.1.inventory.len());
println!("Inspected item: {:?}", i);
let last = parse_last(i, monke.1.operation.last.clone());
match monke.1.operation.operand {
'*' => {
new_prio = ((i * last)) as f32
}
'/' => {
new_prio = ((i / last)) as f32
}
' ' => {
new_prio = ((i last)) as f32
}
'-' => {
new_prio = ((i - last)) as f32
}
_ => panic!("need op bruv"),
}
println!("New worry level of item: {:?}", new_prio);
new_prio /= 3.0;
new_prio = new_prio.floor();
println!("New worry level of item / 3: {:?}", new_prio);
if (new_prio as i32) % monke.1.test == 0 {
monkes.entry(monke.1.true_outcome).and_modify(|monk| {
monk.inventory.push(new_prio as i32);
println!("TRUE: Thrown to: {:?}", monk.id);
println!("Inventory of {:?}: {:?}", monk.id, monk.inventory);
});
} else {
monkes.entry(monke.1.false_outcome).and_modify(|monk| {
monk.inventory.push(new_prio as i32);
println!("FALSE: Thrown to: {:?}", monk.id);
println!("Inventory of {:?}: {:?}", monk.id, monk.inventory);
});
}
//remove item from original monke
monkes
.entry(monke.1.id)
.and_modify(|monk| {
monk.inventory.remove(0);
monk.inspect_count = 1;
});
}
}
return monkes;
}
Here are the structs:
#[derive(Default, Debug, Clone)]
struct Monke {
id: i32,
inventory: Vec<i32>,
operation: Operation,
test: i32,
true_outcome: i32,
false_outcome: i32,
inspect_count: i32,
}
#[derive(Default, Debug, Clone)]
struct Operation {
operand: char,
last: String,
}
And here's the console output when letting it run:
Monke { id: 0, inventory: [20, 23, 27, 26], operation: Operation { operand: '*', last: "19" }, test: 23, true_outcome: 2, false_outcome: 3, inspect_count: 2 }
Monke { id: 1, inventory: [25], operation: Operation { operand: ' ', last: "6" }, test: 19, true_outcome: 2, false_outcome: 0, inspect_count: 4 }
Monke { id: 2, inventory: [], operation: Operation { operand: '*', last: "old" }, test: 13, true_outcome: 1, false_outcome: 3, inspect_count: 3 }
Monke { id: 3, inventory: [500, 620, 1200, 3136], operation: Operation { operand: ' ', last: "3" }, test: 17, true_outcome: 0, false_outcome: 1, inspect_count: 1 }
And here's whats supposed to be the output:
Monke { id: 0, inventory: [20, 23, 27, 26], operation: Operation { operand: '*', last: "19" }, test: 23, true_outcome: 2, false_outcome: 3, inspect_count: 2 }
Monke { id: 1, inventory: [2080, 25, 167, 207, 401, 1046], operation: Operation { operand: ' ', last: "6" }, test: 19, true_outcome: 2, false_outcome: 0, inspect_count: 4 }
Monke { id: 2, inventory: [], operation: Operation { operand: '*', last: "old" }, test: 13, true_outcome: 1, false_outcome: 3, inspect_count: 3 }
Monke { id: 3, inventory: [], operation: Operation { operand: ' ', last: "3" }, test: 17, true_outcome: 0, false_outcome: 1, inspect_count: 1 }
It seems that the BTreeMap i'm using is not being updated correctly, since the logic is correct. What may be the cause for that?
CodePudding user response:
You are cloning monkes
at the beginning of your function (via to_owned()
), and iterating over that object instead of your original. In future iterations of the loop, when you want Monkey 1, you are still reading its original value from your cloned map. The entry pattern you're using may be difficult to make work since you need to modify multiple items from the collection at the same time, but I don't know the best solution to go with the map you have (I would use a Vec
, since the indexes can correspond to the IDs).