2 votes

Pourquoi les valeurs ne sont-elles pas affectées correctement à mon tableau ?

J'essaie de résoudre ce problème de leetcode (jeu de la vie) : https://leetcode.com/problems/game-of-life

Voici mon code :

function isLive(board: number[][], row: number, column: number) {
  let liveNeighbours = 0;
  [row - 1, row, row + 1].forEach(r => {
    if (r < 0 || r >= board.length) return;
    [column - 1, column, column + 1].forEach(c => {
      if (c === column && r === row) return;
      if (c < 0 || c >= board[0].length) return;
      if (board[r][c] === 1) liveNeighbours++
    })
  })

  if (board[row][column] === 1 && (liveNeighbours === 3 || liveNeighbours === 2)) return true;
  if (board[row][column] === 0 && liveNeighbours === 3) return true;

  return false;
}

/**
Do not return anything, modify board in-place instead.
*/
function gameOfLife(board: number[][]): void {

  let nextGen = Array(board.length).fill(Array(board[0].length).fill(0));

  for (let i = 0; i < board.length; i++) {
    for (let j = 0; j < board[0].length; j++) {
      console.log("isLive row ", i, " col ", j, isLive(board, i, j))
      if (isLive(board, i, j)) nextGen[i][j] = 1
    }
  }

  console.log("next gen", nextGen);

  board = nextGen;
};

J'exécute le code avec cette entrée :

[
 [0,1,0],
 [0,0,1],
 [1,1,1],
 [0,0,0]
]

Et il produit ceci (la même chose en gros) :

[
 [0,1,0],
 [0,0,1],
 [1,1,1],
 [0,0,0]
]

Alors qu'il s'attend à ça :

[
 [0,0,0],
 [1,0,1],
 [0,1,1],
 [0,1,0]
]

Ce qui me rend vraiment fou, ce sont les journaux d'impression. Lorsque j'imprime chaque cellule, qu'elle soit active ou non, le résultat est parfaitement conforme à ce qu'il devrait être. Voici le journal :

isLive row  0  col  0 false
isLive row  0  col  1 false
isLive row  0  col  2 false
isLive row  1  col  0 true
isLive row  1  col  1 false
isLive row  1  col  2 true
isLive row  2  col  0 false
isLive row  2  col  1 true
isLive row  2  col  2 true
isLive row  3  col  0 false
isLive row  3  col  1 true
isLive row  3  col  2 false

De plus, dans le dernier journal d'impression de nextGen, il y a ceci : next gen [ [ 1, 1, 1 ], [ 1, 1, 1 ], [ 1, 1, 1 ], [ 1, 1, 1 ] ] Ainsi, toutes les cellules sont réassignées à 1, même si je peux voir que toutes les déclarations ne sont pas vraies.

Ce qui ne ressemble à rien. Il ne correspond pas au retour individuel que j'obtiens pour chaque cellule, et ne correspond même pas à ce qu'il prétend que je renvoie, même si c'est essentiellement à la fin. Est-ce que j'ai raté quelque chose sur la façon d'assigner des valeurs aux tableaux ?

EDIT : Au lieu de simplement assigner board=nextGen J'ai également essayé ce qui suit :

for (let i = 0; i < board.length; i++) {
    for (let j = 0; j < board[0].length; j++) {
        board[i][j] = nextGen[i][j];
    }
}

J'obtiens maintenant ceci comme résultat [[1,1,1],[1,1,1],[1,1,1],[1,1,1]] (le prit de nextGen).

EDIT 2 : J'ai essayé de changer la fonction pour qu'elle renvoie simplement le nombre de voisins et faire le conditionnement après. Bien que je n'aie pas encore déplacé le conditionnement, je peux déjà voir qu'il y a toujours un problème avec l'assignation des éléments au nouveau tableau.

Voici mon code modifié (encore une fois, il n'est pas complet, mais le reste n'est pas pertinent pour le problème à ce stade) :

function countNeighbors(board: number[][], row:number, column:number){
    let liveNeighbors = 0;
    [row-1, row, row+1].forEach(r=>{
        if(r<0 || r>= board.length) return;
        [column-1, column, column+1].forEach(c=>{
            if(c === column && r=== row) return;
            if(c<0 || c>= board[0].length) return;
            if(board[r][c]===1) liveNeighbors++
        })
    })

    return liveNeighbors;
}

/**
 Do not return anything, modify board in-place instead.
 */
