[英]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.