说明
此篇博客将会不定期更新,不断添加C编写的小游戏
这个游戏我单独写了一篇博客,具体详细思路与完整代码见
链接: https://editor.csdn.net/md/?articleId=117386293.
在这里就不做详细介绍了,但在文末会附上三子棋的代码
相信各位读者对于扫雷都不陌生,这里就不再详细介绍。
主要分析一下实现思路:
既然是一款游戏,那必然少不了数据的存储,扫雷给我们的第一感觉就是用二维数组来存储了。
但是存储之后我们要进行判断时就会发现,这张表格(棋盘)的中间格子周围有8个其他格子,而边角位置就不一样了。这样对于我们编写函数得到某一格子周围有几颗雷就显得有些困难了。
所以我们应该定义一个二维数组没错,但是要定义一个比预留要用的棋盘更大的二维数组,这样上面所说的函数就会适用于每一个格子。
还有一个问题:
扫雷时用户看到的是自己输入坐标后对应的二维表,表中的数据都是周围未选择的STYLE和已经选择了的对应周围雷的个数,这样一来,我们布置雷的棋盘就不能在对应的位置显示了,因为会产生冲突。
所以:我们应该选用一张与对用户显示表完全相同的表来布置雷的位置
综上所述
第一:选择比预期更大一点的二维数组存储数据
例如:10*10的扫雷区域
#define ROW1 12
#define COL1 12
char Show_board[ROW1][COL1];
第二:雷的布置用同样规格的另一张表存储
char Mine_board[ROW1][COL1];
#define STYLE '*'
memset(Show_board, STYLE, sizeof(Show_board));
memset(Mine_board, '0', sizeof(Mine_board));
注意:memset为C语言内置的库函数,在头文件string.h下。
具体作用:将规定字节长度的数据按照传入的value值替换(按字节操作)
此操作在二维数组Mines_board[ROW1][COL1]下进行
#define NUM 20
static void SetMines(char Mine_board[][COL1], int row, int col)
{
int count = NUM;
while (count)
{
int x = rand() % (ROW1 - 2) + 1;
int y = rand() % (COL1 - 2) + 1;
if (Mine_board[x][y] == '0')
{
Mine_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 Show_board[][COL1], int row, int col)
{
printf(" ");
for (int i = 1; i <= col - 2; i++)
{
printf("%3d ", i);
}
printf("\n");
showline(col);
for (int i = 1; i <= row - 2; i++)
{
printf("%-2d |", i);
for (int j = 1; j <= col - 2; j++)
{
printf(" %c |", Show_board[i][j]);
}
printf("\n");
showline(col);
}
}
void FindMines()
{
srand((unsigned long)time(NULL));
char Show_board[ROW1][COL1];
char Mine_board[ROW1][COL1];
memset(Show_board, STYLE, sizeof(Show_board));
memset(Mine_board, '0', sizeof(Mine_board));
SetMines(Mine_board, ROW1, COL1);
//count表示用户需要扫雷成功的次数
//只有完成规定的次数用户才能赢
int count = (ROW1 - 2)*(COL1 - 2) - NUM;
while (count)
{
system("cls");
ShowBoard(Show_board, ROW1, COL1);
int x = 0;
int y = 0;
printf("Please Enter Your Choose#" );
scanf("%d %d", &x, &y);
if (x<1 || x>(ROW1 - 1) || y<1 || y>(COL1 - 1))
{
printf("Your Choose Is Error! Please Try Again\n");
continue;
}
if (Show_board[x][y] != STYLE)
{
printf("Your Choose Is Error! Please Try Again\n");
continue;
}
if (Mine_board[x][y] == '1')
{
printf("Game over!\n");
break;
}
//此条语句表示相对应的位置写入周围的雷数
Show_board[x][y] = CountMines(Mine_board, x, y);
count--;
}
ShowBoard(Mine_board, ROW1, COL1);
}
== CountMines(Mine_board, x, y)==求
static char CountMines(char Mine_board[][COL1], int x, int y)
{
//求出周围雷的个数,转换成字符表示
//例如有6颗雷就返回字符‘6’
char count = Mine_board[x - 1][y - 1] + Mine_board[x - 1][y] + Mine_board[x - 1][y + 1] + Mine_board[x][y + 1] \
+ Mine_board[x + 1][y + 1] + Mine_board[x + 1][y] + Mine_board[x + 1][y - 1] + Mine_board[x][y - 1] - 7 * '0';
return count;
}
扫雷完整代码如下:
FindMines.h
#pragma once
#include
#include
#include
#include
#define ROW1 12
#define COL1 12
#pragma warning(disable:4996)
#define STYLE '*'
#define NUM 20
extern void FindMines();
FindMines.c
#include "FindMines.h"
static void SetMines(char Mine_board[][COL1], int row, int col)
{
int count = NUM;
while (count)
{
int x = rand() % (ROW1 - 2) + 1;
int y = rand() % (COL1 - 2) + 1;
if (Mine_board[x][y] == '0')
{
Mine_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 Show_board[][COL1], int row, int col)
{
printf(" ");
for (int i = 1; i <= col - 2; i++)
{
printf("%3d ", i);
}
printf("\n");
showline(col);
for (int i = 1; i <= row - 2; i++)
{
printf("%-2d |", i);
for (int j = 1; j <= col - 2; j++)
{
printf(" %c |", Show_board[i][j]);
}
printf("\n");
showline(col);
}
}
static char CountMines(char Mine_board[][COL1], int x, int y)
{
char count = Mine_board[x - 1][y - 1] + Mine_board[x - 1][y] + Mine_board[x - 1][y + 1] + Mine_board[x][y + 1] \
+ Mine_board[x + 1][y + 1] + Mine_board[x + 1][y] + Mine_board[x + 1][y - 1] + Mine_board[x][y - 1] - 7 * '0';
return count;
}
void FindMines()
{
srand((unsigned long)time(NULL));
char Show_board[ROW1][COL1];
char Mine_board[ROW1][COL1];
memset(Show_board, STYLE, sizeof(Show_board));
memset(Mine_board, '0', sizeof(Mine_board));
SetMines(Mine_board, ROW1, COL1);
int count = (ROW1 - 2)*(COL1 - 2) - NUM;
while (count)
{
system("cls");
ShowBoard(Show_board, ROW1, COL1);
int x = 0;
int y = 0;
printf("Please Enter Your Choose#" );
scanf("%d %d", &x, &y);
if (x<1 || x>(ROW1 - 1) || y<1 || y>(COL1 - 1))
{
printf("Your Choose Is Error! Please Try Again\n");
continue;
}
if (Show_board[x][y] != STYLE)
{
printf("Your Choose Is Error! Please Try Again\n");
continue;
}
if (Mine_board[x][y] == '1')
{
printf("Game over!\n");
break;
}
Show_board[x][y] = CountMines(Mine_board, x, y);
count--;
}
ShowBoard(Mine_board, ROW1, COL1);
}
三子棋完整代码
ThreeGmae.h
# pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
#include
#include
#define ROW 3
#define COL 3
#define INIT ' '
#define WHITE 'X'
#define BLACK 'O'
#define NEXT 'D'
#define DRAW 0
extern void ThreeGame();
ThreeGame.c
#include "ThreeGame.h"
//初始化棋盘
static void Init(char board[][COL], int row, int col)
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
board[i][j] = INIT;
}
}
}
static void Showbard(char board[][COL], int row, int col)
{
system("cls");
printf(" ");
for (int i = 0; i <col; i++)
{
printf("%4d", i + 1);
}
printf("\n----------------\n");
for (int i = 0; i < row; i++)
{
printf("%-2d", i + 1);
for (int j = 0; j < col; j++)
{
printf("| %c ", board[i][j]);
}
printf("\n----------------\n");
}
}
static void PlayerMove(char board[][COL], int row, int col)
{
int x = 0;
int y = 0;
while (1)
{
printf("Please Enter Your Position#\n" );
scanf("%d %d", &x, &y);
if (x<1 || x>3 || y<1 || y>3)
{
printf("Enter Error! Try Again\n");
continue;
}
if (board[x - 1][y - 1] == INIT)
{
board[x - 1][y - 1] = WHITE;
break;
}
else
{
printf("This position is not empty,please enter again!\n");
}
}
}
static char IsEnd(char board[][COL], int row, int col)
{
//判断行
for (int i = 0; i < row; i++)
{
if (board[i][0] == board[i][1] && \
board[i][1] == board[i][2] && \
board[i][0] != INIT)
{
return board[i][0];
}
}
//判断列
for (int j = 0; j < col; j++)
{
if (board[0][j] == board[1][j] && \
board[1][j] == board[2][j] && \
board[0][j] != INIT)
{
return board[0][j];
}
}
//判断对角线
if (board[0][0] == board[1][1] && \
board[1][1] == board[2][2] && \
board[1][1] != INIT)
{
return board[1][1];
}
if (board[0][2] == board[1][1] && \
board[1][1] == board[2][0] && \
board[1][1] != INIT)
{
return board[1][1];
}
return NEXT;
}
static void ComputerMove(char board[][COL], int row, int col)
{
while (1)
{
int x = rand() % ROW;
int y = rand() % COL;
if (board[x][y] == INIT)
{
board[x][y] = BLACK;
break;
}
}
}
void ThreeGame()
{
srand((unsigned long)time(NULL));
char board[ROW][COL];
Init(board, ROW, COL);
char result = 0;
while (1)
{
Showbard(board, ROW, COL);
PlayerMove(board, ROW, COL);
result = IsEnd(board, ROW, COL);
if (result != NEXT)
{
break;
}
Showbard(board, ROW, COL);
ComputerMove(board, ROW, COL);
result = IsEnd(board, ROW, COL);
if (result != NEXT)
{
break;
}
}
Showbard(board, ROW, COL);
switch (result)
{
case WHITE:
printf("You Win\n");
break;
case BLACK:
printf("You lose\n");
break;
case DRAW:
printf("you == computer\n");
break;
default:
printf("Bug!\n");
break;
}
}
日常玩的小游戏,话不多说,直接进行思路分析!!
这与三子棋的实现方式基本相似,但又有不同!
选用二维数组int board[ROW][COL]
存储信息,其中ROW和COL为宏定义,分别表示行和列
将二维数组初始化为全零,在输出时判断若为0输出 .,如下图所示;
int board[ROW2][COL2] = {
0 };
用户1与用户2分别通过输入坐标
#define PLAYER1 1
#define PLAYER2 2
对于用户的每一次输入,我们都要判断输入坐标的合法性,具体通过函数PlayerMove()函数来实现
static void PlayerMove(int board[][COL2], int row, int col,int who)
{
while (1)
{
printf("Please Enter Your Position[player%d]#" , who);
scanf("%d %d", &x, &y);
if (x<0 || x>ROW2 - 1 || y<0 || y>COL2 - 1)
{
printf("This Position is Error,Please Enter Again\n");
continue;
}
else
{
if (board[x][y] == 0)
{
board[x][y] = who;
break;
}
else
{
printf("This Position is not empty, Please Enter Again\n");
}
}
}
}
此函数的参数传入who是什么原因呢?
答案是:确定目前是哪一位玩家在输入。具体作用下面揭晓
和三子棋一样,落完一子后结果无非就是四种,用户1赢,用户2赢,平局和继续。
那如何判断呢?
很简单,只需要判断上一个落子位置的八个方向有没有出现五子连珠的情况,若有,则说明上一个落子的玩家获胜。若没有,就判断有无平局的情况出现(这里平局说明棋盘落子已满,但未出现有一方有五子连珠的情况),剩下的就是对局未结束,继续落子。
到这里,读者就应该发现PlayerMove()函数传入参数who的作用了(为了方便判断输赢)
具体细节见代码:
static int ChessCounts(int board[][COL2], int dir)
{
int _x = x;
int _y = y;
int count = 0;
while (1)
{
switch (dir)
{
case UP:
_x--;
break;
case RIGHT_UP:
_x--, _y++;
break;
case RIGHT:
_y++;
break;
case RIGHT_DOWN:
_x++, _y++;
break;
case DOWN:
_x++;
break;
case LEFT_DOWN:
_x++, _y--;
break;
case LEFT:
_y--;
break;
case LEFT_UP:
_x--, _y--;
break;
default :
printf("Error\n");
break;
}
if (_x<0 || _x>ROW2 - 1 || _y<0 || _y>COL2 - 1)
{
break;
}
else
{
if (board[x][y] != 0 && board[x][y] == board[_x][_y])
{
count++;
}
else
{
break;
}
}
}
return count;
}
static int Judge(int board[][COL2], int row, int col)
{
int count = 0;
count = ChessCounts(board, UP) + ChessCounts(board, DOWN)+1;
if (count >= 5)
{
return board[x][y];
}
count = ChessCounts(board, RIGHT_UP) + ChessCounts(board, LEFT_DOWN) + 1;
if (count >= 5)
{
return board[x][y];
}
count = ChessCounts(board, LEFT) + ChessCounts(board, RIGHT) + 1;
if (count >= 5)
{
return board[x][y];
}
count = ChessCounts(board, LEFT_UP) + ChessCounts(board, RIGHT_DOWN) + 1;
if (count >= 5)
{
return board[x][y];
}
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
if (board[i][j] != 0)
{
return NEXT2;
}
}
}
return DRAW2;
}
其中ChessCounts()函数的作用是
计算每一组方向与上次落子相同的棋子个数。
这里的每一组方向指的是上下,左右,左上右下。左下右上
void Gobang()
{
int board[ROW2][COL2] = {
0 };
int result = 0;
while (1)
{
ShowBoard(board, ROW2, COL2);
PlayerMove(board, ROW2, COL2,PLAYER1);
result = Judge(board, ROW2, COL2);
if (result != NEXT2)
{
break;
}
ShowBoard(board, ROW2, COL2);
PlayerMove(board, ROW2, COL2,PLAYER2);
result = Judge(board, ROW2, COL2);
if (result != NEXT2)
{
break;
}
}
ShowBoard(board, ROW2, COL2);
switch (result)
{
case PLAYER1:
printf("Player1 win!\n");
break;
case PLAYER2:
printf("Player2 win!\n");
break;
case DRAW2:
printf("Draw!\n");
break;
default:
break;
}
}
五子棋完整代码
Gobang.h
#pragma once
#include
#include
extern void Gobang();
#define ROW2 10
#define COL2 10
#define PLAYER1 1
#define PLAYER2 2
#define NEXT2 3
#define DRAW2 4
#define UP 10
#define RIGHT_UP 11
#define RIGHT 12
#define RIGHT_DOWN 13
#define DOWN 14
#define LEFT_DOWN 15
#define LEFT 16
#define LEFT_UP 17
#pragma warning(disable:4996)
Gobang.c
#include "Gobang.h"
int x = 0;
int y = 0;
static void ShowBoard(int board[][COL2], int row, int col)
{
system("cls");
printf(" ");
for (int i = 0; i < COL2; i++)
{
printf("%3d",i);
}
printf("\n");
for (int i = 0; i < ROW2; i++)
{
printf("%-2d |",i);
for (int j = 0; j < COL2; j++)
{
if (board[i][j] == 0)
{
printf(" . ");
}
else if (board[i][j] == PLAYER1)
{
printf(" o ");
}
else if (board[i][j] == PLAYER2)
{
printf(" x ");
}
}
printf("\n");
}
}
static void PlayerMove(int board[][COL2], int row, int col,int who)
{
while (1)
{
printf("Please Enter Your Position[player%d]#" , who);
scanf("%d %d", &x, &y);
if (x<0 || x>ROW2 - 1 || y<0 || y>COL2 - 1)
{
printf("This Position is Error,Please Enter Again\n");
continue;
}
else
{
if (board[x][y] == 0)
{
board[x][y] = who;
break;
}
else
{
printf("This Position is not empty, Please Enter Again\n");
}
}
}
}
static int ChessCounts(int board[][COL2], int dir)
{
int _x = x;
int _y = y;
int count = 0;
while (1)
{
switch (dir)
{
case UP:
_x--;
break;
case RIGHT_UP:
_x--, _y++;
break;
case RIGHT:
_y++;
break;
case RIGHT_DOWN:
_x++, _y++;
break;
case DOWN:
_x++;
break;
case LEFT_DOWN:
_x++, _y--;
break;
case LEFT:
_y--;
break;
case LEFT_UP:
_x--, _y--;
break;
default :
printf("Error\n");
break;
}
if (_x<0 || _x>ROW2 - 1 || _y<0 || _y>COL2 - 1)
{
break;
}
else
{
if (board[x][y] != 0 && board[x][y] == board[_x][_y])
{
count++;
}
else
{
break;
}
}
}
return count;
}
static int Judge(int board[][COL2], int row, int col)
{
int count = 0;
count = ChessCounts(board, UP) + ChessCounts(board, DOWN)+1;
if (count >= 5)
{
return board[x][y];
}
count = ChessCounts(board, RIGHT_UP) + ChessCounts(board, LEFT_DOWN) + 1;
if (count >= 5)
{
return board[x][y];
}
count = ChessCounts(board, LEFT) + ChessCounts(board, RIGHT) + 1;
if (count >= 5)
{
return board[x][y];
}
count = ChessCounts(board, LEFT_UP) + ChessCounts(board, RIGHT_DOWN) + 1;
if (count >= 5)
{
return board[x][y];
}
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
if (board[i][j] != 0)
{
return NEXT2;
}
}
}
return DRAW2;
}
void Gobang()
{
int board[ROW2][COL2] = {
0 };
int result = 0;
while (1)
{
ShowBoard(board, ROW2, COL2);
PlayerMove(board, ROW2, COL2,PLAYER1);
result = Judge(board, ROW2, COL2);
if (result != NEXT2)
{
break;
}
ShowBoard(board, ROW2, COL2);
PlayerMove(board, ROW2, COL2,PLAYER2);
result = Judge(board, ROW2, COL2);
if (result != NEXT2)
{
break;
}
}
ShowBoard(board, ROW2, COL2);
switch (result)
{
case PLAYER1:
printf("Player1 win!\n");
break;
case PLAYER2:
printf("Player2 win!\n");
break;
case DRAW2:
printf("Draw!\n");
break;
default:
break;
}
}
游戏主函数
这里依旧采用多文件编程,日后会在此篇博客的基础之上进行新游戏的添加,各位看官常来回访~~
#include "ThreeGame.h"
#include "FindMines.h"
#include "Gobang.h"
void Menu()
{
printf("+----------------------+\n");
printf("| 1.ThreeGame |\n");
printf("| 2.Findmines |\n");
printf("| 3.Gobang |\n");
printf("| 0.Exit |\n");
printf("+----------------------+\n");
}
int main()
{
int quit = 0;
while (!quit)
{
Menu();
int select = 0;
printf("Please Enter Your Choose#");
scanf("%d", &select);
switch (select)
{
case 1:
ThreeGame();
break;
case 2:
FindMines();
break;
case 3:
Gobang();
break;
case 0:
printf("ByeBye!\n");
quit = 1;
break;
default:
printf("Bug!\n");
break;
}
}
system("pause");
return 0;
}