前期规划
由于需要使用很多函数,我们将创建很多文件,有一个存放主函数的text.h,将其他的一些函数放到game1.c(三子棋)game2.c(扫雷),在game1.h(三子棋)game2.h(扫雷)中声明,以便在text.h中使用。
创建主函数,设计流程
由于想实现两个游戏,并且在以后有新游戏也可以加到里面,所以我想到了用swtih来完成分支。
代码如下
int main()
{
int x = 0;
do
{
printf("请选择想要游玩的项目>:");
scanf("%d", &x);//选择游戏
switch (x)
{
case 1:
{
printf("三子棋");
break;
}
case 2:
{
printf("扫雷");
break;
}
default:
{
printf("未找到此游戏\n");
printf("请重新选择\n");
break;
}
}
} while (x);
return 0;
}
菜单
玩家看不到代码,那么我们加上一个菜单放在选择游戏前面。
代码如下
void menu()
{
printf("╔══════════╗\n");
printf("║ 1.三子棋 ║\n");
printf("║══════════║\n");
printf("║ 2.扫 雷 ║\n");
printf("║══════════║\n");
printf("║ 0.退 出 ║\n");
printf("╚══════════╝\n");
}
在屏幕上显示的效果应该是这样的。
现在,让我们完成游戏的部分吧。
三子棋
创建棋盘
三子棋要一个3x3的棋盘,并且要四条先把棋盘分割成九个区域,那么我们可以用二维数组来完成它
代码如下
#define ROW 3
#define COL 3
char three[ROW][COL] = { 0 };
初始化棋盘
棋盘创建好了,先将棋盘初始化。
代码如下
void init(char three[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i=0;i<row;i++)
{
for (j=0;j<col;j++)
{
three[i][j] = ' ';
}
}
}
打印棋盘
棋盘创建好了,但是还是要在屏幕上打印出来,并且要把四条线也打印出来。
代码如下
//打印棋盘
void print(char three[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
system("cls");
printf(" ");
for (j = 0; j < col; j++)//打印横坐标
{
printf("% d ",j+1);
if (j < col - 1)
{
printf(" ");
}
}
printf("\n");
for (i = 0; i < row; i++)//打印棋盘
{
printf("%d", i+1);//打印纵坐标
for (j = 0; j < col; j++)
{
printf(" %c ", three[i][j]);
if (j < col - 1)//如果打印的是最后一列,那么不打印
{
printf("|");
}
}
printf("\n");
if (i < row - 1)//如果打印的是最后一行,那么不打印
{
printf(" ");//因为纵坐标把棋盘向右挤了一格,这里加一个空格填充
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
{
printf("|");
}
}
printf("\n");
}
}
}
让我们来看看我们的棋盘吧。
玩家下棋
现在该我们下棋了,由于我们一开始初始化棋盘,棋盘里面没有东西,我们可以对此进行判断,当只有数组里面为空格时才可以输入,不仅如此,我们还要判断输入的坐标是不是一个正确的坐标,都满足时才允许玩家下棋。
代码如下
void play(char three[ROW][COL], int row, int col)
{
int x = 0;//行
int y = 0;//列
printf("玩家回合\n");
printf("输入坐标>:");
while (1)
{
scanf("%d %d", &x, &y);
if (x <= row && y <= row && x >= 1 && y >= 1)//判断坐标是否正确
{
if (three[x-1][y-1] == ' ')//判断坐标是否被占用
{
three[x-1][y-1] = '#';//玩家的棋子
break;
}
else
{
printf("该坐标已被输入,请重新输入");
}
}
else
{
printf("没有这个坐标,请重新输入");
}
}
}
电脑下棋
玩家下完了,总得给电脑也下吧,但是怎么能让电脑也学会下棋呢,函数rand()可以产生随机数,我们用srand((int)time(NULL))来让rand()的初始值发生改变。电脑每次就能给出不一样的值,我们可以确定随机数的范围,那我们只需要判断坐标有没有被占用就好了。
代码如下
void computer(char three[ROW][COL], int row, int col)
{
srand((int)time(NULL));
while (1)
{
int x = rand() % row;
int y = rand() % col;
if (three[x][y] == ' ')
{
three[x][y] = '*';
break;
}
}
}
判断胜负
电脑也学会下棋了,我们在case语句中加一个循环,一遍一遍把棋盘下满,或者是有获胜者,当我们就该判断谁是获胜者了。为此,我们设定C为继续下棋的标志,而'#'为玩家获胜,'*'为电脑获胜,平局时返回Q。
代码如下
char win(char three[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
for (x = 0; x < row; x++)//横
{
if (three[x][0] == three[x][1] && three[x][0] == three[x][2] && three[x][0] != ' ')
{
return three[x][0];
}
}
for (x = 0; x < col; x++)//列
{
if (three[0][x] == three[1][x]&& three[0][x] == three[2][x] && three[0][x] != ' ')
{
return three[0][x];
}
}
if (three[0][0] == three[1][1] && three[1][1] == three[2][2] && three[1][1] != ' ')//对角线
{
return three[1][1];
}
if (three[0][2] == three[1][1] && three[1][1] == three[2][0] && three[1][1] != ' ')//对角线
{
return three[1][1];
}
for (x = 0; x < row; x++)
{
for (y = 0; y < col; y++)
{
if (three[x][y] == ' ')//检查棋盘是否满了
{
return 'C';
}
}
}
return 'S';
}
三子棋代码
有了返回值,我们就要进行判断了,在把之前的整合一下,三子棋游戏就完成了。
代码如下
int main()
{
int x = 0;
do
{
menu();
printf("请选择想要游玩的项目>:");
scanf("%d", &x);
switch (x)
{
case 1:
{
char i = ' ';
char three[ROW][COL];//创建二维数组
init(three, ROW, COL);//初始化二维数组
while (1)
{
print(three, ROW, COL);//打印棋盘
play(three, ROW, COL);//玩家下棋
print(three, ROW, COL);//打印棋盘
i=win(three, ROW, COL);//判断输赢
if (i != 'C')
{
break;
}
computer(three, ROW, COL);//电脑下棋
print(three, ROW, COL);//打印棋盘
i = win(three, ROW, COL); //判断输赢
if (i != 'C')
{
break;
}
}
if ('#' == i)
{
printf("玩家胜利\n");
}
else if ('*' == i)
{
printf("电脑胜利\n");
}
else if ('S' == i)
{
printf("平局\n");
}
break;
}
case 2:
{
pritnf("扫雷");
break;
}
default:
{
system("cls");
printf("未找到此游戏\n");
printf("请重新选择\n");
break;
}
}
} while (x);
return 0;
}
扫雷
创建棋盘
同样的,扫雷也需要一个棋盘,但是在四周容易越界访问,为了避免这个问题,我们可以将四周都扩大一格,并且只访问中间的。
棋盘的问题解决了,但是在布雷的过程中将雷设置1,安全的地方设置成0的时候。排雷是,如果排雷的位置周围正好只有一个雷,那个这个位置也会被改成1,那么就有歧义了。我们可以创建两个棋盘,一个棋盘放雷,另一个棋盘放排雷的信息。
代码如下
#define towrow towrows-2
#define towcol towcols-2
#define towrows 11
#define towcols 11
char bomb[towrows][towcols];//雷棋盘
char find[towrows][towcols];//玩家排雷棋盘
初始化棋盘
同样的,我们要初始化棋盘,但两个棋盘初始化内容不一致,解决方法很简单,加一个参数就好了。
代码如下
void init(char bomb[ROWS][COLS], int row, int col, char sel)
{
int x = 0;
int y = 0;
for (x = 0; x < row; x++)
{
for (y = 0; y < col; y++)
{
bomb[x][y] = sel;
}
}
}
打印棋盘
现在,让我们把棋盘打印出来看看。
代码如下
void print2(char bomb[towrows][towrows], int row, int col)
{
int x = 0;
int y = 0;
system("cls");
printf(" ");
for (x = 1; x <= col; x++)
{
printf("%d ", x);//横坐标打印
}
printf("\n");
for (x = 1; x <= row; x++)
{
printf("%d ", x);//纵坐标打印
for (y = 1; y <= col; y++)
{
printf("%c ", bomb[x][y]);
}
printf("\n");
}
}
效果是这样的
布雷
我们教会了电脑怎么产生随机数,现在就再麻烦它帮我们布一下雷吧
代码如下
#define bombs 10
void boom(char bomb[towrows][towcols], int row, int col)
{
int x = 0;
int y = 0;
int z = bombs;
srand((int)time(NULL));
while (z)
{
x = rand() % row+1;
y = rand() % col+1;
if ('0' == bomb[x][y])
{
bomb[x][y] = '1';
z--;
}
}
}
判断部分
雷布置完了,现在就该排雷了。我们每输进去一个坐标,电脑应该是首先判断这个坐标是不是已经被排了。如果没有排,那么我们该判断这个坐标是不是雷,如果是,那么游戏结束,跳出循环。如果不是,计算周围八个位置的雷,并将周围雷的数量写入数组中,当把所有不是雷的区域排干净后,游戏胜利跳出循环。
代码如下
void find_bomb(char bomb[towrows][towcols],char find[towrows][towcols],int row,int col)
{
int x = 0;
int y = 0;
int count = 0;
while (count < row * col - bombs)
{
printf("请输入排查雷的坐标:");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if ('*' == find[x][y])
{
if ('1' == bomb[x][y])
{
end_printf(bomb, find, x, y);
printf("游戏结束\n");
break;
}
else
{
find[x][y] = get_bomb(bomb, x, y) + '0';
count++;
print2(find, towrow, towcol);
}
}
else
{
printf("该区域已被排查过");
}
}
else
{
printf("超出棋盘范围\n");
}
}
if (!(count < row * col - bombs))
{
printf("恭喜你,游戏胜利\n");
}
}
判断四周的雷
数字字符的ascii码是连续的,将周围的八个数字加起来再减去8个字符0就可以得到周围就几个雷了。
代码如下
int get_bomb(char bomb[towrows][towcols], int row, int col)
{
return (bomb[row-1][col-1]+
bomb[row-1][col]+
bomb[row - 1][col + 1]+
bomb[row][col - 1]+
bomb[row][col + 1]+
bomb[row + 1][col - 1]+
bomb[row + 1][col]+
bomb[row + 1][col + 1] - 8 * '0');
}
在游戏失败时,标记踩的是哪一个雷,并且加了一个动画,
代码如下
void end_printf(char bomb[towrows][towcols], char find[towrows][towcols], int x, int y)
{
find[x][y] = '#';//踩的雷改成#,其他的改成*
int i = 0;
int j = 0;
for (i = 1;i<towrow + towcol; i++)
{
for (j = i; j >= 0; j--)
{
if (x + j >= 1 && x + j <= 9 && y + i - j >= 1 && y + i - j <= 9)
{
lost(bomb, find, x + j, y + i - j);
}
if (x - j >= 1 && x - j <= 9 && y + i - j >= 1 && y + i - j <= 9)
{
lost(bomb, find, x - j, y + i - j);
}
if (x + j >= 1 && x + j <= 9 && y - i + j >= 1 && y - i + j <= 9)
{
lost(bomb, find, x + j, y - i + j);
}
if (x - j >= 1 && x - j <= 9 && y - i + j >= 1 && y - i + j <= 9)
{
lost(bomb, find, x - j, y - i + j);
}
}
print2(find, towrow, towcol);
Sleep(200);
}
}
void lost(char bomb[towrows][towcols], char find[towrows][towcols], int x, int y)
{
if ('0' == bomb[x][y])
{
find[x][y] = get_bomb(bomb, x, y)+'0';
}
else if ('#' == find[x][y])
{
;
}
else
{
find[x][y] = '*';
}
}
好了,现在我们完成了两个游戏的制作,下面是代码
text.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
#include"扫雷.h"
void menu()
{
printf("╔══════════╗\n");
printf("║ 1.三子棋 ║\n");
printf("║══════════║\n");
printf("║ 2.扫 雷 ║\n");
printf("║══════════║\n");
printf("║ 0.退 出 ║\n");
printf("╚══════════╝\n");
}
int main()
{
int x = 0;
do
{
menu();
printf("请选择想要游玩的项目>:");
scanf("%d", &x);
switch (x)
{
case 1:
{
char i = ' ';
char three[ROW][COL] = { 0 };//创建二维数组
init(three, ROW, COL);//初始化二维数组
while (1)
{
print(three, ROW, COL);//打印棋盘
play(three, ROW, COL);//玩家下棋
print(three, ROW, COL);//打印棋盘
i=win(three, ROW, COL);//判断输赢
if (i != 'C')
{
break;
}
computer(three, ROW, COL);//电脑下棋
print(three, ROW, COL);//打印棋盘
i = win(three, ROW, COL); //判断输赢
if (i != 'C')
{
break;
}
}
if ('#' == i)
{
printf("玩家胜利\n");
}
else if ('*' == i)
{
printf("电脑胜利\n");
}
else if ('S' == i)
{
printf("平局\n");
}
break;
}
case 2:
{
char bomb[towrows][towcols];//雷棋盘
char find[towrows][towcols];//玩家排雷棋盘
init2(bomb, towrows, towcols,'0');//初始化雷棋盘
init2(find, towrows, towcols, '*');//初始化玩家排雷棋盘
boom(bomb, towrow, towcol);//布雷
print2(find, towrow, towcol);//打印棋盘
find_bomb(bomb, find, towrow,towcol);//排雷
break;
}
default:
{
system("cls");
printf("未找到此游戏\n");
printf("请重新选择\n");
break;
}
}
} while (x);
return 0;
}
game1.h(三子棋)
#include<stdio.h>
#include<time.h>
#include<Windows.h>
#include<stdlib.h>
#define ROW 3
#define COL 3
void init(char three[ROW][COL], int row, int col);//格式化数组
void print(char three[ROW][COL], int row, int col);//打印棋盘
void play(char three[ROW][COL], int row, int col);//玩家输入
void computer(char three[ROW][COL], int row, int col);//电脑输入
char win(char three[ROW][COL], int row, int col);//判断输赢
game1.c(三子棋)
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void init(char three[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i=0;i<row;i++)
{
for (j=0;j<col;j++)
{
three[i][j] = ' ';
}
}
}
void print(char three[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
system("cls");
printf(" ");
for (j = 0; j < col; j++)//打印坐标
{
printf("% d ",j+1);
if (j < col - 1)
{
printf(" ");
}
}
printf("\n");
for (i = 0; i < row; i++)//打印棋盘
{
printf("%d", i+1);
for (j = 0; j < col; j++)
{
printf(" %c ", three[i][j]);
if (j < col - 1)
{
printf("|");
}
}
printf("\n");
if (i < row - 1)
{
printf(" ");
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
{
printf("|");
}
}
printf("\n");
}
}
}
void play(char three[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("玩家回合\n");
printf("输入坐标>:");
while (1)
{
scanf("%d %d", &x, &y);
if (x <= row && y <= row && x >= 1 && y >= 1)
{
if (three[x-1][y-1] == ' ')
{
three[x-1][y-1] = '#';
break;
}
else
{
printf("该坐标已被输入,请重新输入");
}
}
else
{
printf("没有这个坐标,请重新输入");
}
}
}
void computer(char three[ROW][COL], int row, int col)
{
srand((int)time(NULL));
while (1)
{
int x = rand() % row;
int y = rand() % col;
if (three[x][y] == ' ')
{
three[x][y] = '*';
break;
}
}
}
char win(char three[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
for (x = 0; x < row; x++)//横
{
if (three[x][0] == three[x][1] && three[x][0] == three[x][2] && three[x][0] != ' ')
{
return three[x][0];
}
}
for (x = 0; x < col; x++)//列
{
if (three[0][x] == three[1][x]&& three[0][x] == three[2][x] && three[0][x] != ' ')
{
return three[0][x];
}
}
if (three[0][0] == three[1][1] && three[1][1] == three[2][2] && three[1][1] != ' ')//对角线
{
return three[1][1];
}
if (three[0][2] == three[1][1] && three[1][1] == three[2][0] && three[1][1] != ' ')//对角线
{
return three[1][1];
}
for (x = 0; x < row; x++)
{
for (y = 0; y < col; y++)
{
if (three[x][y] == ' ')
{
return 'C';
}
}
}
return 'S';
}
game2.h(扫雷)
#include<stdio.h>
#include<Windows.h>
#include<stdlib.h>
#include<time.h>
#define towrow towrows-2
#define towcol towcols-2
#define towrows 11
#define towcols 11
#define bombs 10
void init2(char bomb[towrows][towcols], int row, int col,char sel);//初始化
void print2(char bomb[towrows][towrows], int row, int col);//打印
void boom(char bomb[towrows][towcols], int row, int col);//布雷
void find_bomb(char bomb[towrows][towcols], char find[towrows][towcols], int row, int col);//排雷
int get_bomb(char bomb[towrows][towcols], int row, int col);//得到周围雷
void lost(char bomb[towrows][towcols], char find[towrows][towcols], int x, int y);//失败
void end_printf(char bomb[towrows][towcols], char find[towrows][towcols], int x, int y);//失败动画
game2.c(扫雷)
#define _CRT_SECURE_NO_WARNINGS 1
#include"扫雷.h"
void init2(char bomb[towrows][towcols],int row,int col,char sel)
{
int x = 0;
int y = 0;
for (x = 0; x < row; x++)
{
for (y = 0; y < col; y++)
{
bomb[x][y] = sel;
}
}
}
void print2(char bomb[towrows][towrows], int row, int col)
{
int x = 0;
int y = 0;
system("cls");
printf(" ");
for (x = 1; x <= col; x++)
{
printf("%d ", x);
}
printf("\n");
for (x = 1; x <= row; x++)
{
printf("%d ", x);
for (y = 1; y <= col; y++)
{
printf("%c ", bomb[x][y]);
}
printf("\n");
}
}
void boom(char bomb[towrows][towcols], int row, int col)
{
int x = 0;
int y = 0;
int i = 0;
int j = 0;
int z = bombs;
srand((int)time(NULL));
while (z)
{
x = rand() % row+1;
y = rand() % col+1;
if ('0' == bomb[x][y])
{
bomb[x][y] = '1';
z--;
}
}
}
void find_bomb(char bomb[towrows][towcols],char find[towrows][towcols],int row,int col)
{
int x = 0;
int y = 0;
int count = 0;
while (count < row * col - bombs)
{
printf("请输入排查雷的坐标:");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if ('*' == find[x][y])
{
if ('1' == bomb[x][y])
{
end_printf(bomb, find, x, y);
printf("游戏结束\n");
break;
}
else
{
find[x][y] = get_bomb(bomb, x, y) + '0';
count++;
print2(find, towrow, towcol);
}
}
else
{
printf("该区域已被排查过");
}
}
else
{
printf("超出棋盘范围\n");
}
}
if (!(count < row * col - bombs))
{
printf("恭喜你,游戏结束\n");
}
}
int get_bomb(char bomb[towrows][towcols], int row, int col)
{
return (bomb[row-1][col-1]+
bomb[row-1][col]+
bomb[row - 1][col + 1]+
bomb[row][col - 1]+
bomb[row][col + 1]+
bomb[row + 1][col - 1]+
bomb[row + 1][col]+
bomb[row + 1][col + 1] - 8 * '0');
}
void end_printf(char bomb[towrows][towcols], char find[towrows][towcols], int x, int y)
{
find[x][y] = '#';
int i = 0;
int j = 0;
for (i = 1;i<towrow + towcol; i++)
{
for (j = i; j >= 0; j--)
{
if (x + j >= 1 && x + j <= 9 && y + i - j >= 1 && y + i - j <= 9)
{
lost(bomb, find, x + j, y + i - j);
}
if (x - j >= 1 && x - j <= 9 && y + i - j >= 1 && y + i - j <= 9)
{
lost(bomb, find, x - j, y + i - j);
}
if (x + j >= 1 && x + j <= 9 && y - i + j >= 1 && y - i + j <= 9)
{
lost(bomb, find, x + j, y - i + j);
}
if (x - j >= 1 && x - j <= 9 && y - i + j >= 1 && y - i + j <= 9)
{
lost(bomb, find, x - j, y - i + j);
}
}
print2(find, towrow, towcol);
Sleep(200);
}
}
void lost(char bomb[towrows][towcols], char find[towrows][towcols], int x, int y)
{
if ('0' == bomb[x][y])
{
find[x][y] = get_bomb(bomb, x, y)+'0';
}
else if ('#' == find[x][y])
{
;
}
else
{
find[x][y] = '*';
}
}