Как сделать эту функцию рекурсивной / запустить, пока не будут выполнены требования? - PullRequest
0 голосов
/ 18 октября 2019

На данный момент я могу жестко кодировать один и тот же фрагмент после каждого оператора if, которому нужно только изменить аргумент, который получает getAdjacentCells (id). Я не смог найти способ повторить эту часть. Я думаю, что это можно сделать рекурсивно, но я не знаю, как это сделать.

Редактировать: я изначально набрал, что isCellEmpty получил массив объектов: [{topLeft: null}, {topCenter: "cell-1-2 "}, {topRight:" cell-1-3 "}, {middleLeft: null}, {middleRight:" cell-2-3 "}], когда в действительности это один объект: {topLeft:null, topCenter: "cell-1-2", topRight: "cell-1-3", middleLeft: null, middleRight: "cell-2-3"}

// Gets an object that looks like this: {topLeft: null, topCenter: "cell-1-2", topRight: "cell-1-3", middleLeft: null, middleRight: "cell-2-3"}
function isCellEmpty(adjacentCells) {
  Object.values(adjacentCells).forEach(id => {
    // Checks that the ids in stored in the object values do not equal null
    if (id !== null) {
      board[getBoardPosition(id)].opened = true;
      // getAdjacentCells() will return either an array of objects similar to the one the function takes as an argument or an integer
      // if getAdjacentCells(id) returns a number, add a div to the HTML element with that id
      if (typeof (getAdjacentCells(id)) === "number") {
        // Removes all other divs, this prevents repetition
        $("#" + id).empty();
        // Appends an empty div
        $("#" + id).append("<div></div>");
      // HERE'S WHERE IT STARTS: If getAdjacentCells(id) returns an object, do the same as above with every id in it
      } else if (typeof (getAdjacentCells(id)) === "object") {
        Object.values(getAdjacentCells(id)).forEach(id2 => {
          if (id2 !== null) {
            board[getBoardPosition(id2)].opened = true;
            if (typeof (getAdjacentCells(id2)) === "number") {
              $("#" + id2).empty();
              $("#" + id2).append("<div></div>");
            // HERE IT REPEATS: 
            } else if (typeof (getAdjacentCells(id2)) === "object") {
              ... 
            }
          }
        })
      }
    }
  });
}

Ответы [ 2 ]

0 голосов
/ 18 октября 2019

Рекурсия должна работать просто отлично: в самом базовом случае вы вызываете свой собственный метод с id2. Однако, предполагая, что getAdjacentCells может вернуть ячейки, которые вы уже посетили, вы в конечном итоге будете возвращаться бесконечно, если не сможете отследить, какие идентификаторы вы уже посетили, и передать это.

function setCellState(id, visited) {
  if(id === null) {
    return;
  }
  if(visited === undefined) {
    visited = new Set();
  }
  if(visited.has(id)) {
    return;
  }
  visited.add(id);

  board[getBoardPosition(id)].opened = true;

  // getAdjacentCells() will return either an array of objects similar to the one the function takes as an argument or an integer
  let adjacentCells = getAdjacentCells(id);
  // if getAdjacentCells(id) returns a number, add a div to the HTML element with that id
  if (typeof (adjacentCells) === "number") {
        // Removes all other divs, this prevents repetition
        $("#" + id).empty()
          // Appends an empty div
          .append("<div></div>");
  } else if (typeof (adjacentCells) === "object") {
    Object.values(adjacentCells).forEach(id2 => setCellState(id2, visited));
  }

Я позволил себе сменить имя метода, чтобы лучше представить, что метод на самом деле делает. Я также изменил его, чтобы начать с идентификатора отдельной ячейки, поскольку это упрощает рекурсию и позволяет комментарию вокруг поведения getAdjacentCells обеспечить лучший контекст.

0 голосов
/ 18 октября 2019

Вы можете сделать рекурсивный вызов со значением, полученным из getAdjacentCells. Однако, обязательно позвоните getAdjacentCells только один раз для того же id. Теперь это совершенно неэффективно, поскольку вы повторяете тот же вызов.

См. Также некоторые другие предложения в коде.

function isCellEmpty(adjacentCells) {
    // I would move this check here, although not necessary if you prefer it in the loop.
    if (typeof adjacentCells === "number") {
        $("#" + id).empty().append("<div>"); // You can chain jQuery...
        return;
    } 
    for (let id of adjacentCells) { // Just use a for..of loop
        if (id === null) continue; // keep IF-ELSE nesting flat.
        let cell = board[getBoardPosition(id)];
        if (cell.opened) continue; // Add this to avoid circling around
        cell.opened = true;
        isCellEmpty(getAdjacentCells(id)); // recursive call
    }
}

Object.values ​​

Вы пишете в комментарияхвашего кода, который:

getAdjacentCells () вернет либо массив объектов, аналогичный тому, который функция принимает в качестве аргумента, либо целое число

Однако ваши комментарииниже этот ответ, кажется, предполагает, что это не (всегда) так. Это может быть простой объект, который объясняет, почему вы использовали Object.values для его итерации. Если это так, я хотел бы изменить getAdjacentCells, чтобы он действительно возвращал массив. Или, если это невозможно, используйте Object.values, как вы уже сделали:

function isCellEmpty(adjacentCells) {
    // I would move this check here, although not necessary if you prefer it in the loop.
    if (typeof adjacentCells === "number") {
        $("#" + id).empty().append("<div>"); // You can chain jQuery...
        return;
    } 
    for (let id of Object.values(adjacentCells)) { // Just use a for..of loop
        if (id === null) continue; // keep IF-ELSE nesting flat.
        let cell = board[getBoardPosition(id)];
        if (cell.opened) continue; // Add this to avoid circling around
        cell.opened = true;
        isCellEmpty(getAdjacentCells(id)); // recursive call
    }
}
...