在Reaction中,我试图重现著名的游戏"扫雷舰",在我的旅程中,我想随机生成炸弹将在哪里产生,所以我得到了一个12*12矩阵和40个炸弹,我随机生成了代表坐标的x和y,但为了不公平,我只在第一个方块被选中后才生成炸弹,现在代码还没有完成,但我猜是因为在游戏的第一阶段(前面提到的)我通过按下提交按钮进行了重新渲染,变量炸弹永远不会减少到0,因为它总是被再次声明为40.我试图在函数外部声明它,我甚至try 为该值设置useState,但它不断递增并创建无限循环.如何声明不可更改的变量?

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

推荐答案

这是对您最初创建的内容的重构,主要区别在于:

  1. 当矿网格更新时,我们强制重新创建矿网格对象(数组的数组),以确保React识别状态更改
  2. 当当前没有放置地雷时,地雷单元的onClick处理程序将通过createMines函数在第一次单击时处理创建地雷.这样,状态只会作为操作的结果进行更改,而不是在每次渲染时更改.

示例:

const totalBombs = 40;
const square = { bomb: 0, viz: 0 };
const boardSideSize = 12;
// this is an easy way for us to recreate the mine_grid
const createDefaultGrid = () =>
  new Array(boardSideSize)
    .fill(0)
    .map(() => new Array(boardSideSize).fill(0).map(() => ({ ...square })));

// we call this once we want to initialize the game and place bombs
const createMineGridFromPositions = (minePositions) => {
  const grid = createDefaultGrid();
  minePositions.forEach(({ x, y }) => {
    grid[x][y].bomb = 1;
  });
  return grid;
};

// this is used to change mine_grid state. we create a new grid and return it
const createMineGrid = (grid) => {
  const new_grid = createDefaultGrid();
  new_grid.forEach((row, x) =>
    row.forEach((cell, y) => {
      cell.bomb = grid[x][y].bomb;
      cell.viz = grid[x][y].viz;
    })
  );
  return new_grid;
};

function App() {
  const [mine_grid, change_mine_grid] = useState(createDefaultGrid());
  const [mines_placed, change_mines_placed] = useState(false);
  const [game_over, set_game_over] = useState(false);

  const createMines = (firstX, firstY) => {
    const totalMines = [];
    while (totalMines.length < totalBombs) {
      const x = Math.floor(Math.random() * boardSideSize);
      const y = Math.floor(Math.random() * boardSideSize);
      console.log(x, y, totalMines);
      const gridPos = mine_grid[x][y];
      const sameAsFirstPos = x === firstX && y === firstY;
      if (
        gridPos.bomb === 0 &&
        gridPos.viz === 0 &&
        !sameAsFirstPos &&
        !totalMines.find((mines) => mines.x === x && mines.y === y)
      ) {
        totalMines.push({ x, y });
      }
    }
    const newGrid = createMineGridFromPositions(totalMines);
    newGrid[firstX][firstY].viz = 1;
    change_mine_grid(newGrid);
  };

  const clickHandler = (cell, x, y) => {
    if (cell.viz) {
      // if visible already this is a no-op. do nothing
      return;
    }

    if (!mines_placed) {
      createMines(x, y);
      change_mines_placed(true);
    } else {
      const new_mine_grid = createMineGrid(mine_grid);
      new_mine_grid[x][y].viz = 1;
      if (new_mine_grid[x][y].bomb) {
        set_game_over(true);
      }
      change_mine_grid(new_mine_grid);
    }
  }

  if (game_over) {
    // can render something different in this game state
    return null;
  }

  return (
    <div className="all">
      <div className="grid_container">
        {mine_grid.map((row, x) =>
          row.map((cell, y) => (
            <div
              key={`${x}-${y}`}
              style={{
                background:
                  cell.bomb && cell.viz ? "red" : cell.viz ? "green" : "gray",
                width: "50px",
                height: "50px",
                margin: "5px",
              }}
              onClick={() => clickHandler(cell, x, y)}
            />
          ))
        )}
      </div>
    </div>
  );
}

如果您进一步重构这一点,您可能会发现使用minePositions方法处理可见/炸弹单元的状态实际上比维护整个网格的状态更容易.

Javascript相关问答推荐

如何提取Cypress中文本

fetch在本地设置相同来源的cookie,但部署时相同的代码不会设置cookie

为什么从liveWire info js代码传递数组我出现错误?

过滤对象数组并动态将属性放入新数组

使用javascript将Plotly Expandable Sparkline转换为HighCharter Plot在bslib卡中

D3 Scale在v6中工作,但在v7中不工作

Mongoose post hook在使用await保存时不返回Postman响应

分层树视图

你怎么看啦啦队的回应?

Javascript json定制

未定义引用错误:未定义&Quot;而不是&Quot;ReferenceError:在初始化&Quot;之前无法访问';a';

rxjs插入延迟数据

JavaScript是否有多个`unfined`?

删除加载页面时不存在的元素(JavaScript)

使用Reaction窗体挂钩注册日历组件

用于测试其方法和构造函数的导出/导入类

有没有办法更改Chart.js 3.x.x中主要刻度的字体?

AG-GRIDreact 显示布尔值而不是复选框

如何在加载页面时使锚定标记成为焦点

观察子组件中的@Output事件emits 器?