首页 > 解决方案 > C语言中的扫雷算法

问题描述

所以我在班上有一个项目,必须用 C 语言制作一个 8X8 扫雷程序。我们还没有学习递归,所以现在还不是完整的游戏......

规则:你输入一个坐标,如果你击中了炸弹——你输了。如果您没有击中炸弹,则会显示一个数字 - 此特定单元格周围的炸弹数量。如果您在没有击中炸弹的情况下清除棋盘,您就赢了。此外,我们的老师让我们在代码中包含一个“作弊”——这就是我开始有点困惑的地方。如果坐标以 -1 开头,他输入的下一个值将是第一个不是地雷的单元格。所以,我的想法是做一个计数器,++只要细胞不是炸弹就可以。问题是,当他再次输入 -1、x 和 -1 时,第二个 x 将无法按预期打开。这是代码,相关块是 if (cordChecker(col, row) == 10) 中的块。

顺便说一句,由于某种原因,它会在不打算打印时打印“:”...在此先感谢。如果我的帖子有问题,我很抱歉,这是我第一次在这里发帖。

`#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <string.h>
#define COLS_1 8
#define ROWS_1 8
void printBoard(char arr[][ROWS_1]); // gets a minesweeper board and prints it 
void boardInit(char arr[][ROWS_1]); // initializing a board with 'X's.
void gameOn(int col, int row, char arr[][ROWS_1], char arr2[][ROWS_1]); // gets coordinates from the user, and gets 2 arrays: a hidden board
                                                                        // with the bombs in it, and a board the user can see. 
                                                                        // the function uses other functions in order to get the game going.
int welcomeUser(); // welcome message
void minePlacer(char arr[][ROWS_1], int arrLength); // gets an empty board and mines it.
int cordChecker(int col, int row); // gets column and row from user. Returns 1 if valid and 0 if not. (0<=x<=7 are valid options)
int mineCounter(int col, int row, char arr[][ROWS_1]);  // gets an array and a coordinate, and counts the nearby mines.
void youLose(char arr[][ROWS_1]); // prints the hidden board and delivers a you lose message.
void printNumMines(char arr[][ROWS_1], char arr2[][ROWS_1], int col, int row); // printing the number of mines surrounding a cell.

void main()
{
    int userChoice, row, col;
    userChoice = welcomeUser();
    srand(time(NULL));
    srand(time(NULL));
    while (userChoice != 1)
    {
        if (userChoice == 0)
            break;
        userChoice = welcomeUser();
    }
    if (userChoice == 1)
    {
        char arr[COLS_1][ROWS_1];                   // Creating the hidden board (the one with bombs)
        char arr2[COLS_1][ROWS_1];                  // Creating the board the user will see
        boardInit(arr);                             // initializing both boards with 'X'
        boardInit(arr2);
        minePlacer(arr, ROWS_1);                    // mining the hidden board
        printBoard(arr2);
        printf("Please enter your move, column and row:\n"); 
        scanf("%d%d", &col, &row);
        gameOn(col, row, arr, arr2);
    }
}

void minePlacer(char arr[][ROWS_1], int arrLength)
{
    int i;
    if (arrLength == ROWS_1)
    {
        for (i = 0; i < ROWS_1; i++)
            arr[i][rand() % (ROWS_1-1)] = '*';
    }
}
int cordChecker(int col, int row)
{
    if (col == -1) // If the user wants to win fast
    {
        return 10;
    }
        if ((col >= COLS_1 || col < 0) || (row >= ROWS_1 || row < 0))              // user chose invalid coordinates
            return 0;
        else if ((col < COLS_1 - 1 && col >= 1) && (row < ROWS_1 - 1 && row >= 1)) // checking if the coordinates are not on boundaries.
            return 1;
        else if (col == 0 && (row != 0 && row != ROWS_1 - 1))                      // user chose (0,x) 0<x<7 
            return 2;
        else if ((col != 0 && col != COLS_1 - 1) && row == 0)                      // user chose (x,0) 0<x<7 
            return 3;
        else if (col == 0 && row == 0)                                             // user chose (0,0)
            return 4;
        else if (col == COLS_1 - 1 && row == ROWS_1 - 1)                           // user chose (7,7)
            return 5;
        else if (col == COLS_1 - 1 && (row != ROWS_1 - 1 && row != 0))             // user chose (7,x) 0<x<7 
            return 6;
        else if ((col != COLS_1 - 1 && row != 0) && row == ROWS_1 - 1)             // user chose (x,7) 0<x<7 
            return 7;
        else if (col == COLS_1 - 1 && row == 0)                                    // user chose (7,0)
            return 8;
        else if (col == 0 && row == ROWS_1 - 1)                                    // user chose (0,7)
            return 9;


}

void printBoard(char arr[][ROWS_1])
{
    int i, j;
    printf("\n");
    printf("       0   1   2   3   4   5   6   7  \n");
    printf("   ___________________________________\n");
    for (i = 0; i < COLS_1; i++)
    {
        printf("   %d | ", i);
        for (j = 0; j < ROWS_1; j++)
        {
            printf("%c", arr[i][j]);
            printf(" | ");
        }
        printf("\n");

    }
    printf("   ___________________________________\n");
}
int welcomeUser()
{
    int userChoice;
    printf("Welcome to Minesweeper!\n\n");
    printf("Please choose one of the following options and enter its number:\n\n");
    printf("1 - for size 8X8\n\n");
    printf("2 - for size 12X12\n\n");
    printf("3 - for size 15X15\n\n");
    printf("4 - for custom size\n\n");
    printf("0 - Exit\n\n");
    scanf("%d", &userChoice);
    return userChoice;
}
void boardInit(char arr[][ROWS_1])
{
    int i, j;
    for (i = 0; i < COLS_1; i++)
    {
        for (j = 0; j < ROWS_1; j++)              // Creating a minesweeper board with "X"s.
        {
            arr[i][j] = 'X';
        }
    }


}
void gameOn(int col, int row, char arr[][ROWS_1], char arr2[][ROWS_1])
{
    int countSquares = 0, count = 0, temp = row;
    while (cordChecker(col, row) == 0)
    {
        printf("Invalid coordinates, please try again\n");
        scanf("%d%d", &col, &row);
    }
    while (cordChecker(col, row) != 0)
    {
        if ((arr2[col][row] != 'X')&&(col!=-1))
            printf("Invalid move, please enter another move!\n");
        if (col != -1)
        {
            if (arr[col][row] == '*')
            {
                youLose(arr);
                break;
            }
        }
        else if (countSquares >= 56)
        {
            printf("YOU WIN\n");
            break;
        }
        printNumMines(arr, arr2, col, row);
        printBoard(arr2);
        if (cordChecker(col, row) == 10)
        {
            int i, j;
            printf("\n");
            printf("       0   1   2   3   4   5   6   7  \n");
            printf("   ___________________________________\n");
            for (i = 0; i < COLS_1; i++)
            {
                printf("   %d | ", i);
                for (j = 0; j < ROWS_1; j++)
                {
                    if (count < temp)
                    {
                        if (arr[i][j] == '*')
                        {
                            printf("%c", arr2[i][j]);
                            printf(" | ");
                            
                        }
                        else
                        {
                            printNumMines(arr, arr2, i, j);
                            printf("%c", arr2[i][j]);
                            printf(" | ");
                            count++;
                        }
                    }
                    else
                    {

                            printf("%c", arr2[i][j]);
                            printf(" | ");
                            count++;
                    }
                    
                    

                }
                printf("\n");

            }
            printf("   ___________________________________\n");
            countSquares = countSquares+row;
            

        }
        
        countSquares++;
        if (countSquares > 56)
        {
            printf("YOU WIN\n");
            break;
        }
        printf("Please enter your move, column and row:\n");
        scanf("%d%d", &col, &row);
        temp = temp + row;
    }
}
void printNumMines(char arr[][ROWS_1], char arr2[][ROWS_1], int col, int row)
{
    if (mineCounter(col, row, arr) == 0)
        arr2[col][row] = ' ';
    else
        arr2[col][row] = (char)(mineCounter(col, row, arr) + '0');

}
void youLose(char arr[][ROWS_1])
{
    int i, j;
    printf("\n");
    printf("       0   1   2   3   4   5   6   7  \n");
    printf("   ___________________________________\n");
    for (i = 0; i < COLS_1; i++)
    {
        printf("   %d | ", i);
        for (j = 0; j < ROWS_1; j++)
        {   
            if ((arr[i][j] != '*') && mineCounter(i, j, arr) == 0)        // if the cell is not a mine and is not surrounded by mines, replace it with ' '
                arr[i][j] = ' ';
            else if (arr[i][j] != '*')                                    // if the cell is not a mine but surrounded by mines, count them
                arr[i][j] = (char)(mineCounter(i, j, arr) + '0');
            printf("%c", arr[i][j]);                                      // print the cell
            printf(" | ");  
        }
        printf("\n");
    }
    printf("   ___________________________________\n");
    printf("YOU LOSE\n");
}

int mineCounter(int col, int row, char arr[][ROWS_1])
{
    int mines = 0;
    switch (cordChecker(col, row))
    {
    case 1:

        // Checking the following directions: up, down, left, right
        if (arr[col - 1][row] == '*')
            mines++;
        if (arr[col + 1][row] == '*')
            mines++;
        if (arr[col][row - 1] == '*')
            mines++;
        if (arr[col][row + 1] == '*')
            mines++;

        // Checking diagonal directions
        if (arr[col - 1][row + 1] == '*')
            mines++;
        if (arr[col - 1][row - 1] == '*')
            mines++;
        if (arr[col + 1][row + 1] == '*')
            mines++;
        if (arr[col + 1][row - 1] == '*')
            mines++;

        return mines;

    case 2:

        // Checking the following directions: up, down, left, right
        if (arr[col][row - 1] == '*')
            mines++;
        if (arr[col][row + 1] == '*')
            mines++;
        if (arr[col + 1][row] == '*')
            mines++;

        // Checking diagonal directions
        if (arr[col + 1][row - 1] == '*')
            mines++;
        if (arr[col + 1][row + 1] == '*')
            mines++;
        return mines;

    case 3:

        // Checking the following directions: up, down, left, right
        if (arr[col][row + 1] == '*')
            mines++;
        if (arr[col - 1][row] == '*')
            mines++;
        if (arr[col + 1][row] == '*')
            mines++;

        // Checking diagonal directions
        if (arr[col + 1][row + 1] == '*')
            mines++;
        if (arr[col - 1][row + 1] == '*')
            mines++;
        return mines;

    case 4:

        // Checking the following directions: up, down, left, right
        if (arr[col][row + 1] == '*')
            mines++;
        if (arr[col + 1][row] == '*')
            mines++;

        // Checking diagonal directions
        if (arr[col + 1][row + 1] == '*')
            mines++;
        return mines;

    case 5:

        // Checking the following directions: up, down, left, right
        if (arr[col][row - 1] == '*')
            mines++;
        if (arr[col - 1][row] == '*')
            mines++;

        // Checking diagonal directions
        if (arr[col - 1][row - 1] == '*')
            mines++;
        return mines;

    case 6:

        // Checking the following directions: up, down, left, right
        if (arr[col][row - 1] == '*')
            mines++;
        if (arr[col][row + 1] == '*')
            mines++;
        if (arr[col - 1][row] == '*')
            mines++;

        // Checking diagonal directions
        if (arr[col - 1][row - 1] == '*')
            mines++;
        if (arr[col - 1][row + 1] == '*')
            mines++;

        return mines;

    case 7:

        // Checking the following directions: up, down, left, right
        if (arr[col][row - 1] == '*')
            mines++;
        if (arr[col - 1][row] == '*')
            mines++;
        if (arr[col + 1][row] == '*')
            mines++;

        // Checking diagonal directions
        if (arr[col + 1][row - 1] == '*')
            mines++;
        if (arr[col - 1][row - 1] == '*')
            mines++;
        return mines;

    case 8:

        // Checking the following directions: up, down, left, right
        if (arr[col][row + 1] == '*')
            mines++;
        if (arr[col - 1][row] == '*')
            mines++;

        // Checking diagonal directions

        if (arr[col - 1][row + 1] == '*')
            mines++;
        return mines;

    case 9:

        // Checking the following directions: up, down, left, right
        if (arr[col][row - 1] == '*')
            mines++;
        if (arr[col + 1][row] == '*')
            mines++;

        // Checking diagonal directions
        if (arr[col + 1][row - 1] == '*')
            mines++;
        return mines;

    }
}
    
`

