arrays - 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;
}
}
`
解决方案
问题是,当他再次输入 -1、x 和 -1 时,第二个 x 将无法按预期打开。
至少有这些问题:
阵列外访问
代码尝试arr2[-1][row]
,可能尝试访问外部arr2
。col != -1
之前执行更有意义arr2[col][row] != 'X'
。
while (cordChecker(col, row) != 0) {
if ((arr2[col][row] != 'X') && (col != -1)) // bad
不清楚由于混合使用的row, col
vs。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)。不要在外缘放置地雷。只允许用户在内部方块中移动。然后检查内板不需要边界检查。
提示:启用所有编译器警告
推荐阅读
- linux - 自动化 bash 脚本
- java - Android Studio Java 从 getLastTimeUsed 重写代码 getTotalTimeInForeground
- angular - Promise.all() 使用 RxJs.Observable
- r - 在 R 中转换为日期格式时出错
- java - 如何在java中读取文件时动态创建嵌套对象?
- c++ - 复制具有多态内容的 std::unique_ptr 的 std::map
- node.js - 从 package-lock.json 创建 package.json
- netty - EventLoop 在 netty 中是如何工作的?
- excel - 将数据从excel导入Oracle DB中的多个表
- android - 使用 API 密钥限制时 Android SafetyNet API 失败