简体   繁体   中英

React - Update state of 2D array and fill it with random numbers using .map function and new Array.fill

I'm working on a John Conway's Game of Life app and I'm still learning React.

Here is what I have so far . The game board is created using a 2D array in my App.js 's state. I use new Array and the .fill method in my constructor to initially create the squares of the board. Later on in App.js I have a function called isSquareAlive that handles the onClick functionality and changes the appropriate squares to a different color when the user clicks on them (they are "alive" in the Game of Life sense).

What I want to do now is generate a random board when the user first loads the app, some of the squares will be active and others will not. I have created a random number function called getRandomNumber that creates a 1 or 0. Now I want to create another function that will be called on componentDidMount and this function would create an initial game board when the user loads the app and it will call getRandomNumber and fill some of the 2d array's elements (squares) with 1's and others with 0's. Squares with 1's will be "alive" and squares with 0's won't.

In other words I want a randomly generated game board every time a user loads the page. How would I do this? Nested .map functions and then pushing the results of getRandomNumber into new Array.fill?

Here is my App.js :

import React, { Component } from 'react';
import './App.css';
import GameBoard from './GameBoard.js';
import Controls from './Controls.js';
import update from 'immutability-helper';
import Info from './Info.js';

class App extends Component {
  constructor(props){
    super(props);

    this.state = {
      boardHeight: 50,
      boardWidth: 30,
      iterations: 10,
      reset: false,
      alive: false,
      board: [],
      randomNum: ''
    };

    this.state.board = new Array(this.state.boardHeight).fill(new Array(this.state.boardWidth).fill(0));
  }

  // Allows user to click button and change size of game board
  selectBoardSize = (width, height) => {
    this.setState({
      boardHeight: height,
      boardWidth: width,
      board: new Array(this.state.boardHeight).fill(new Array(this.state.boardWidth).fill(0))
    });
  }

  // Resets game board back to blank when user clicks reset button
  onReset = () => {
    this.setState({ board: new Array(this.state.boardHeight).fill(new Array(this.state.boardWidth).fill(0)) })
  }

  // Generates random number
  getRandomNumber = (max) => {
    return Math.floor(Math.random() * Math.floor(max));
  }

  /* This is the function I am trying to build and generate a random starting game board with
  componentDidMount = () => {
    // Stores random number 1 or 2
    const number = this.getRandomNumber(2);
    const data = this.state.board;

    // This is what I need help on
    const startingBoard = data.map((row, y) => {
                            row.map((ea, x) => {
                              return 1;
                            })
    })

    // After startingBoard is working I can set state with startingBoard
    this.setState({
      board: startingBoard
    });
  }
*/


  // Called when user clicks on specific square. Changes color of square depending on if it's alive or not
  isSquareAlive = (x, y) => {
    const data = this.state.board;
    const ySquare = y;
    const xSquare = x;

    const newData = data.map((row, y) => {
      return y === ySquare ? (
        row.map((cell, x) => x === xSquare ? (cell + 1) % 2 : cell)
      ) : (
        row
      )
    })

    this.setState({ board: newData });

  }



  render() {
    /*console.log('Random number is : ' + this.state.randomNum);*/
    return (
      <div>
      <div className="game-container">

      <GameBoard
        height={this.state.boardHeight}
        width={this.state.boardWidth}
        reset={this.onReset}
        board={this.state.board}
        alive={this.isSquareAlive}
        isAlive={this.state.alive}
      />

      <Controls
        selectBoardSize={this.selectBoardSize}
        iterations={this.state.iterations}
        onReset={this.onReset}
      />

      </div>

      <div className="info-container">
        <Info />
      </div>
      </div>
    );
  }
}

export default App;

The return 1 in startingBoard was just me being a noob and trying to get that to return something.

Just to reiterate: the board is created like this:

this.state.board = new Array(this.state.boardHeight).fill(new Array(this.state.boardWidth).fill(0));

How can I push random numbers into the 2D array?

Here is a simplified App. I think it may work to set the initial value for state.board in the constructor. This should effectively create a new board every time the user start the app.

import React, {Component} from 'react';

const createRandomBoard = (height, width) => {

  const randomCellValue = () => (Math.random() < 0.5 ? 1 : 0);

  // thank you @simonbor on StackOverflow:
  // https://stackoverflow.com/questions/5836833/create-a-array-with-random-values-in-javascript
  const createRow = () => Array.from({length: width}, randomCellValue);

  return Array.from({length: height}, createRow);
};


class App extends Component {
  constructor(props){
    super(props);
    const boardHeight = 50;
    const boardWidth = 30;

    this.state = {
      boardHeight,
      boardWidth,
      board: createRandomBoard(boardHeight, boardWidth),
    };
  }

  render() {

    return (
      <div>

      </div>
    );
  }
}

export default App;

Sit this on stackblitz: https://stackblitz.com/edit/so-gol-answer?file=App.js

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM