情况GIF:

javascript - React.js生活游戏:为什么滑翔机的表现不如预期?-LMLPHP



情况:

完全没有错误。我放入一些单元格,单击“开始”,无论配置如何,它们都消失了。我还尝试了滑翔机配置,它立即消失了。

如果您发现我做错了什么,并且我们能够使“人生游戏”发挥作用,我将在可接受的答案的基础上再给您50英镑的赏金。



更新:

现在,我可以放点,它们会不断发展,但并非像《人生游戏》那样。例如,查看滑翔机配置会发生什么。

这是滑翔机应该如何表现:

javascript - React.js生活游戏:为什么滑翔机的表现不如预期?-LMLPHP

这是发生了什么:

javascript - React.js生活游戏:为什么滑翔机的表现不如预期?-LMLPHP

有关滑翔机的更多信息:https://en.wikipedia.org/wiki/Glider_(Conway%27s_Life)



码:

游戏

var Game = createReactClass({

    getInitialState() {
        return {
            start: false
        }
    },

    handleStartClick() {
        this.setState({
            start: true
        })
    },

    handleStopClick() {
        this.setState({
            start: false
        })
    },

    render() {
        return (
            <div>
                <h1>React.js Game of Life</h1>
                <div className="buttons">
                    <button className="btn btn-danger" onClick={this.handleStopClick}>Stop</button>
                    <button className="btn btn-success" onClick={this.handleStartClick}>Start</button>
                </div>
                <Board start={this.state.start}/>
            </div>
        )
    }

});




var Board = createReactClass({

    getInitialState() {
        var array = [];
        for (var i = 0; i < 400; i++) {
            array.push(<Cell key={i} id={i} cells={array} start={this.props.start} />);
        }

        return {
            cells: array
        };
    },

    render() {

        var that = this;

        return (
            <div className="board">
                {
                    this.state.cells.map(function(item, i) {
                        return <Cell key={i} id={i} cells={that.state.cells} start={that.props.start}/>
                    })
                }
            </div>
        );
    }

});


细胞

var Cell = createReactClass ({

    getInitialState() {
        return {
            alive: false,
            nextAlive: false,
            started: false
        }
    },

    componentWillReceiveProps(nextProps) {

        var evolution;

        if(nextProps.start && this.state.started == false) {

            let evolution = setInterval(() => {
                this.life();
                this.nextLife();
            }, 500);
            this.setState({
                started: true,
                evolution
            })
        }

        else {
            clearInterval(this.state.evolution);
            this.setState({
                started: false
            })
        }

    },

    isAlive(r, c){

        var size = Math.sqrt(this.props.cells.length)

        if (r == -1) {
            r = size - 1
        }
        if (r == size) {
            r = 0
        }
        if (c == -1) {
            c = size - 1
        }
        if (c == size) {
            c = 0
        }
        var id = r * size + c
        return this.props.cells[id].state.alive

    },

    life() {

        var neighbours = 0
        var size = Math.sqrt(this.props.cells.length)
        var row = Math.floor( this.props.id / size )
        var col = this.props.id - row * size

        if (this.isAlive(row - 1, col)) {
            neighbours++
        }
        if (this.isAlive(row - 1, col + 1)) {
            neighbours++
        }
        if (this.isAlive(row - 1, col - 1)) {
            neighbours++
        }
        if (this.isAlive(row, col + 1)) {
            neighbours++
        }
        if (this.isAlive(row, col - 1)) {
            neighbours++
        }
        if (this.isAlive(row + 1, col)) {
            neighbours ++
        }
        if (this.isAlive(row + 1, col + 1)) {
            neighbours ++
        }
        if (this.isAlive(row + 1, col - 1))  {
            neighbours ++
        }

        this.state.nextState = false

        if (this.state.alive){
          if( neighbours < 2) {
              this.setState ({
                 nextAlive: false
              })
          }
          if (neighbours > 3) {
              this.setState ({
                 nextAlive: false
              })
          }
          if (neighbours == 3 || neighbours == 2) {
              this.setState ({
                 nextAlive: true
              })
          }
        }
        else{
          if (neighbours == 3) {
              this.setState ({
                 nextAlive: true
              })
          }
        }
    },

    nextLife () {
        this.setState({
            alive: this.state.nextAlive
        })
    },

    componentDidMount() {
        this.props.cells[this.props.id] = this;
    },

    toggleLife() {
        this.setState({
            alive: !this.state.alive
        })
    },

    render() {
        return (
           <div className={this.state.alive ? "cell alive" : "cell"} onClick={this.toggleLife}></div>
        );
    }

});