标签: arrayscminesweeper

解决方案


问题是,当他再次输入 -1、x 和 -1 时,第二个 x 将无法按预期打开。

至少有这些问题:

阵列外访问

代码尝试arr2[-1][row],可能尝试访问外部arr2col != -1之前执行更有意义arr2[col][row] != 'X'

while (cordChecker(col, row) != 0) {
  if ((arr2[col][row] != 'X') && (col != -1))  // bad

不清楚由于混合使用的row, colvs。x,y

选择一对或另一对,并在整个代码和文档中使用。

控制到达非空函数的结尾

两者cordChecker(), mineCounter()都没有在所有情况下都清楚地返回一个值。一个良好启用的编译器报告。

警告:控制到达非 void 函数的结尾 [-Wreturn-type]

代码可以在每个末尾添加以下内容,以帮助代码永远不会到达该路径。

  assert(0);
  return 0;
}

...或者更好的是,重新编写以清楚地始终在所有路径中返回一个值。

不处理不当输入

scanf("%d%d", &col, &row);当输入为"-1, 0".

代码需要处理','和/或 OP 需要发布使用的真实输入。

次要:冗余代码

无需打 2 个电话,一个就行

srand(time(NULL));
// srand(time(NULL));

转换为安静的unsigned转换警告“警告:从 'time_t' {aka 'long int'} 到 'unsigned int' 的转换可能会改变值 [-Wconversion]”

srand((unsigned) time(NULL));

代码将因简化而受益

使用这种有界网格的一个简单“技巧”:使网格在所有 4 个边上都变大(10x10)。不要在外缘放置地雷。只允许用户在内部方块中移动。然后检查内板不需要边界检查。

提示:启用所有编译器警告


推荐阅读