Search code examples
arraysloopsrusthashmapbtreemap

Rust - BTreeMap not updating vector in value correctly


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?


Solution

  • 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).