《掃雷》是一款大眾類的益智小游戲,于1992年發(fā)行。游戲目標是在最短的時間內(nèi)根據(jù)點擊格子出現(xiàn)的數(shù)字找出所有非雷格子,同時避免踩雷,踩到一個雷即全盤皆輸。
以上就是掃雷的介紹,來源百度百科。 我在網(wǎng)上找了幾個掃雷游戲,對于這樣一個游戲我們不僅僅要實現(xiàn)其基礎(chǔ)的功能,還要為了提升游戲性,我們需要實現(xiàn)兩個功能 1.當(dāng)?shù)谝粋€為炸彈時,我們需要將炸彈移動到別的地方,防止游戲一開始就結(jié)束 2.當(dāng)我們選擇的位置周邊不存在炸彈,同時以九宮格的方式擴撒,將周邊不存在炸彈的地方展開,這樣可以大大的減去不必要的游戲過程,提高游戲的效率與可玩性。
這是我在CSDN上實現(xiàn)的第三個小游戲,這個游戲與前幾個很相似,我們可以借用前幾個的界面和框架來完成這個游戲 1.https://blog.csdn.net/qq_35423154/article/details/101311952猜數(shù)字游戲 2.https://blog.csdn.net/qq_35423154/article/details/102490244三子棋游戲
首先我們需要明確思路,我們可以用兩個棋盤來實現(xiàn)這個游戲,一個用來存放炸彈,一個用來給玩家顯示炸彈的位置及周圍的炸彈數(shù),這樣一個二維的棋盤我們可以使用二維數(shù)組來實現(xiàn)。
二維數(shù)組的建立及初始化 例如我們要使用一個9X9的棋盤,我們這時候應(yīng)當(dāng)建立一個11X11的即(N+2)x(N+2)的棋盤 這是我們顯示的9X9的棋盤 但是我們實際建立的是這樣一個棋盤 為什么我們需要在每一個邊界擴大一行呢?因為如果當(dāng)我們要判斷周圍的雷數(shù)時,如果不擴大,對于邊界的格子可能要判斷周圍兩個位置,四個位置,而不在邊界的要判斷八個位置,我們需要增加多種條件,為了簡化算法,我們可以采用整體擴大一圈,來保證每一個格子周圍都有八個格子,而邊上擴大的那一圈僅僅輔助計算,不顯示也不作用。 宏定義棋盤及炸彈 我們設(shè)置好行數(shù)和列數(shù)之后,再在其基礎(chǔ)上設(shè)置一個輔助棋盤既周圍擴大一圈的棋盤,分別在行數(shù)及列數(shù)的基礎(chǔ)上加二,然后我們設(shè)置炸彈數(shù),用宏定義的好處是后期修改時方便
#define ROW 9
#define COL 9#define ROWS ROW+2
#define COLS COL+2#define BOMBSNUM 10
#define SAFENUM ROW*COL-BOMBSNUM
初始化棋盤 我們需要兩個棋盤,一個給用戶進行游戲,一個用來存放炸彈。給用戶游戲的我們?nèi)砍跏蓟癁椤?’,存放炸彈的全部初始化為‘0’
void InitBoard(char Board[ROWS][COLS], int row, int col,char ch)
{int i, j;for (i = 0; i < row; i++){for (j = 0; j < col; j++){Board[i][j] = ch;}}
}
用字符0和1來代表炸彈可以方便我們后面計算周圍的炸彈
放置炸彈
void SetBombs(char Bombs[ROWS][COLS], int row, int col, int Bombsnum)
{int x, y,count=0;while( count < Bombsnum ){x = rand() % row+1;y = rand() % col+1;if (Bombs[x][y] != '1'){Bombs[x][y] = '1';count++;}}
}
使用rand函數(shù)來獲取一個隨機的坐標,當(dāng)坐標不重復(fù)并且所處位置沒有炸彈時,將炸彈存放
選擇菜單
void GameMenu()
{printf("*****************************************\n");printf("********* 1.開始游戲 *********\n");printf("********* 0.結(jié)束游戲 *********\n");printf("*****************************************\n");
}
顯示棋盤
void ShowBoard(char Board[ROWS][COLS], int row, int col)
{int i, j;printf(" ");for (i = 0; i < row+1; i++){printf("%d ",i);}printf("\n");for (i = 0; i < row; i++){if (0 == i)printf(" |");elseprintf("|");printf("---");}printf("|\n");for (i = 0; i < row; i++){for (j = 0; j < col; j++){if (0 == j){printf(" ");printf("%d ", i + 1);printf("|");}printf(" %c |", Board[i+1][j+1]);}printf("\n");for (j = 0; j < col; j++){if ( 0 == j )printf(" |");printf("---|");}printf("\n");}
}
用這個函數(shù)來向玩家展示棋盤,這里用了大量的代碼其實是我為了讓棋盤更加美觀,可根據(jù)情況修改。 以上的幾個函數(shù)在上一個三子棋游戲中都詳細講解過,在這里就不再多提
計算周圍的炸彈數(shù) 因為我們之前初始化時將用字符1代表有炸彈,字符0代表沒有炸彈,所以在這一部我們可以利用這個規(guī)律,來計算周圍的炸彈數(shù)。 我們只需要讓選擇的位置周邊的八個格子全部相加,然后減去8個字符0,即可得到整形的炸彈數(shù),而后在主函數(shù)給其加上一個字符0將其將這個數(shù)字變?yōu)樽址偷膶?yīng)數(shù)字,存放與棋盤中
int BombsAround(char Bombs[ROWS][COLS], int row, int col)
{return Bombs[row - 1][col] + Bombs[row + 1][col] + Bombs[row][col - 1] + Bombs[row][col + 1] + Bombs[row + 1][col + 1] + Bombs[row - 1][col - 1] + Bombs[row + 1][col - 1] + Bombs[row - 1][col + 1] - 8 * '0';
}
勝利條件
int WinGame(char Board[ROWS][COLS], int row, int col)
{int i, j, flag=0;for (i=1; i < row; i++){for (j = 1; j < col; j++){if (Board[i][j] == '*')flag++;}}return flag;
}
我們只需要計算棋盤中剩余的炸彈數(shù),當(dāng)剩余炸彈數(shù)等于我們的放置炸彈數(shù)時,游戲勝利
附加功能1.當(dāng)?shù)谝淮螢檎◤棔r,將炸彈移動到別的位置 這個函數(shù)實現(xiàn)的方法很簡單,我們只需要將那個位置的炸彈清空,再次調(diào)用SetBombs函數(shù)重新設(shè)置一個炸彈即可
int BombsAround(char Bombs[ROWS][COLS], int row, int col)
{return Bombs[row - 1][col] + Bombs[row + 1][col] + Bombs[row][col - 1] + Bombs[row][col + 1] + Bombs[row + 1][col + 1] + Bombs[row - 1][col - 1] + Bombs[row + 1][col - 1] + Bombs[row - 1][col + 1] - 8 * '0';
}
附加功能2.當(dāng)我們選擇的位置周邊不存在炸彈,同時以九宮格的方式擴撒,將周邊不存在炸彈的地方展開 這項功能是windows系統(tǒng)掃雷自帶的一個功能,當(dāng)我們選擇一個周圍沒有炸彈的位置時,以九宮格擴撒,將不存在炸彈的格子顯示為空,直到有一個格子周圍存在炸彈。 這個很簡單我們就可以想到用遞歸函數(shù)來完成,我們只需要用BombsAround函數(shù)來知道這個位置是否存在炸彈,如果不存在則顯示為‘ ’,如果存在則顯示炸彈數(shù)。我們可以用遞歸的方式,當(dāng)位置合法時,對他周圍的八個格子進行判斷,那八個格子再對他們周圍的格子進行判斷
void SafeArea(char Board[ROWS][COLS], char Bombs[ROWS][COLS], int row, int col)
{int flag;flag = BombsAround(Bombs, row, col);if (0 == flag){Board[row][col] = ' ';if (row - 1 > 0 && row + 1 <= ROW && col > 0 && col <= COL && Board[row - 1][col] == '*')SafeArea(Board, Bombs, row-1, col);if (row + 1 > 0 && row + 1 <= ROW && col > 0 && col <= COL && Board[row +1 ][col] == '*')SafeArea(Board, Bombs, row+1, col);if (row > 0 && row <= ROW && col - 1 > 0 && col - 1 <= COL && Board[row][col - 1] == '*')SafeArea(Board, Bombs, row, col-1);if (row > 0 && row <= ROW && col + 1 > 0 && col + 1 <= COL && Board[row][col + 1] == '*')SafeArea(Board, Bombs, row, col+1);if (row - 1 > 0 && row - 1 <= ROW && col - 1 > 0 && col - 1 <= COL && Board[row - 1][col - 1] == '*')SafeArea(Board, Bombs, row-1, col-1);if (row + 1 > 0 && row + 1 <= ROW && col + 1 > 0 && col + 1 <= COL && Board[row + 1][col + 1] == '*')SafeArea(Board, Bombs, row+1, col+1);if (row - 1 > 0 && row - 1 <= ROW && col + 1 > 0 && col + 1 <= COL && Board[row - 1][col + 1] == '*')SafeArea(Board, Bombs, row-1, col+1);if (row + 1 > 0 && row + 1 <= ROW && col - 1 > 0 && col - 1 <= COL && Board[row + 1][col - 1] == '*')SafeArea(Board, Bombs, row+1, col-1);}else{Board[row][col] = BombsAround(Bombs, row, col) + '0';}
}
排查炸彈
char FindBombs(char Board[ROWS][COLS], char Bombs[ROWS][COLS], int row, int col)
{int x, y,count=1;while(count){printf("請輸入行和列:\n");scanf("%d%d",&x,&y);system("CLS");if (x > 0 && x <= row && y > 0 && y <= col){if (Bombs[x][y] == '1'){if (1 == count){MoveBomb(Bombs, x, y);Board[x][y] = BombsAround(Bombs, x, y) + '0';if (Board[x][y] == '0')Board[x][y] = ' ';SafeArea(Board, Bombs, x, y);count++;}else{ShowBoard(Bombs, ROW, COL);return 'F';}}else if (Board[x][y] >= '0' && Board[x][y] <= '8' && Board[x][y] != '*' && Board[x][y] != ' '){printf("該坐標已被輸入\n");}else{Board[x][y] = BombsAround(Bombs, x, y) + '0';SafeArea(Board, Bombs, x, y);count++;if (WinGame(Board, ROW, COL) == BOMBSNUM)return 'T';ShowBoard(Board, ROW, COL);}}else{printf("輸入錯誤,請重新輸入\n");}}
}
我們需要判斷輸入是否合法,輸入是否重復(fù),如果錯誤則重新輸入,當(dāng)輸入的位置為炸彈時,如果是第一次輸入,則將炸彈移動到別的位置,如果不是第一次輸入,則代表游戲失敗,返回’F’。每次輸入完一個位置,我們將那個位置周圍的炸彈數(shù)保存到Board棋盤中,既玩家看到的棋盤,然后再使用展開函數(shù)來展開周圍不必要的格子,并且用WinGame函數(shù)判斷是否勝利
游戲控制函數(shù)
void Game(char Board[ROWS][COLS],char Bombs[ROWS][COLS], int row, int col)
{char flag;InitBoard(Board, ROWS, COLS, '*');InitBoard(Bombs, ROWS, COLS, '0');SetBombs(Bombs, ROW, COL, BOMBSNUM);ShowBoard(Board, ROW, COL);printf("\n");ShowBoard(Bombs, ROW, COL);flag = FindBombs(Board, Bombs, ROW, COL);if (flag == 'F'){printf("該位置為炸彈,游戲結(jié)束\n");}else{printf("游戲勝利\n");}
}
這一步只需調(diào)用前面寫完的函數(shù)即可
完整代碼 game.c
#include "head.h"void GameMenu()
{printf("*****************************************\n");printf("********* 1.開始游戲 *********\n");printf("********* 0.結(jié)束游戲 *********\n");printf("*****************************************\n");
}void InitBoard(char Board[ROWS][COLS], int row, int col,char ch)
{int i, j;for (i = 0; i < row; i++){for (j = 0; j < col; j++){Board[i][j] = ch;}}
}
//初始化void SetBombs(char Bombs[ROWS][COLS], int row, int col, int Bombsnum)
{int x, y,count=0;while( count < Bombsnum ){x = rand() % row+1;y = rand() % col+1;if (Bombs[x][y] != '1'){Bombs[x][y] = '1';count++;}}
}
//放置炸彈void ShowBoard(char Board[ROWS][COLS], int row, int col)
{int i, j;printf(" ");for (i = 0; i < row+1; i++){printf("%d ",i);}printf("\n");for (i = 0; i < row; i++){if (0 == i)printf(" |");elseprintf("|");printf("---");}printf("|\n");for (i = 0; i < row; i++){for (j = 0; j < col; j++){if (0 == j){printf(" ");printf("%d ", i + 1);printf("|");}printf(" %c |", Board[i+1][j+1]);}printf("\n");for (j = 0; j < col; j++){if ( 0 == j )printf(" |");printf("---|");}printf("\n");}
}
//界面int BombsAround(char Bombs[ROWS][COLS], int row, int col)
{return Bombs[row - 1][col] + Bombs[row + 1][col] + Bombs[row][col - 1] + Bombs[row][col + 1] + Bombs[row + 1][col + 1] + Bombs[row - 1][col - 1] + Bombs[row + 1][col - 1] + Bombs[row - 1][col + 1] - 8 * '0';
}
//算出周圍的炸彈void MoveBomb(char Bombs[ROWS][COLS], int row, int col)
{Bombs[row][col] = '0';SetBombs(Bombs, ROW, COL, 1);
}
//防止玩家第一次選擇時遇到炸彈,將炸彈移動到別的位置void SafeArea(char Board[ROWS][COLS], char Bombs[ROWS][COLS], int row, int col)
{int flag;flag = BombsAround(Bombs, row, col);if (0 == flag){Board[row][col] = ' ';if (row - 1 > 0 && row + 1 <= ROW && col > 0 && col <= COL && Board[row - 1][col] == '*')SafeArea(Board, Bombs, row-1, col);if (row + 1 > 0 && row + 1 <= ROW && col > 0 && col <= COL && Board[row +1 ][col] == '*')SafeArea(Board, Bombs, row+1, col);if (row > 0 && row <= ROW && col - 1 > 0 && col - 1 <= COL && Board[row][col - 1] == '*')SafeArea(Board, Bombs, row, col-1);if (row > 0 && row <= ROW && col + 1 > 0 && col + 1 <= COL && Board[row][col + 1] == '*')SafeArea(Board, Bombs, row, col+1);if (row - 1 > 0 && row - 1 <= ROW && col - 1 > 0 && col - 1 <= COL && Board[row - 1][col - 1] == '*')SafeArea(Board, Bombs, row-1, col-1);if (row + 1 > 0 && row + 1 <= ROW && col + 1 > 0 && col + 1 <= COL && Board[row + 1][col + 1] == '*')SafeArea(Board, Bombs, row+1, col+1);if (row - 1 > 0 && row - 1 <= ROW && col + 1 > 0 && col + 1 <= COL && Board[row - 1][col + 1] == '*')SafeArea(Board, Bombs, row-1, col+1);if (row + 1 > 0 && row + 1 <= ROW && col - 1 > 0 && col - 1 <= COL && Board[row + 1][col - 1] == '*')SafeArea(Board, Bombs, row+1, col-1);}else{Board[row][col] = BombsAround(Bombs, row, col) + '0';}
}int WinGame(char Board[ROWS][COLS], int row, int col)
{int i, j, flag=0;for (i=1; i < row; i++){for (j = 1; j < col; j++){if (Board[i][j] == '*')flag++;}}return flag;
}char FindBombs(char Board[ROWS][COLS], char Bombs[ROWS][COLS], int row, int col)
{int x, y,count=1;while(count){printf("請輸入行和列:\n");scanf("%d%d",&x,&y);system("CLS");if (x > 0 && x <= row && y > 0 && y <= col){if (Bombs[x][y] == '1'){if (1 == count){MoveBomb(Bombs, x, y);Board[x][y] = BombsAround(Bombs, x, y) + '0';SafeArea(Board, Bombs, x, y);count++;}else{ShowBoard(Bombs, ROW, COL);return 'F';}}else if (Board[x][y] >= '0' && Board[x][y] <= '8' && Board[x][y] != '*' && Board[x][y] != ' '){printf("該坐標已被輸入\n");}else{Board[x][y] = BombsAround(Bombs, x, y) + '0';SafeArea(Board, Bombs, x, y);count++;if (WinGame(Board, ROW, COL) == BOMBSNUM)return 'T';ShowBoard(Board, ROW, COL);}}else{printf("輸入錯誤,請重新輸入\n");}}
}
//排查炸彈void Game(char Board[ROWS][COLS],char Bombs[ROWS][COLS], int row, int col)
{char flag;InitBoard(Board, ROWS, COLS, '*');InitBoard(Bombs, ROWS, COLS, '0');SetBombs(Bombs, ROW, COL, BOMBSNUM);ShowBoard(Board, ROW, COL);printf("\n");flag = FindBombs(Board, Bombs, ROW, COL);if (flag == 'F'){printf("該位置為炸彈,游戲結(jié)束\n");}else{printf("游戲勝利\n");}
}
test.c
#include "head.h"int main()
{int n;char board[ROWS][COLS] = { 0 };char bombs[ROWS][COLS] = { 0 };srand((int)time(NULL));do{GameMenu();printf("請輸入您的選擇:\n");scanf("%d", &n);switch (n){case 1:Game(board, bombs, ROWS, COLS);break;case 0:printf("結(jié)束游戲\n");break;default:printf("輸入錯誤,請重新輸入\n");break;}}while (n);return 0;
}
head.h
#define _CRT_SECURE_NO_WARNINGS
#pragma once#include<stdio.h>
#include<stdlib.h>
#include<time.h>#define ROW 9
#define COL 9#define ROWS ROW+2
#define COLS COL+2#define BOMBSNUM 10void GameMenu();void InitBoard(char Board[ROWS][COLS], int row, int col, char ch);void SetBombs(char Bombs[ROWS][COLS], int row, int col, int Bombsnum);void ShowBoard(char Board[ROWS][COLS], int row, int col);int BombsAround(char Bombs[ROWS][COLS], int row, int col);char FindBombs(char Board[ROWS][COLS], char Bombs[ROWS][COLS], int row, int col);void Game(char Board[ROWS][COLS], char Bombs[ROWS][COLS], int row, int col);void MoveBomb(char Bombs[ROWS][COLS], int row, int col);void OpenMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y);void SafeArea(char Board[ROWS][COLS], char Bombs[ROWS][COLS], int row, int col);
代碼鏈接: https://github.com/HONGYU-LEE/test/tree/master/project/Mine%20sweeper
總結(jié)
以上是生活随笔 為你收集整理的C语言程序设计 | 扫雷游戏 的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔 推薦給好友。