this post was submitted on 10 Jun 2024
12 points (100.0% liked)

Bevy

234 readers
1 users here now

A community for discussion around the bevy game engine! https://bevyengine.org/

founded 11 months ago
MODERATORS
 

I don't know if it's the best place to ask this, but I've been having issues with trying to make minesweeper with bevy.

I tried making a function that would give the number of mines around the tile that was clicked if it wasn't a mine. Then, I wanted to make it so that when the number of mines around the clicked tiles is 0, it reveals the surrounding tiles. Finally, I tried making the function recursive by rerunning it on the empty surrounding tiles.

The issue is that it seems that certain tiles with no mines surrounding them don't reveal the surrounding tiles.

Here's the portion of the code I am talking about (I know it's pretty bad):

fn find_surrounding_mines(
                          mut set: ParamSet<(
                              EventReader<TileEntity>,
                              EventWriter<TileEntity>,
                             )>,
                          mut surrounding_mines: EventWriter<SurroundingMines>,
                          mut query_board: Query<&mut Board>,
                          mut change_tile_image: EventWriter<ChangeTileImage>,
                        mut query_mine: Query<(&Mine, &mut Tile)>) {
    let dy: [i8; 8] = [-1, -1, -1, 0, 0, 1, 1, 1];
    let dx: [i8; 8] = [-1, 0, 1, -1, 1, -1, 0, 1];
    
    let board = query_board.single_mut();
    let mut num_mine: u8 = 0;
    let mut y: u8 = 0;
    let mut copy_x: usize = 0;
    let mut tile_read:bool = false;
    let mut copy_num_mine:u8 = 0;
    for tile in set.p0().read(){
        for (row_index, vector) in board.tiles.iter().enumerate(){
            if let Some(x) = vector.iter().position(|&x|x == tile.0) {
                copy_x = x;
                y = row_index as u8;
                for i in 0..8{
                    if x as i8 + dx[i] >= 0 && x as i8 + dx[i] < board.width as i8 && y as i8 + dy[i] >= 0 && y as i8 +dy[i] < board.height as i8{
                        if let Ok((_mine,mut tile)) = query_mine.get_mut(board.tiles[(y as i8 + dy[i]) as usize][(x as i8+ dx[i]) as usize]){
                            num_mine += 1;
                            tile.hidden = false;
                        }
                    }
                }
                break;
            } 
        }
        
        surrounding_mines.send(SurroundingMines(num_mine));
        change_tile_image.send(ChangeTileImage{tile: tile.0, asset: "Minesweeper_LAZARUS_21x21_".to_string() + &num_mine.to_string() + ".png"});
        copy_num_mine = num_mine;
        num_mine = 0;
        tile_read = true;
    }

    if copy_num_mine == 0 && tile_read{
            tile_read = false;
            for i in 0..8{
                if copy_x as i8 + dx[i] >= 0 && copy_x as i8 + dx[i] < board.width as i8 && y as i8 + dy[i] >= 0 && y as i8 +dy[i] < board.height as i8{
                    if let Ok((_mine, mut tile)) = query_mine.get(board.tiles[(y as i8 + dy[i]) as usize][(copy_x as i8 + dx[i]) as usize]){
                        continue;
                    }else{
                        println!("{:?}", (y as i8 + dy[i], copy_x as i8 + dx[i]));
                        set.p1().send(TileEntity(board.tiles[(y as i8 + dy[i]) as usize][(copy_x as i8 + dx[i]) as usize]));
                    }
                }
            }
        }
}
top 2 comments
sorted by: hot top controversial new old
[โ€“] 5C5C5C 5 points 4 months ago* (last edited 4 months ago) (1 children)

One thing I'm not sure about is whether an EventReader will provide you with events that were created with an EventWriter which is owned by the same system.

Is there any discernable pattern to which tiles don't get flipped? If the problem is with the reader/writer relationship then I would expect the tiles surrounding the target to get flipped but no others.

Recursion isn't necessary or recommended here. Instead of using recursion you should use a queuing pattern:

let mut queue = Vec::new();
for e in set.p0.read() {
    queue.push(e);
}

while let Some(e) = queue.pop() {
    // If e is already flipped then skip to the next iteration 
    // If e is not a mine, flip it and push its neighbors into the queue
}
[โ€“] [email protected] 2 points 4 months ago* (last edited 4 months ago)

I'm nor really sure I can find a pattern. It's really random. I'm going to try using queues. Maybe that'll work.

Edit: Not only is my code way cleaner, but it works without any issues. Thank you so much!