Problème fonction récursive

Résolu/Fermé
lenouveau82 Messages postés 53 Date d'inscription mercredi 7 décembre 2016 Statut Membre Dernière intervention 30 juillet 2024 - 6 mars 2022 à 14:58
mamiemando Messages postés 33446 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 décembre 2024 - 28 avril 2022 à 14:41
Salut à tous ! Je viens vers vous parce que j'ai un petit soucis dans un programme en C. Je suis en train de coder un démineur, et je souhaite créer une fonction capable de découvrir toutes les cases jusqu'à rencontrer une mine. C'est une fonction qu'un professeur m'avait fait coder il y a longtemps, mais en me repenchant dessus j'ai un soucis : bien qu'il n'y ai pas d'erreur de compilation, le programme plante au moment d'exécuter la fonction. La voici :
int DiscoverCells(int k, int n, int tab[NB_ROW][NB_COL]){
	int l=0, m=0, nbMines=0;

	if(tab[k][n]==MINE)return 10;
	mSetPlayed(tab[k+m][n+l]);
	for(m=-1;m<=1;m++){
		for(l=-1;l<=1;l++){
			if((k+m>=0)&&(n+l>=0)&&(k+m<NB_ROW)&&(n+l<NB_COL)&&(mCellValue(tab[k+m][n+l])!=MINE)){
				nbMines+=DiscoverCells(k+m, n+l, tab);
				return 1;
			}
		}
	}
	return nbMines;
}


et voici la partie de code qui l'appelle :

while(1){
		for(k=0;k<NB_ROW;k++){
			for(n=0;n<NB_COL;n++){
				if(!mIsPlayed(tab[k][n])){
					printf(".\t");
				}
				else if(mCellValue(tab[k][n])==9){
					printf("%c\t", CELL_MINE_CHAR);
				}
				else{
					printf("%d\t", mCellValue(tab[k][n]));
				}
			}
			printf("\n\n");
		}
		scanf("%d", &l);
		scanf("%d", &m);
		DiscoverCells(l, m, tab);
	}


Merci d'avance pour vos réponses

4 réponses

yg_be Messages postés 23405 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 20 décembre 2024 Ambassadeur 1 557
6 mars 2022 à 15:20
bonjour, sans l'énoncé de l'exercice et sans commentaire, il est difficile de comprendre à quoi sert le code que tu as écrit.
0
lenouveau82 Messages postés 53 Date d'inscription mercredi 7 décembre 2016 Statut Membre Dernière intervention 30 juillet 2024
6 mars 2022 à 15:47
Merci de ta réponse. Pour l'énoncé de l'exercice, il s'agit juste de faire un démineur. Sinon voilà pour les commentaires :

while(1){ // On fait apparaitre le tableau à l'infini à chaque entrée de case. La condition doit être remplacée une fois que le programme contera les cases découvertes.
		//Le programme affiche le tableau en mettant des points à la place des cases cachées et des étoiles à la place des mines (si la case est découverte).
		for(k=0;k<NB_ROW;k++){
			for(n=0;n<NB_COL;n++){
				if(!mIsPlayed(tab[k][n])){
					printf(".\t");
				}
				else if(mCellValue(tab[k][n])==9){
					printf("%c\t", CELL_MINE_CHAR);
				}
				else{
					printf("%d\t", mCellValue(tab[k][n]));
				}
			}
			printf("\n\n");
		}
		//Le joueur entre la case qu'il souhaite découvrir et le programme appelle la fonction qui sert à découvrir les cases alentour jusqu'à trouver une mine.
		scanf("%d", &l);
		scanf("%d", &m);
		DiscoverCells(l, m, tab);
	}


int DiscoverCells(int k, int n, int tab[NB_ROW][NB_COL]){
	int l=0, m=0, nbMines=0;
	
	if(tab[k][n]==MINE)return 10; // si le joueur rentre les coordonnées d'une mine la fonction renvoi un code de Game Over
	mSetPlayed(tab[k+m][n+l]); //la fonction marque la case entrée en paramètres comme découverte (jouée)
	//La fonction se répète avec toutes les cases aux alentours jusqu'à rencontrer une mine ou un bord du tableau
	for(m=-1;m<=1;m++){
		for(l=-1;l<=1;l++){
			if((k+m>=0)&&(n+l>=0)&&(k+m<NB_ROW)&&(n+l<NB_COL)&&(mCellValue(tab[k+m][n+l])!=MINE)){
				nbMines+=DiscoverCells(k+m, n+l, tab);
				return 1;
			}
		}
	}
	return nbMines;
}