最佳答案

我会分别回答您的更新。

下一个错误更加棘手:您无需任何同步即可独立更新单元。这意味着,根据您的运气,邻居可能会处于完全不同的世代。因此,当您点击开始时得到的是随机的。

为了解决此问题,您需要通过以下方式将裁决代码移动到Board元素:

var Board = React.createClass({

  componentWillReceiveProps(nextProps) { // <- from here ...

    var evolution;

    if(nextProps.start && this.state.started == false) {

      let evolution = setInterval(() => {
        this.state.cells.forEach( cell => cell.life() )
        this.state.cells.forEach( cell => cell.nextLife() )
      }, 500);

      this.setState({
        started: true,
        evolution
      })
    }

    else {
      clearInterval(this.state.evolution);
      this.setState({
        started: false
      })
    }

  }, // <- ... to here

  getInitialState() {
    var array = [];
    for (var i = 0; i < 400; i++) {
      array.push(<Cell key={i} id={i} cells={array} start={this.props.start} />);
    }

    return {
      cells: array,
      started: false
    };
  },

  render() {

    var that = this;

    return (
      <div className="board">
      {
        this.state.cells.map(function(item, i) {
          return <Cell key={i} id={i} cells={that.state.cells} start={that.props.start}/>
        })
      }
      </div>
    );
  }

});


然后,您应该从cells元素中删除componentWillReceiveProps()

var Cell = createReactClass ({

    getInitialState() {
        return {
            alive: false,
            nextAlive: false,
            started: false
        }
    },

    componentWillReceiveProps(nextProps) { /* I'm useless now */  },

    isAlive(r, c){

        var size = Math.sqrt(this.props.cells.length)

        if (r == -1) {
            r = size - 1
        }
        if (r == size) {
            r = 0
        }
        if (c == -1) {
            c = size - 1
        }
        if (c == size) {
            c = 0
        }
        var id = r * size + c
        return this.props.cells[id].state.alive

    },

    life() {

        var neighbours = 0
        var size = Math.sqrt(this.props.cells.length)
        var row = Math.floor( this.props.id / size )
        var col = this.props.id - row * size

        if (this.isAlive(row - 1, col)) {
            neighbours++
        }
        if (this.isAlive(row - 1, col + 1)) {
            neighbours++
        }
        if (this.isAlive(row - 1, col - 1)) {
            neighbours++
        }
        if (this.isAlive(row, col + 1)) {
            neighbours++
        }
        if (this.isAlive(row, col - 1)) {
            neighbours++
        }
        if (this.isAlive(row + 1, col)) {
            neighbours ++
        }
        if (this.isAlive(row + 1, col + 1)) {
            neighbours ++
        }
        if (this.isAlive(row + 1, col - 1))  {
            neighbours ++
        }

        this.state.nextState = false

        if (this.state.alive){ // bug 2
          if( neighbours < 2) {
              this.setState ({
                 nextAlive: false
              })
          }
          if (neighbours > 3) {
              this.setState ({
                 nextAlive: false
              })
          }
          if (neighbours == 3 || neighbours == 2) {
              this.setState ({
                 nextAlive: true
              })
          }
        }
        else{
          if (neighbours == 3) {
              this.setState ({
                 nextAlive: true
              })
          }
        }
    },

    nextLife () {
        this.setState({
            alive: this.state.nextAlive
        })
    },

    componentDidMount() {
        this.props.cells[this.props.id] = this;
    },

    toggleLife() {
        this.setState({
            alive: !this.state.alive
        })
    },

    render() {
        return (
           <div className={this.state.alive ? "cell alive" : "cell"} onClick={this.toggleLife}></div>
        );
    }

});


另外,您也可以从started中删除​​start状态和Cell道具。

07-28 11:40