在电脑还是Windows xp和Windows 7的时代,想必很多人都一定会接触到一款很经典的游戏,扫雷游戏。简单的界面,易上手的难度,不用上网即可游玩的模式,让它大受欢迎。虽然现在Windows 10系统上已不再默认安装扫雷游戏,但我们却可以通过自己编写代码的方式,来回味我们曾经游玩时的感受。但由于本人目前能力有限,仅能实现由键盘输入的方式,来实现位置的确认。
大概思路
首先,我们需要明确扫雷游戏的规则。我们通过键盘输入坐标的方式,来确定位置排雷,若此位置有雷,则游戏结束,若此位置没有雷,则游戏继续,并显示周围地雷的个数。若我们将所有没有地雷的地方确认后,埋有地雷的所有地方也都知道了,则玩家胜利。 然后,我们可以去思考如何去实现了。因为地雷的数据不能让玩家在游玩时知道,且玩家输入的数据需要存储,同时显示在面板上的数据应该是周围地雷的数量,两者并不相同,基于以上两个原因,我们需要创建两个二维数组,一个用于显示未排雷的地方和周围地雷的数量,命名为show_board,另一个用于存储地雷的位置,命名为mine_board。 但还有个很关键的地方,若我们想展示出一个66的面板,我们是该创建两个66的二维数组吗?这样虽然是最符合我们最直接的想法,但随之而来的问题也有了。若玩家输入的坐标位于面板的边框,如最上面的一行,我们在计算周围地雷数量的时候,则不需要检测上面一行的数据,但若是在最下面一行,则不需要检测下面的一行,甚至若是在左上角,则上面和左边的一行都不需要检测了,这会对我们编写检测周围地雷数的代码有很大的麻烦。因此我们需要在外面再加上一圈,则创建一个8*8的数组,在显示和存储时,都会方便不少。 接着,我们可以编写我们需要的功能函数了。我们需要的功能函数应该有:显示目录的函数Menu,埋下地雷的函数SetMines,显示面板的函数ShowBoard,计算周围地雷数量的函数CountMines,执行游戏相关命令的函数Game。当我们梳理出思路后,便可以上手编写程序了。
功能函数
显示目录的函数Menu
该函数用于向玩家提供游玩或者退出的选项。
void Menu()
{
printf("########################\n");
printf("# 1. Play 0.Exit #\n");
printf("########################\n");
}
埋下地雷的函数SetMines
取出两个随机数作为坐标,将其所指向的位置赋值,则为埋下地雷。同时,定义宏定义,将地雷的个数NUM定义为20,方便后期程序维护时修改。
#define NUM 20
static void SetMines(char board[][COL], int row, int col)
{
int count = NUM;
while (count){
int x = rand() % (row - 2) + 1;
int y = rand() % (col - 2) + 1;
if (board[x][y] == '0'){
board[x][y] = '1';
count--;
}
}
}
显示面板的函数ShowBoard
将show_board中所有值通过循环显示出来。因为每行都要显示出表的下边框,为了方便和美观,单独写一个函数ShowLine来显示出下边框。定义两个宏定义ROW和COL来表示创建的数组的行和列。
#define ROW 8
#define COL 8
static void ShowBoard(char board[][COL], int row, int col)
{
printf(" ");
for (int i = 1; i <= (col - 2); i++){
printf("%d ", i);
}
printf("\n");
ShowLine(col);
for (int i = 1; i <= (row - 2); i++){
printf("%-3d|", i);
for (int j = 1; j <= (col - 2); j++){
printf(" %c |", board[i][j]);
}
printf("\n");
ShowLine(col);
}
}
static void ShowLine(int col)
{
for (int i = 0; i <= (col - 2); i++){
printf("----");
}
printf("\n");
}
计算周围地雷数量的函数CountMines
此函数则为将所指向的坐标的座位8个位置的数据全部相加,则为周围所有地雷的数量。因为一个位置在没有埋下地雷的时候,其所显示的值为0,在埋下地雷后,显示的值被改为1,将8个位置的值相加,但我们存入的值为char型,所以还需要减去7个‘0’的值,才能真正表示出周围地雷的数量。
static char CountMines(char board[][COL], int x, int y)
{
return board[x - 1][y - 1] + board[x - 1][y] + board[x - 1][y + 1] + \
board[x][y + 1] + board[x + 1][y + 1] + board[x + 1][y] + \
board[x + 1][y - 1] + board[x][y - 1] - 7 * '0';
}
执行游戏相关命令的函数Game
首先我们我们需要向玩家展示出面板,让玩家输入一个坐标,然后判断此坐标是否合法,则判断此坐标是否超出面板限制的范围,和判断是否已被占用,若出现以上两种情况,则需要显示出相关的提示语句。为了玩家查看提示语句方便,则将提示语句放在下一次显示面板钱,同时使用选择语句,来显示不同的提示语句。若坐标合法,则判断此坐标是否有雷,有雷则游戏结束,没有雷则将坐标所只想到的位置赋值。当面板上已无除地雷外的位置时,游戏胜利。
#define ROW 8
#define COL 8
#define STYLE '?'
#define NUM 20
void Game()
{
srand((unsigned long)time(NULL));
char show_board[ROW][COL];
char mine_board[ROW][COL];
memset(show_board, STYLE, sizeof(show_board));
memset(mine_board, '0', sizeof(mine_board));
SetMines(mine_board, ROW, COL);
int count = (ROW - 2)*(COL - 2) - NUM;
int error = 0;
while (count){
system("cls");
if (error == 1){
printf("Postion Error!\n");
}
else if(error == 2){
printf("Postion Is not *\n");
}
ShowBoard(show_board, ROW, COL);
printf("Please Enter Your Postion<x,y># ");
int x = 0;
int y = 0;
scanf("%d %d", &x, &y);
if (x < 1 || x > ROW - 2 || y < 1 || y > COL - 2){
error = 1;
continue;
}
if (show_board[x][y] != STYLE){
error = 2;
continue;
}
if (mine_board[x][y] == '1'){
printf("game over!\n");
ShowBoard(mine_board, ROW, COL);
break;
}
error = 0;
show_board[x][y] = CountMines(mine_board, x, y);
count--;
}
if (!count){
printf("You win!\n");
}
}
主调函数main
先显示目录,让玩家输入其想执行的操作,并执行相应的命令。
int main()
{
int quit = 0;
int select = 0;
while (!quit){
Menu();
printf("Please Enter# ");
scanf("%d", &select);
switch (select){
case 1:
Game();
break;
case 0:
quit = 1;
break;
default:
printf("Postion Error, Try Again!\n");
break;
}
}
printf("byebye!\n");
system("pause");
return 0;
}
至此,所有三子棋的程序都已经编写完毕,后面为将前面所有代码合在一起的结果。
合集
合集中game.h文件中,主要为宏定义和函数的声明;game.c文件中为所有功能函数的编写;main.c文件中为主调函数的编写。
clear_mine.h文件
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <windows.h>
#define ROW 8
#define COL 8
#define STYLE '?'
#define NUM 20
extern void Game();
extern void Menu();
clear_mine.c文件
#include "clear_mine.h"
void Menu()
{
printf("########################\n");
printf("# 1. Play 0.Exit #\n");
printf("########################\n");
}
static void SetMines(char board[][COL], int row, int col)
{
int count = NUM;
while (count){
int x = rand() % (row - 2) + 1;
int y = rand() % (col - 2) + 1;
if (board[x][y] == '0'){
board[x][y] = '1';
count--;
}
}
}
static void ShowLine(int col)
{
for (int i = 0; i <= (col - 2); i++){
printf("----");
}
printf("\n");
}
static void ShowBoard(char board[][COL], int row, int col)
{
printf(" ");
for (int i = 1; i <= (col - 2); i++){
printf("%d ", i);
}
printf("\n");
ShowLine(col);
for (int i = 1; i <= (row - 2); i++){
printf("%-3d|", i);
for (int j = 1; j <= (col - 2); j++){
printf(" %c |", board[i][j]);
}
printf("\n");
ShowLine(col);
}
}
static char CountMines(char board[][COL], int x, int y)
{
return board[x - 1][y - 1] + board[x - 1][y] + board[x - 1][y + 1] + \
board[x][y + 1] + board[x + 1][y + 1] + board[x + 1][y] + \
board[x + 1][y - 1] + board[x][y - 1] - 7 * '0';
}
void Game()
{
srand((unsigned long)time(NULL));
char show_board[ROW][COL];
char mine_board[ROW][COL];
memset(show_board, STYLE, sizeof(show_board));
memset(mine_board, '0', sizeof(mine_board));
SetMines(mine_board, ROW, COL);
int count = (ROW - 2)*(COL - 2) - NUM;
int error = 0;
while (count){
system("cls");
if (error == 1){
printf("Postion Error!\n");
}
else if(error == 2){
printf("Postion Is not *\n");
}
ShowBoard(show_board, ROW, COL);
printf("Please Enter Your Postion<x,y># ");
int x = 0;
int y = 0;
scanf("%d %d", &x, &y);
if (x < 1 || x > ROW - 2 || y < 1 || y > COL - 2){
error = 1;
continue;
}
if (show_board[x][y] != STYLE){
error = 2;
continue;
}
if (mine_board[x][y] == '1'){
printf("game over!\n");
ShowBoard(mine_board, ROW, COL);
break;
}
error = 0;
show_board[x][y] = CountMines(mine_board, x, y);
count--;
}
if (!count){
printf("You win!\n");
}
}
main.c文件
#include "clear_mine.h"
int main()
{
int quit = 0;
int select = 0;
while (!quit){
Menu();
printf("Please Enter# ");
scanf("%d", &select);
switch (select){
case 1:
Game();
break;
case 0:
quit = 1;
break;
default:
printf("Postion Error, Try Again!\n");
break;
}
}
printf("byebye!\n");
system("pause");
return 0;
}
|