function gameOfLife(board: number[][]): void {

let neighbors = Array(board.length).fill(Array(board[0].length).fill(0));

    for (let i = 0; i<board.length; i++){
        for (let j = 0; j<board[0].length; j++){
            let numberOfNeighbors = countNeighbors(board,i,j);
            console.log(i, j, numberOfNeighbors)
            neighbors[i][j] = numberOfNeighbors
        }
        console.log("neighbors", neighbors)
    }
};

J'ai ajouté un journal de console après chaque itération de i et voici ce qu'il imprime :

0 0 1
0 1 1
0 2 2
neighbors [ [ 1, 1, 2 ], [ 1, 1, 2 ], [ 1, 1, 2 ], [ 1, 1, 2 ] ]
1 0 3
1 1 5
1 2 3
neighbors [ [ 3, 5, 3 ], [ 3, 5, 3 ], [ 3, 5, 3 ], [ 3, 5, 3 ] ]
2 0 1
2 1 3
2 2 2
neighbors [ [ 1, 3, 2 ], [ 1, 3, 2 ], [ 1, 3, 2 ], [ 1, 3, 2 ] ]
3 0 2
3 1 3
3 2 2
neighbors [ [ 2, 3, 2 ], [ 2, 3, 2 ], [ 2, 3, 2 ], [ 2, 3, 2 ] ]

En fait, chaque ligne est dupliquée sur toutes les lignes. Cela semble être ce qui perturbe ma fonction, quelle que soit la façon dont je l'ai fait, mais pourquoi cela se produit-il ?

Est-ce que ça a quelque chose à voir avec le comportement de fill ?

Edit 3 : Ok, donc je suis sur la façon dont le nouveau tableau est créé. Si je le crée comme ceci pour mon cas de test : let neighbors = [[],[],[],[]]; Ensuite, tout fonctionne parfaitement.

J'aimerais cependant savoir quelle est la cause de ce comportement ? Existe-t-il un moyen efficace de créer ce tableau sans que cela ne se produise ? Je peux simplement pousser de nouveaux tableaux vides pour chaque itération de i tout en fonctionnant et en n'étant pas très gourmand, mais j'ai pensé que la façon dont je l'ai fait en premier était plus élégante.

1voto

Kai O. Points 31

En gros, ce qui se passe ici, c'est qu'en function gameOfLife() lorsque vous attribuez board = nextGen; vous ne faites qu'attribuer le board variable (le nom) dans la fonction pour faire référence à l'objet nextGen mais ne modifient pas les données dans board . En gros, vous faites le nom board se référer à nextGen tout en laissant les données auxquelles on se référait auparavant par board la même chose.

Ce que tu dois faire, c'est qu'au lieu de dire board = , utilisez des méthodes pour copier les données contenues dans nextGen a board . Voici donc un moyen simple de le faire :

~~for (let i = 0; i < board.length; i++) { board[i] = nextGen[i]; }~~

Editar:

Étant donné qu'à l'origine, nextGen semblait être correct lors de l'impression pour chaque cellule, c'est très étrange. Je pourrais essayer de m'assurer que les parenthèses et les points-virgules sont tous inclus, juste pour garantir que le flux de contrôle de toutes les instructions if fonctionne comme prévu, puisqu'il n'y a qu'un seul endroit où nextGen devrait pouvoir être réglé sur 1 et l'instruction if voisine ne devrait parfois pas l'inclure.

Sinon, pourquoi ne pas essayer une toute autre stratégie qui n'utiliserait pas une nextGen du tout. Ce que vous pourriez essayer de faire, c'est qu'au lieu de créer un nouveau plateau pour la prochaine génération, il suffit d'obtenir le nombre de voisins de chaque tuile. Ensuite, vous pouvez modifier directement le plateau en fonction des règles relatives au nombre de voisins et à la valeur de vie actuelle sans avoir à vous soucier de la copie des données. Donc :

let neighbors = Array(board.length).fill(Array(board[0].length).fill(0));

// ============================================================================================================
// Put the code for finding the number of neighbors here, inserting it into the corresponding spot in neighbors
// ============================================================================================================

for (let i = 0; i < board.length; i++) {
    for (let j = 0; j < board[0].length; j++) {
        if (board[i][j] === 1) { // Only change things if conditions are met for death
            if (neighbors[i][j] < 2 || 3 < neighbors [i][j]) {
                board[i][j]--;
            }
        } else { // === 0; only change things if conditions are met for new life
            if (neighbors[i][j] === 3 {
                board[i][j]++;
            }
        }
    }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X