En espérant que ça convienne
0
yg_be Messages postés 23405 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 20 décembre 2024 1 557 > lenouveau82 Messages postés 53 Date d'inscription mercredi 7 décembre 2016 Statut Membre Dernière intervention 30 juillet 2024
6 mars 2022 à 16:07
Si je lis bien, aucune mine ne sera jamais marquée comme découverte.
As-tu partagé ton programme complet?
0
lenouveau82 Messages postés 53 Date d'inscription mercredi 7 décembre 2016 Statut Membre Dernière intervention 30 juillet 2024 > yg_be Messages postés 23405 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 20 décembre 2024
6 mars 2022 à 16:13
seulement la partie intéressante, le reste c'est juste la pose des mines et le marquage des cases autour (si y a une mine adjacente, la case aura la valeur 1, etc...). Sinon pourquoi tu penses qu'aucune mine ne sera marquée comme découverte ?
0
yg_be Messages postés 23405 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 20 décembre 2024 1 557 > lenouveau82 Messages postés 53 Date d'inscription mercredi 7 décembre 2016 Statut Membre Dernière intervention 30 juillet 2024
6 mars 2022 à 17:22
Qui a écrit ce code? Quels sont les endroits où une case est marquée comme découverte?
0
lenouveau82 Messages postés 53 Date d'inscription mercredi 7 décembre 2016 Statut Membre Dernière intervention 30 juillet 2024
6 mars 2022 à 18:21
C'est moi qui l'ai écrit, et c'est marqué à la ligne 5 de la fonction. mSetPlayed est une macro qui met un bit d'une variable à 1. Dans ce cas, il s'agit du 32ème bit d'une variable qui symbolise une case
0
yg_be Messages postés 23405 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 20 décembre 2024 1 557
6 mars 2022 à 18:46
Est-il possible que cette ligne 5 soit exécutée pour une mine?
0
lenouveau82 Messages postés 53 Date d'inscription mercredi 7 décembre 2016 Statut Membre Dernière intervention 30 juillet 2024 > yg_be Messages postés 23405 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 20 décembre 2024
6 mars 2022 à 19:18
Oui, mais dans le cadre de cette fonction soit ça renvoit un code de Game Over (la valeur 10) soit ça arrête la récursivité
0
yg_be Messages postés 23405 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 20 décembre 2024 1 557 > lenouveau82 Messages postés 53 Date d'inscription mercredi 7 décembre 2016 Statut Membre Dernière intervention 30 juillet 2024
6 mars 2022 à 19:21
Je ne pense pas qu'il soit possible que la ligne 5 soit exécutée pour une mine.
0
lenouveau82 Messages postés 53 Date d'inscription mercredi 7 décembre 2016 Statut Membre Dernière intervention 30 juillet 2024 > yg_be Messages postés 23405 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 20 décembre 2024
6 mars 2022 à 19:33
Pas dans cette fonction, puisque si le joueur sélection une mine la fonction renvoit "10" et ne marque pas la case comme jouée
0
yg_be Messages postés 23405 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 20 décembre 2024 Ambassadeur 1 557
6 mars 2022 à 20:10
ajoute des printf dans ton programme, afin de mieux comprendre comment il se comporte.
0
mamiemando Messages postés 33446 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 décembre 2024 7 812
8 mars 2022 à 18:25
Bonjour,

Ce qui est bizarre c'est que dans le démineur, on découvre les cases une par une et donc il n'y a pas de récursivité. La seule exception, c'est quand on clique sur une case avec aucune mine adjacente (donc si
mCellValue[i][j] == 0
en admettant que j'ai bien compris ton code). Dans ce cas le jeu de démineur sous windows découvre les cases voisines et répète le processus pour les éventuelles cases.

