Member 13527254 Ответов: 1

Как реализовать рекурсию в этой программе сапера?


У меня есть задача реализовать рекурсию в моделируемой игре сапера в С Он должен в основном вызывать себя, чтобы очистить соседние ячейки, если это возможно сделать. Я был бы признателен за любую помощь в указании на ошибку в моем алгоритме. И, пожалуйста, имейте в виду, что я изучал программирование только в течение 6 недель, поэтому я могу не понимать продвинутых объяснений. Спасибо!

(PS: Я хотел бы опубликовать фактический вопрос, но, похоже, здесь это сделать невозможно)

Что я уже пробовал:

#include <stdio.h>
#include <stdbool.h>
#define ROW 16 //max number of rows 
#define COL 30 //max number of columns

void readBoard(int board[][COL], int m, int n);
void printBoard(int board[][COL], int m, int n);
int countNeighbour(int board[][COL], int r, int c, int m, int n);
bool isValid(int r, int c, int m, int n);
bool allCleared(int board[][COL], int m, int n);
void clearNeighbours(int board[][COL], int r, int c, int m, int n); 

int main(void) {
   int r, c, m, n, board[ROW][COL]={{0}}; //initializes all values to 0

   scanf("%d%d", &m, &n);
   readBoard(board, m, n); // reads the board.
   do {
      scanf("%d%d", &r, &c);     
      if(board[r][c] < 9  && isValid(r,c,m,n) == true) { // checks for mines presence and location validity
         if(countNeighbour(board, r, c, m, n) == 0) {
            clearNeighbours(board, r, c, m, n);
         }
      } else break; // escape the loop if the conditions are not fulfilled
   } while (allCleared(board,m,n) == false); // checks if all safe locations are cleared

   printBoard(board, m, n);
   return 0;
}

/* 
  allCleared checks the board and returns true if all safe locations
  have been cleared, false otherwise.
*/
bool allCleared(int board[][COL], int m, int n) {
   int i,j;
   for(i=0; i<m; i++) {
      for(j=0; j<n; j++) {
         if(board[i][j] == -1) {
            return false;
         }
      }
   }
   return true;
}

/* 
  isValid checks if the input location is valid or not.
*/
bool isValid(int r, int c, int m, int n) {
   if(r>=0 && r<=m && c>=0 && c<=n) {
      return true;
   }
   return false;
}   

/* 
 readBoard reads the input of the location of the mines and safe locations
 and stores the values inside an array.
 Precondition: the input values must be either -1 or 9.
*/
void readBoard(int board[][COL], int m, int n) {
   int i,j;
   for(i=0; i<m; i++) {
      for(j=0; j<n; j++) {
         scanf("%d", &board[i][j]);
      }
   }
}

/* 
 printBoard prints the minesweeper board. "*" represents mines 
 and "." represents safe locations. Numbers from 0 to 8 represents
 the number of mines present in the neighbouring cells.
*/
void printBoard(int board[][COL], int m, int n) {
   int i, j;
   for(i=0; i<m; i++) {
      for(j=0; j<n; j++) {
         if(board[i][j] == -1) {
            printf(".");
         }
         else if( board[i][j] >= 9) {
            printf("*");
         } else {
            printf("%d", board[i][j]);
         }
      }
      printf("\n");
   }
}

