繁体   English   中英

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

[英]React.js Game of Life: Why doesn't the glider behave as expected?

情况GIF:

在此处输入图片说明


情况:

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

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


更新:

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

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

在此处输入图片说明

这是发生了什么:

在此处输入图片说明

有关滑翔机的更多信息: 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>
        );
    } 

});

您的错误可能不在您正在查看的地方。 Cell组件的componentWillReceiveProps函数中:

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

    let evolution = setInterval(() => { 
        this.life();
        this.nextLife();
    }, 500);
    this.nextLife(); // <- remove this line !!
    this.setState({
        started: true,
        evolution
    })   
}

您应该删除this.nextLife() (或之前调用this.life() )。 实际上,此函数在将要由nextLife()计算之前将alive设置为nextAlive :换句话说,您将其设置为默认值,即false

顺便说一句,我在单元组件的life()函数中发现了另一个错误:您可以访问this.state.selected而不是this.state.alive

总之,您的Cell组件的代码应为:

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.nextLife(); // bug 1
            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){ // 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>
        );
    } 

});

我会分别回答您的更新。

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

为了解决此问题,您需要通过以下方式将裁决代码移至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>
        );
    } 

});

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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