I am working on a minesweeper copy in Rust and WASM. At the moment, I'm finishing the logic for Mine Sweeper. Mainly, when the user clicks on an empty tile with no bombs near it, the program then searches the neighbors and reveals those tiles if they are not near any bombs.
Notice the large empty spaces on the game that opens up automatically.
The program uses two 1D vectors to store where the bombs are and also what is the state of each tile.
Then this recursive program sets the state of a found empty tile to SpotState::Empty, then continues this with the neighbors.
/// for uncovering empty neighbors and recursively uncovering their empty neighbors
fn uncover_empty_neighbors(&mut self, col: usize, row: usize) {
// break case for recursion
if self.state_vec[self.get_idx(col, row)] == SpotState::Empty {
return;
}
if self.get_mine_neighbor_count(col, row) == 0 {
let idx = self.get_idx(col, row);
self.state_vec[idx] = SpotState::Empty;
}
let inbound_neighbors = POSSIBLE_NEIGHBORS
.iter()
.map(|[x, y]| [x + col as isize, y + row as isize])
.filter(|[x, y]| self.check_bounds(x, y))
.for_each(|[x, y]| self.uncover_empty_neighbors(x as usize, y as usize));
}
However, I get this error:
error[E0500]: closure requires unique access to `*self` but it is already borrowed
--> src\lib.rs:138:23
|
137 | .filter(|[x, y]| self.check_bounds(x, y))
| -------- ---- first borrow occurs due to use of `*self` in closure
| |
| borrow occurs here
138 | .for_each(|[x, y]| {
| -------- ^^^^^^^^ closure construction occurs here
| |
| first borrow later used by call
139 | self.uncover_empty_neighbors(x as usize, y as usize)
| ---- second borrow occurs due to use of `*self` in closure
For more information about this error, try `rustc --explain E0500`.
error: could not compile `minesweeper_wasm` due to previous error
warning: build failed, waiting for other jobs to finish...
error: build failed
I'm confused about how to accomplish this. Is the closure unable to capture self
since self
is already mutably borrowed in the function uncover_empty_neighbors()
? Is using self
inevitably a bad move in this case and what other data structure would be useful?
Yes. Remember that iterators are evaluated lazily, so the closure passed into filter
needs to borrow self
and keep borrowing it while for_each
is executing, as for_each
needs to evaluate the iterator it is called on.
You can either try to restructure the code so that either of the methods does not depend on self
, or you can simply collect()
into a new Vec
after the filter()
, so that there is no immutable borrow alive as uncover_empty_neighbors
executes.