2015-12-18 1 views
0

J'écris un jeu de dragueur de mines. Voici le code pour 3 méthodes dans dragueur de mines. La première méthode consiste à vérifier tous les espaces autour du bouton et à compter le nombre de bombes qui l'entourent. La méthode suivante doit être appelée récursivement, afin que si l'utilisateur appuie sur un bouton avec 0 boutons autour de lui, il ouvrira tous les carrés qui indiquent également 0 carrés autour de lui. La troisième méthode consiste à vérifier que le contrôle sera lié. L'appel récursif d'espace vide m'obtient une erreur de stackoverflow, qu'est-ce que je fais mal?récursive stackoverflow minesweeper C#

Merci!

private int GameLogicChecker(int x, int y) 
    { 
     int count = 0; 
     if (_grid[x, y] != -1) 
     { 
      if (x + 1 < SizeX) 
      { //Right 
       if (_grid[x + 1, y] == -1) 
        count++; 
      } 
      if (x - 1 > 0) 
      { //Left 
       if (_grid[x - 1, y] == -1) 
        count++; 
      } 
      if (y + 1 < SizeY) 
      { //Upper 
       if (_grid[x, y + 1] == -1) 
        count++; 
      } 
      if (y - 1 > 0) 
      { //Lower 
       if (_grid[x, y - 1] == -1) 
        count++; 
      } 
      if (x + 1 < SizeX && y + 1 < SizeY) 
      { //Right-Upper 
       if (_grid[x + 1, y + 1] == -1) 
        count++; 
      } 
      if (x + 1 < SizeX && y - 1 > 0) 
      { //Right-Lower 
       if (_grid[x + 1, y - 1] == -1) 
        count++; 
      } 
      if (x - 1 > 0 && y + 1 < SizeY) 
      { //Left-Upper 
       if (_grid[x - 1, y + 1] == -1) 
        count++; 
      } 
      if (x - 1 > 0 && y - 1 > 0) 
      { //Left-Lower 
       if (_grid[x - 1, y - 1] == -1) 
        count++; 
      } 
     } 
     return count; 
    } 

    void OpenEmptySpace(int x, int y) 
    { 
     for (var k = -1; k <= 1; k++) 
     { 
      for (var l = -1; l <= 1; l++) 
      { 
       if (CheckBounds(x + k, y + l) && GameLogicChecker(x + k, y + l) == 0) 
       { 
        _buttons[x + k, y + l].Text = "0"; 
        OpenEmptySpace(x + k, y + l); 
       } 
      } 
     } 
    } 

    private bool CheckBounds(int x, int y) 
    { 
     return x >= 0 && x < SizeX && y >= 0 && y < SizeY; 
    } 
+4

Avez-vous essayé de parcourir votre code pour observer son comportement et ses valeurs transitoires? –

+2

Lorsque k vaut 0 et que l vaut 0 et si la case if est true, vous appelez OpenEmtpySpace à nouveau avec les valeurs initiales x et y et vous créez une boucle sans fin. –

+1

En effet, 'OpenEmptySpace' est codé pour ne jamais mettre fin à la récursivité ... Pas vraiment sûr pourquoi vous attendez autrement. –

Répondre

3

Pour k = 0 et l = 0, vous vous appelez encore et encore et encore ...


Merci à @BenVoigt de remarquer que deux zéros adjacents les uns aux autres conduira également à une récursion infinie. Donc, pour résoudre cette méthode, il faut aussi créer une grille booléenne et définir la valeur d'une cellule particulière à true si elle a été exécutée une fois. En supposant que la grille est appelée Explored, j'ai ajouté la condition pour cela dans le code ci-dessous.


Si vous insistez sur votre code actuel, essayez de changer la condition:

if (CheckBounds(x + k, y + l) 
    && GameLogicChecker(x + k, y + l) == 0 
    && !(k == 0 && l == 0) 
    && !Explored[x + k, y + l]) 
{ 
    Explored[x + k, y + l] = true; 
    _buttons[x + k, y + l].Text = "0"; 
    OpenEmptySpace(x + k, y + l); 
} 
+2

@displayName: Vous aurez toujours une récursion infinie si vous avez deux zéros adjacents l'un à l'autre. –

+1

Notez que 'CheckBounds (5,5)' va appeler 'CheckBounds (5,6)' et alors il appellera 'CheckBound (5,5)' et ainsi de suite si les deux ont zéro bombes autour d'eux. – juharr

+0

@BenVoigt: Merci pour votre contribution, j'ai mis à jour la réponse et crédité à vous. – displayName

1

Voici une autre réponse pour vous, réécrire vos méthodes une par une suite de meilleures pratiques de codage. Comme dans l'autre réponse, une grille booléenne appelée Explored[SizeX, SizeY] a été supposée.


1. GameLogicChecker()

private int GameLogicChecker(int x, int y) 
{ 
    if (_grid[x, y] == -1) return 0; 
    int count = 0; 
    if (x + 1 < SizeX && _grid[x + 1, y] == -1) //Right 
    { 
     count++; 
    } 
    if (x - 1 > 0 && _grid[x - 1, y] == -1) //Left 
    { 
     count++; 
    } 
    if (y + 1 < SizeY && _grid[x, y + 1] == -1) //Upper 
    { 
     count++; 
    } 
    if (y - 1 > 0 && _grid[x, y - 1] == -1) //Lower 
    { 
     count++; 
    } 
    if (x + 1 < SizeX && y + 1 < SizeY && _grid[x + 1, y + 1] == -1) //Right-Upper 
    { 
     count++; 
    } 
    if (x + 1 < SizeX && y - 1 > 0 && _grid[x + 1, y - 1] == -1) //Right-Lower 
    { 
     count++; 
    } 
    if (x - 1 > 0 && y + 1 < SizeY && _grid[x - 1, y + 1] == -1) //Left-Upper 
    { 
     count++; 
    } 
    if (x - 1 > 0 && y - 1 > 0 && _grid[x - 1, y - 1] == -1) //Left-Lower 
    { 
     count++; 
    } 
    return count; 
} 

Quoi de mieux? Retour plus rapide de la méthode pour cas particulier. Nidification réduite dans Si (...) blocs.


2. OpenEmptySpace()

public/private void OpenEmptySpace(int x, int y) 
{ 
    for (var deltaX = -1; deltaX <= 1; deltaX += 2) 
    { 
     for (var deltaY = -1; deltaY <= 1; deltaY += 2) 
     { 
      var thisX = x + deltaX; 
      var thisY = y + deltaY; 
      if (OpeningNotNeeded(thisX, thisY)) 
      { 
       continue; 
      } 
      Explored[thisX, thisY] = true; 
      _buttons[thisX, thisY].Text = "0"; 
      OpenEmptySpace(thisX, thisY); 
     } 
    } 
} 

private bool OpeningNotNeeded(int x, int y) 
{ 
    return !CheckBounds(x, y) 
      || GameLogicChecker(x, y) != 0 
      || Explored[x, y]; 
} 

Quoi de mieux? Indiquez correctement les variables d'indexation dans les deux boucles. Condition correctement écrite (+= 2 au lieu de ++). Nidification réduite dans Si (...). Plus facile à lire appel de méthode dans le Si (...) au lieu de trois prédicats. Ajout de variables temporaires utiles qui précisent ce que x + k et y + l étaient dans le code écrit précédemment.


3. CheckBounds() est écrit très bien.