这行代码出了什么问题?(React,Game Of Life)
2017-08-26
100
出现一个我无法理解的错误。当我按下
<button>50x70</button>
并按下
<button>run</button>
时,我收到此错误。
我不明白为什么,因为它适用于标准 50x50 板。
为什么这行代码会导致错误?
neighbors+=board[x+i][y+j].value
https://codepen.io/anon/pen/OjoZKX
TypeError: Cannot read property '0' of undefined
evaluateGen
C:/Www/Projects/gameoflife/src/App.js:65
62 |
63 | for(let i=-1; i <= 1; i++){
64 | for(let j=-1; j<= 1; j++){
> 65 | neighbors+=board[x+i][y+j].value
66 | }
67 | }
68 | neighbors-=board[x][y].value
View compiled
(anonymous function)
C:/Www/Projects/gameoflife/src/App.js:108
105 |
106 | run(){
107 | this.interval = setInterval(() => {
> 108 | const nextState = evaluateGen(this.state.board)
109 | this.setState({paused: false, generation: this.state.generation + 1, board: nextState})
110 | }, 50)
111 | }
// creates the board with random 1/0 value.
const createBoard = function(width, height) {
let board = []
for(var x = 0; x < width; x++){
board.push([])
for(var y = 0; y < height; y++){
if(x === 0 || y === 0) {
board[x].push({value: 0})
}
else if (x === width-1 || y === height-1){
board[x].push({value: 0})
}
else {
let number = Math.round(Math.random())
board[x].push({value: number})
}
}
}
return board
}
// Game Of Life rules.
const evaluateCell = function(x, cell){
let value = x
if(x < 2){
value = 0
}
else if(x === 2){
value = cell
}
else if(x === 3){
value = 1
}
else if(x > 3){
value = 0
}
else {
console.log('error: default case evaluateCell()')
value = 0
}
return value
}
// evaluates a generation of board state by going through each cell and counting neighbors and calling evaluateCell accordingly.
const evaluateGen = function(board){
let nextGen = JSON.parse(JSON.stringify(board));
for(let y = 1; y < board.length - 1; y++){
for(let x = 1; x < board[y].length - 1; x++){
let neighbors = 0
for(let i=-1; i <= 1; i++){
for(let j=-1; j<= 1; j++){
neighbors+=board[x+i][y+j].value
}
}
// remove current cell from neighbors.
neighbors-=board[x][y].value
let nextvalue = evaluateCell(neighbors, board[x][y].value)
nextGen[x][y].value = nextvalue
}
}
return nextGen
}
class App extends React.Component {
constructor(){
super()
this.state = {
width: 50,
height: 50,
board: createBoard(50, 50),
paused: false,
generation: 0
}
}
generateBoard(width, height) {
this.pause()
const board = createBoard(width, height)
this.setState({board, generation: 0, width, height })
}
pause(){
clearInterval(this.interval)
this.setState({paused: true})
}
run(){
this.interval = setInterval(() => {
const nextState = evaluateGen(this.state.board)
this.setState({paused: false, generation: this.state.generation + 1, board: nextState})
}, 50)
}
componentDidMount() {
this.run()
}
componentWillUnmount() {
clearInterval(this.interval)
}
render() {
let {board, generation, width, height} = this.state
return (
<div className="App">
<h3>generation:{generation}</h3>
{board.map(x => x.map(item => {
return (
<div className={`state-${item.value}`}></div>
)
}))}
<button onClick={()=> this.run()}>run</button>
<button onClick={()=> this.pause()}>pause </button>
<button onClick={()=> this.generateBoard(width, height)}>generate</button>
<button onClick={()=> this.generateBoard(50, 70)}>50 x 70</button>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'))
.App div {
width: 10px; height: 10px;
outline: 1px solid black;
}
.App {
display: flex;
flex-wrap: wrap;
width: 500px; height: 500px;
}
.state-1{
background-color: red;
}
<div id='root'></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
2个回答
我认为问题发生在您尝试计算边缘上的图块的邻居时。由于您尝试访问不在网格上的图块,因此循环中的某些变量变得未定义。我建议添加 if 语句来检查这一点。类似于:
if(x+i >= 0 && y+i >= 0){
neighbors+=board[x+i][y+j].value
}
Pizza Scripters
2017-08-26
您应该循环直到 x 和 y 小于 board.length - 2,而不是 board.length - 1,因为您要确保它不会评估板的边缘​​。我认为您犯了一个相当常见的错误,即忘记了数组的长度将比该数组的最大索引多一个。
例如,如果其中一行看起来像 [4, 6, 2, 3],它的 .length 为 4,但如果您尝试访问 row[4],您将得到未定义的结果。如果您在外循环中循环直到长度 - 1,然后在内循环中将每个值加 1(您这样做是因为您在 -1 和 1 之间循环 i/j,然后将该值添加到外索引),您的代码就会执行上述操作。
此外
我认为您在内部数组中反转了变量 - 在外循环中使用
y
作为行循环变量,使用
x
作为列循环变量,但在内循环中这些变量被反转了。因此,如果它不是正方形,它最终会碰到不存在的行。
您的代码整体应如下所示:
const evaluateGen = function(board){
let nextGen = JSON.parse(JSON.stringify(board));
for(let x = 1; x < board.length - 2; x++){
for(let y = 1; y < board[y].length - 2; y++){
let neighbors = 0
for(let i=-1; i <= 1; i++){
for(let j=-1; j<= 1; j++){
neighbors+=board[x+i][y+j].value
}
}
// remove current cell from neighbors.
neighbors-=board[x][y].value
let nextvalue = evaluateCell(neighbors, board[x][y].value)
nextGen[x][y].value = nextvalue
}
}
return nextGen
}
Ben Hare
2017-08-27