Is using `Rc` the "correct" way to mak the compiler happy in this case?

Here are a couple of code snippets showing what I am trying to do.

Context:

struct NeatVsNeat<'a> {
    pub organism_1: &'a mut Organism,
    pub organism_2: &'a mut Organism
}

impl Controller for NeatVsNeat<'_> {
    fn retry_allowed(&mut self) -> bool {
        false
    }

    fn circle_mover(&mut self, gameboard: &GameBoard) -> CellLocation {
        let res = neat_move(&mut self.organism_1.network, gameboard);
        println!("circle AI has selected move: {:?}", res);
        res
    }

    fn cross_mover(&mut self, gameboard: &GameBoard) -> CellLocation {
        let res = neat_move(&mut self.organism_2.network, gameboard);
        println!("cross AI has selected move: {:?}", res);
        res
    }
}

Hopefully you don't need more context to understand the next snippet

let mut rng = rand::thread_rng();
    let mut all_orgs:Vec<Organism> = (1 .. 10).map(|_| Organism::init(&mut rng, 10, 9)).collect();

    for i in 0 .. 10 {
        for j in 0 .. 10 {
            if i != j {
                let o1 = &mut all_orgs[i];
                let o2 = &mut all_orgs[j];
                let ctrl = NeatVsNeat{organism_1: o1, organism_2: o2};
            }
        }
    }

In the above, I want to have each AI compete against each other AI. In doing so, the state of each AI becomes mutated. But the compiler doesn't want me to borrow from all_orgs more than once.

The tricks shown to me here will not work in this case, as far as I can tell.

Is all_orgs: Vec<Rc<Organism>> = ... the best way to satisfy the compiler here?

1 Like

I just found out about split_at_mut so now I am trying this

for i in 0 .. 10 {
        let (left, others) = all_orgs.split_at_mut(i);
        let (middle, right) = others.split_at_mut(1);
        let org1 = &mut middle[0];
        //process left
        for org2 in left {
            let ctrl = NeatVsNeat{organism_1: org1, organism_2: org2};
            //do stuff
        }
        //process right
        for org2 in right {
            let ctrl = NeatVsNeat{organism_1: org1, organism_2: org2};
            //do stuff
        }
    }

seems to be ok so far

I wouldn't say Rc is "the" way, just a way, as in it is one way to write code that compiles. The tradeoff is you pay the runtime cost for the reference counting. If I were writing this myself, the first thing I would ask myself is whether or not the matchup is symmetrical because if "o1 vs o2" is redundant with "o2 vs o1" then that saves about half the time. I'd write a loop that looks like this:

fn do_pairs<T, F: FnMut(&mut T, &mut T)>(v: &mut [T], mut f: F) {
    let mut remaining = &mut v[..];    
    while let Some((first, rest)) = remaining.split_first_mut() {
        for second in &mut *rest {
            f(first, second);
        }
        remaining = rest;
    }
}

"o1 vs o2" is not the same as "o2 vs o1" since each AI gets a turn to make the first move.

Directly answering the question, I think Arc<Mutex<T>> is more appropriate, as you may have both 1) as many references as you want, and 2) the objects will be mutable. But that comes with performance cost.

But I think it's not quite necessary.

I guess the core problem here is that all_orgs is borrowed mutably once when you get org1, and you can't get org2 then. Well, then just pop one of them from the vec, and the vec will be "free":

let all_orgs: Vec<Organism> = vec![...];

for i in 0..all_orgs.len() {
    let mut left_org = all_orgs.remove(i);
    for right_org in all_orgs.iter_mut() { 
        // I think your NeatVsNeat structure is basically just a function call
        // (and the compiler won't let you both a) store them with &mut's to objects elsewhere and b) cycle)
        play_a_match(&mut left_org, right_org); // right_org is already a `&mut`
    }
    all_orgs.push(left_org);
}

It's an unstable feature, but it seems like get_many_mut is exactly what you want...

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.