Quelle que soit la répétition que tu veux faire, il faut s'assurer que
  • ta récursion exprime, à partir d'une case, quelle case explorer ;
  • ta récursion se termine (n'engendre pas une boucle infinie) et idéalement ne re-déclenche pas des calculs déjà faits.


Si on se place dans le cas du démineur standard, si une case dont le nombre de bombes adjacentes 0 est dévoilée, alors on dévoile les cases voisines. Si l'une de ces cases voisine a également 0 bombe adjacentes, alors on répète le processus récursivement :

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#define X 9

int min(int x, int y) {
    return x < y ? x : y;
}

int max(int x, int y) {
    return x > y ? x : y;
}

void display(int **tab, int **played, size_t num_rows, size_t num_cols) {
    for (size_t i = 0; i < num_rows; i++) {
        for (size_t j = 0; j < num_cols; j++) {
            if (played[i][j]) {
                if (tab[i][j] == X) {
                    printf("*");
                } else {
                    printf("%d", tab[i][j]);
                }
            } else {
                printf(".");
            }
        }
        printf("\n");
    }
}

int ** calloc_matrix(size_t num_rows, size_t num_cols) {
    int ** matrix = (int **) malloc(sizeof(int *) * num_rows);
    if (matrix) {
        for (size_t i = 0; i < num_rows; i++) {
            matrix[i] = (int *) calloc(sizeof(int), num_rows);
        }
    }
    return matrix;
}

void free_matrix(int ** matrix, size_t num_rows) {
    if (matrix) {
        for (size_t i = 0; i < num_rows; i++) {
            if (matrix[i]) {
                free(matrix[i]);
            }
        }
        free(matrix);
    }
}

void play(int **tab, int **played, size_t num_rows, size_t num_cols, size_t k, size_t l) {
    played[k][l] = 1;
    if (tab[k][l] == 0) {
        for (size_t i = max(0, k - 1); i < min(num_rows, k + 2); i++) {
            for (size_t j = max(0, l - 1); j < min(num_cols, l + 2); j++) {
                if (!played[i][j]) {
                    play(tab, played, num_rows, num_cols, i, j);
                }
            }
        }
    }
}


int main(){
    const size_t num_rows = 4;
    const size_t num_cols = 5;

    int ** played = calloc_matrix(num_rows, num_cols);

    // X == mine
    // autre valeur == nombre de mines adjacentes
    int ** tab = calloc_matrix(num_rows, num_cols);
    tab[0][0] = 0; tab[0][1] = 0; tab[0][2] = 1; tab[0][3] = 1; tab[0][4] = 1;
    tab[1][0] = 0; tab[1][1] = 0; tab[1][2] = 2; tab[1][3] = X; tab[1][4] = 2;
    tab[2][0] = 1; tab[2][1] = 1; tab[2][2] = 2; tab[2][3] = X; tab[2][4] = 2;
    tab[3][0] = X; tab[3][1] = 1; tab[3][2] = 1; tab[3][3] = 1; tab[3][4] = 1;


    printf("Before:\n");
    display(tab, played, num_rows, num_cols);

    printf("\nAfter:\n");
    play(tab, played, num_rows, num_cols, 0, 0);
    display(tab, played, num_rows, num_cols);

    free_matrix(tab, num_rows);
    free_matrix(played, num_rows);
    return 0;
}

Résultat :

Before:
.....
.....
.....
.....

After:
001..
002..
112..
.....


Bonne chance
0
lenouveau82 Messages postés 53 Date d'inscription mercredi 7 décembre 2016 Statut Membre Dernière intervention 30 juillet 2024
10 mars 2022 à 08:33
Merci, désolé je n'avais pas vu que j'avais de nouvelles réponses. Cette histoire de valeur de case me donne une bonne idée pour conditionner ma fonction, merci
0
mamiemando Messages postés 33446 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 décembre 2024 7 812 > lenouveau82 Messages postés 53 Date d'inscription mercredi 7 décembre 2016 Statut Membre Dernière intervention 30 juillet 2024
Modifié le 10 mars 2022 à 15:01
Pour information, tu peux trier les messages par dates ce qui t'évitera de te faire avoir. Et les messages sont numérotés, donc s'il y a une flèche à droite du numéro, c'est que des messages sont apparus depuis.

Est-ce que la solution que je t'ai proposée te convient ? Est-ce que ton problème est résolu ? Si oui, voir ce lien. Et sinon, merci de nous indiquer ce qu'il reste à voir :-)

Bonne chance
0
lenouveau82 Messages postés 53 Date d'inscription mercredi 7 décembre 2016 Statut Membre Dernière intervention 30 juillet 2024 > mamiemando Messages postés 33446 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 décembre 2024
11 mars 2022 à 17:55
Merci, mais non ce n'est pas encore résolu ^^' je ne sais vraiment pas comment expliquer ça, mais finalement je pense que je vais essayer de trouver la solution seul :) merci quand même à tout le monde pour l'aide apportée
0
mamiemando Messages postés 33446 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 décembre 2024 7 812 > lenouveau82 Messages postés 53 Date d'inscription mercredi 7 décembre 2016 Statut Membre Dernière intervention 30 juillet 2024
Modifié le 11 mars 2022 à 18:18
Ok :-)

Dans ce cas je clos le sujet, car d'une part tu ne sembles plus attendre d'aide de notre part dans l'immédiat, et d'autre part, je pense que la réponse que je t'ai donnée dans le message #12 répond à ton problème ou du moins est adaptable pour faire ce que tu veux.

Bien entendu, si tu as besoin d'aide, n'hésite pas à revenir poster un message dans cette discussion ;-)
0
lenouveau82 Messages postés 53 Date d'inscription mercredi 7 décembre 2016 Statut Membre Dernière intervention 30 juillet 2024 > mamiemando Messages postés 33446 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 décembre 2024
28 avril 2022 à 11:35
Désolé de ma réponse (très) tardive, merci pour l'aide
0