Game of Life на Javascript: не работает проверка соседей

Я пытаюсь реализовать игру Конвея «Жизнь», и она работает неправильно, но я не могу найти, в чем проблема. В настоящее время я использую setInterval(), чтобы каждый раз получать новое поколение платы, но я пробовал проверять ошибки, используя setTimeout(), затем проверять таблицы до и после, используя console.table, и не мог понять это. Моя функция checkNeighbors работает корректно (т. е. идентифицирует рождение к смерти и смерть к рождению) для некоторых ячеек, но не для всех.

Может ли кто-нибудь помочь мне понять, где проблема?

(Я получаю новую доску из функции newBoard, которую я вызываю в своей функции mapDispatchToProps.)

Вот мой код и ссылка на Codepen: https://codepen.io/lieberscott/pen/qxrVbE?editors=0110

// React & Redux libraries setup
const { Component } = React;
const { createStore, applyMiddleware } = Redux;
const { Provider } = ReactRedux;
const { connect } = ReactRedux;
const { combineReducers } = Redux;

let grid = [];
let width = 25;
let height = 50;

for (let i = 0; i < height; i++) {
  grid.push([]);
  for (let j = 0; j < width; j++) {
    grid[i][j] = Math.random() > 0.85;
  }
}

const initState = {
  arr: grid
};


const reducer = (state = initState, action) => {
  let newState;
  // console.table(state.arr);
  switch (action.type) {
    case "NEW_ARR":
      newState = {
        arr: action.arr
      };
      // console.table(newState.arr);
      return newState;
      break;

    default:
      return state;
      break;
  }
}

const store = createStore(reducer);

const newBoard = (arr, newArr) => {
  for (let i = 0; i < height; i++) {
    for (let j = 0; j < width; j++) {
      let score = checkNeighbors(arr, i, j);
      if (arr[i][j] == false && score == 3) {
        newArr[i][j] = true;
      }
      else if (arr[i][j] == true && (score > 3 || score < 2)) {
        newArr[i][j] = false;
      }
      else { // unessential line since already set newArr = arr
        newArr[i][j] = arr[i][j];
      }
    }
  }
  return newArr;
}

function checkNeighbors(array, x, y) {
  let score = 0;
  for (let i = -1; i <= 1; i++) {
    let h = (i + x + height) % height;
    for (let j = -1; j <= 1; j++) {
      let w = (j + y + width) % width;
      score += array[h][w];
    }
  }
  score -= array[x][y];
  return score;
}

const Cell = (props) => {
  return (
    <td className={props.black ? "black" : ""}>
    </td>
  );
}

class App extends React.Component {
  constructor(props) {
    super(props);
  }

  componentDidMount() {
    setInterval(() => this.props.newGeneration(this.props.data.arr), 90)
  }

  render() {

    return (
      <table onClick={this.toggle}>
        <thead>
        </thead>
          <tbody>
            {this.props.data.arr.map((row, i) =>
              <tr key={i}> {row.map((cell, j) =>
                <Cell key={j} black={cell}/>)}
              </tr> )}
          </tbody>
      </table>
    );
  }
}


const mapStateToProps = (state) => {
  return {
    data: state
  };
};

const mapDispatchToProps = (dispatch) => {
  return {
    newGeneration: (array) => {
      let arr1 = array.slice(0);
      let arr2 = array.slice(0);
      let newArr = newBoard(arr1, arr2);
      dispatch(newGeneration(newArr));
    }
  }
}

function newGeneration(newArr) {
  return {
    type: "NEW_ARR",
    arr: newArr
  };
}

App = connect(mapStateToProps, mapDispatchToProps)(App); // use same name as class apparently?







const main = window.document.getElementById("main");

// Provider wraps our app
ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
    main);

person Scott    schedule 10.02.2018    source источник


Ответы (1)


Мне вроде удалось разобраться. В моей функции newBoard менялись значения в исходном массиве (arr) (хотя в моем коде я якобы изменял только значения newArr).

Поэтому вместо этого я изменил функцию newBoard, создав новый массив ВНУТРИ функции вместо того, чтобы передавать его. Это сработало:

https://codepen.io/lieberscott/pen/EQWGXW?editors=0110

const newBoard = (arr) => {
  let newArr = [];
  for (let i = 0; i < height; i++) {
    newArr.push([]);
    for (let j = 0; j < width; j++) {
      let score = checkNeighbors(arr, i, j);
      if (arr[i][j] == false && score == 3) {
        newArr[i].push(true);
      }
      else if (arr[i][j] == true && (score > 3 || score < 2)) {
        newArr[i].push(false);
      }
      else {
        newArr[i].push(arr[i][j]);
      }
    }
  }
  return newArr;
}

Тем не менее, я думаю, что любые комментарии о том, почему имело место первоначальное поведение, были бы ценны.

person Scott    schedule 10.02.2018