In react I tried to recreate the well known game "minesweeper" and in my journey I wanted to randomly generate where the bombs will spawn, so I got a 12*12 matrix and 40 bombs for which I randomly generate x and y that stand for the coordinates, but to not be unfair I generate the bombs only after the first square is selected, now the code isn’t complete but I guess because after the first phase of the game(mentioned earlier) I do a re-render by pressing the submit button the variable bomb is never decremented to 0 because it will always be declared again as 40 ,tried to declare it outside of the function and I have even tried to set up a useState for that value but it keeps getting incremented back and creating an infinite loop . How can I declare an unchangeable variable?
import { useState } from 'react'
import './App.css'
const square = {
bomb: 0,
viz: 0,
}
let nrbomb = 40
function App() {
const n = 12
let v = []
for (let i = 0; i < n; i++) {
let arr = []
for (let j = 0; j < n; j++) arr.push(square)
v.push(arr)
}
const [inc, change_inc] = useState(0)
const [mine_grid, change_mine_grid] = useState(v)
const [cx, change_cx] = useState(0)
const [cy, change_cy] = useState(0)
const [rendergame, change_render_game] = useState(0)
if (inc == 0) {
return (
<div className="all">
<div className="grid_container">
{mine_grid.map((arr) => {
return arr.map((e) => {
return (
<div
style={{
background: 'green',
width: '50px',
height: '50px',
margin: '5px',
}}
></div>
)
})
})}
</div>
<h6>for x:</h6>
<input
value={cx}
onChange={(e) => {
change_cx(e.target.value)
}}
></input>
<h6>for y:</h6>
<input
value={cy}
onChange={(e) => {
change_cy(e.target.value)
}}
></input>
<button
type="button"
onClick={() => {
let new_grid = mine_grid
new_grid[cx][cy].viz = 1
change_mine_grid(new_grid)
change_inc(1)
}}
>
Submit move
</button>
</div>
)
}
if (inc == 1 && rendergame == 0) {
while (nrbomb != 0) {
let x = Math.floor(Math.random() * n)
let y = Math.floor(Math.random() * n)
console.log(x, y, nrbomb)
if (mine_grid[x][y].bomb === 0 && mine_grid[x][y].viz == 0) {
nrbomb = nrbomb - 1
let new_grid = mine_grid
new_grid[x][y].bomb = 1
change_mine_grid(new_grid)
}
}
}
return <div className="grid_container"></div>
}
export default App
2
Answers
Instead of a
while
loop, use afor
:This is a refactor of what you originally created, with the major differences being:
createMines
function. This way state is only ever changed as a result of an action, and not on every render.Sample:
If you refactor this further you might find it’s actually easier to use the
minePositions
approach for handling state for visible/ bomb cells instead of maintaining state for the entire grid.