/* 
  countNeighbour checks the specified location for neighbouring mines,
  returns the number of mines present. P.S: I hard coded this part during the lab
  so I had no choice but to leave it as it is.
  Precondition: the specified location is inside the board
*/
int countNeighbour(int board[][COL], int r, int c, int m, int n) {
   if(board[r][c]!=-1) return board[r][c]; //returns if the location contains a mine or it has been checked
   
   if(isValid(r-1,c,m,n) && board[r-1][c] == 9) {
      board[r][c]++;
   }  
   if(isValid(r-1,c-1,m,n) && board[r-1][c-1] == 9) {
      board[r][c]++;
   }
   if(isValid(r,c-1,m,n) && board[r][c-1] == 9) {
      board[r][c]++;
   }
   if(isValid(r+1,c+1,m,n) && board[r+1][c+1] == 9) {
      board[r][c]++;
   }
   if(isValid(r,c+1,m,n) && board[r][c+1] == 9) {
      board[r][c]++;
   }
   if(isValid(r+1,c,m,n) && board[r+1][c] == 9) {
      board[r][c]++;
   }
   if(isValid(r+1,c-1,m,n) && board[r+1][c-1] == 9) {
      board[r][c]++;
   }
   if(isValid(r-1,c+1,m,n) && board[r-1][c+1] == 9) {
      board[r][c]++;
   }

   board[r][c]++; //since safe locations are denoted by -1, increments regardless of mines' presence.
   return board[r][c];
}

/* 
 clearNeighbours clear neighbouring cells, while making sure
 that they are inside the board. Calls itself repeatedly until
 all possible neighboring cells are cleared
 Precondition: the input location must be a safe location.
*/
void clearNeighbours(int board[][COL], int r, int c, int m, int n) {
   int row[] = {1,0,-1,0,1,1,-1,-1}; //temp array to check all 8 neighbouring cells row
   int col[] = {0,1,0,-1,1,-1,1,-1}; //temp array to check the column
   int i;

   countNeighbour(board,r,c,m,n);
   if(board[r][c] != 8) return;  
   for(i = 0;i<8;i++) { //loop terminates if all neighboring safe cells are cleared 
      int nextRow =  r + row[i], nextCol = c + col[i];
      if(isValid(nextRow,nextCol,m,n) && board[r][c] == -1) {
         clearNeighbours(board,nextRow,nextCol,m,n); //clears the safe cells repeatedly
      }
   }
} 

Graeme_Grant

Это возвращает меня назад ... У меня есть код, чтобы сделать это где-то... Я посмотрю, смогу ли найти его и опубликую в виде статьи... Если я правильно помню, это было гораздо проще сделать с одним массивом измерений...

Member 13527254

одномерный массив, как в случае многократной очистки соседних ячеек? Конечно я был бы признателен за любую помощь

1 Ответов

Рейтинг:
2

Patrice T

Вы должны это понять C массивы основаны на нуле
Это означает, что в массиве размером 30 допустимые индексы находятся в диапазоне от 0 до 29.
Поскольку вы этого не поняли, вы считаете соседей за пределами доски.
Вы не можете сказать, работает ли рекурсивная часть или нет, пока она использует глючные подпрограммы.

Использование отладчика должно быть большим подспорьем для проверки того, что происходит.

Существует инструмент, который позволяет вам видеть, что делает ваш код, его имя отладчик Это также отличный инструмент обучения, потому что он показывает вам реальность, и вы можете увидеть, какие ожидания соответствуют реальности.
Когда вы не понимаете, что делает ваш код или почему он делает то, что он делает, ответ таков: отладчик.
Используйте отладчик, чтобы увидеть, что делает ваш код. Просто установите точку останова и посмотрите, как работает ваш код, отладчик позволит вам выполнять строки 1 на 1 и проверять переменные по мере их выполнения.

Отладчик - Википедия, свободная энциклопедия[^]

Освоение отладки в Visual Studio 2010 - руководство для начинающих[^]
Базовая отладка с помощью Visual Studio 2010 - YouTube[^]
Отладчик здесь, чтобы показать вам, что делает ваш код, и ваша задача-сравнить с тем, что он должен делать.
В отладчике нет никакой магии, он не находит ошибок, он просто помогает вам. Когда код не делает того, что ожидается, вы близки к ошибке.
[Обновление]

Цитата:
Я не думаю, что это правда, поскольку я реализовал функцию isValid, чтобы проверить, находится ли массив за пределами границ или нет. Я считаю, что в моей реализации рекурсии есть ошибка

Не думайте, не верьте, используйте отладчик и убедитесь.


Member 13527254

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