下面展示一些 功能实现
int Menu() {
system("color 3F");
printf("-----------------亲,欢迎来到五子棋!----------------\n\n");
printf("----------------------------------------\n\n");
printf("------------------1.亲,你可以输入1选择与你的电脑PK喔---------------------\n\n");
printf("------------------2.你可以输入2想与你一决高下的对手PK---------------------\n\n");
printf("------------------0.结束游戏---------------------\n\n");
printf("---------------------------------------------------------------------------\n");
printf("请输入您的选择\n");
int choice = 0;
scanf("%d", &choice);
return choice;
}
(1)初始化棋盘
void Init()
{
for (int row = 0; row < Max_Row; ++row) {
for (int col = 0; col < Max_Col; ++col) {
ChessBoard[row][col] = ' ';
}
}
}
(2)打印棋盘
void Print() //void说明这个方法的返回值类型为空
{
system("color 6F");//颜色属性由两个十六进制数字指定 – 第一个为背景,第二个则为前景.
printf(" 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14\n");
for (int row = 0; row < Max_Row; ++row) {
printf("| %c | %c | %c | %c | %c | %c | %c | %c | %c | %c | %c | %c | %c | %c | %c |%d\n",
ChessBoard[row][0], ChessBoard[row][1], ChessBoard[row][2],
ChessBoard[row][3], ChessBoard[row][4], ChessBoard[row][5],
ChessBoard[row][6], ChessBoard[row][7], ChessBoard[row][8],
ChessBoard[row][9], ChessBoard[row][10], ChessBoard[row][11],
ChessBoard[row][12], ChessBoard[row][13], ChessBoard[row][14], row);
printf("|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|\n", row);
}
}
1.初始化棋盘
将二维数组中所有元素初始化为空格因为已在程序开始时定义了二维数组全局变量为棋盘存储信息,且存储元素定义为字符型,因此以空格初始化棋盘
2.棋盘的打印
(1)棋盘构造
此处利用printf直接输出以|—|和| %c |构造出的棋盘,而中间%c的位置就是将元素输出后的位置,而棋盘是由15*15的小方格组成的
(2)棋盘的输出方式
用循环的方式,将棋盘一行的方式一行一行依次输出
解决此问题所用到的知识、技巧
1.棋盘的构造可用一些常用的符号构造,—±–±–也是可以的,而此程序构造方式是|—|,| %c |
2.运用到了循环语句,将棋盘依次打印出
3.同样如同菜单页面一样引用了system(“color 6F”)图形库函数,将背景设计为橙色,字体和边框是亮白色的,给玩家美的感受
1、人机对战功能模块设计
(1)玩家落子
void PlayerMove() {
printf("到您落子了\n");
while (1) {
printf("请输入您想要落子的坐标\n");
int row, col;
scanf("%d %d", &row, &col);
//如果行数或者列数不合法,继续下一次循环
if (row >= Max_Row || col >= Max_Col || row < 0 || col < 0) {
printf("您的输入无效!\n");
continue;
}
//如果落子的位置不是空格,提示玩家已落子,继续下一次循环
if (ChessBoard[row][col] != ' ') {
printf("您输入的位置已落子\n");
continue;
}
ChessBoard[row][col] = 'o';
printf("\a");
break;
}
}
(2)电脑落棋
void ComputerMove() {
printf("电脑落子\n");
while (1) {
int row, col;
srand((unsigned int)time(0));
row = rand() % 15
col = rand() % 15;
if (ChessBoard[row][col] == ' ') {
ChessBoard[row][col] = 'x';
printf("\a");
break;
}
}
}
(3)人机对战函数调用实现
void GameComputer() {
//1.初始化棋盘
Init();
char winner = ' ';
while (1) {
//2.打印棋盘
Print();
//3.玩家落子
PlayerMove();
//4.检测胜负
winner = JudgeWinner();
if (winner != ' ') {
break;
}
//5.电脑落子
ComputerMove();
//6.检测胜负
winner = JudgeWinner();
if (winner != ' ') {
break;
}
}
Print();
if (winner == 'o') {
printf("你好厉害啊,你赢了\n");
}
if (winner == 'x') {
printf("你一定是出现了失误,输给电脑啦\n");
}
else {
printf("您只能和人工智障打平手!!\n");
}
}
说明:此处是将玩家落子与电脑落子联系起来的人机对战总函数函数,判断获胜情况的函数模块将在后面进行详细说明。
每个角色每完成一次落子,都会调用判断获胜情况的函数判断输赢
解决此问题所用到的知识、技巧
玩家落子
(1)实现玩家落子的函数主要依据条件判断语句进行相应条件的判断,后给出一定提示,指引玩家操纵
(2)在判断玩家落子的位置是否已有子的时候,前面的初始化棋盘的方式为此处做了一个很好的铺垫,即判断玩家输入坐标位置是否为空格,如果为空格,则说明此处无棋子,此位置是可以落子的
(3)利用while(1){……},与if{……}if{……}嵌套,如果不满足条件则continue,则跳出当层循环,玩家可以继续输入,如果满足条件,完成落子以后则break,跳出整个循环
电脑落子
(1)此处利用了随机数srand((unsigned int)time(0)),以时间作为随机数种子,电脑随机产生1-15内的随机数生成行列坐标位置,行:row = rand() % 15,列:col = rand() % 15
2、双人对战模块设计
(1)玩家1
void Player1() {
printf("到玩家1落子了\n");
while (1) {
printf("请输入玩家1想要落子的坐标\n");
int row, col;
scanf("%d %d", &row, &col);
//如果行数或者列数不合法,继续下一次循环
if (row >= Max_Row || col >= Max_Col || row < 0 || col < 0) {
printf("您的输入无效!\n");
continue;
}
//如果落子的位置不是空格,提示玩家已落子,继续下一次循环
if (ChessBoard[row][col] != ' ') {
printf("您输入的位置已落子\n");
continue;
}
ChessBoard[row][col] = 'o';
printf("\a");
break;
}
}
(2)玩家2
void Player2() {
printf("到玩家2落子了\n");
while (1) {
printf("请输入玩家2想要落子的坐标\n");
int row, col;
scanf("%d %d", &row, &col);
//如果行数或者列数不合法,继续下一次循环
if (row >= Max_Row || col >= Max_Col || row < 0 || col < 0) {
printf("您的输入无效!\n");
continue;
}
//如果落子的位置不是空格,提示玩家已落子,继续下一次循环
if (ChessBoard[row][col] != ' ') {
printf("您输入的位置已落子\n");
continue;
}
ChessBoard[row][col] = 'x';
printf("\a");
break;
}
}
(3)双人对战总函数
void GamePlayer() {
//1.初始化棋盘
Init();
//2.打印棋盘
Print();
char winner = ' ';
while (1) {
//3.玩家1落子
Player1();
Print();
//4.检测胜负
winner = JudgeWinner();
if (winner != ' ') {
break;
}
//5.玩家2落子
Player2();
Print();
//6.检测胜负
winner = JudgeWinner();
if (winner != ' ') {
break;
}
}
if (winner == 'o') {
printf("玩家1赢了\n");
}
if (winner == 'x') {
printf("玩家2赢了\n");
}
else {
printf("你们打成平手啦!!\n");
}
}
说明:此处是将玩家1,玩家2落子联系起来的双人对战总函数函数,判断获胜情况的函数模块将在后面进行详细说明。
此处每一次完成落子都要调用判断胜负的函数,确保判断的正确性
解决此问题所用到的知识、技巧
(1)实现玩家落子的函数主要依据条件判断语句进行相应条件的判断,后给出一定提示,指引玩家操纵
(2)在判断玩家落子的位置是否已有子的时候,前面的初始化棋盘的方式为此处做了一个很好的铺垫,即判断玩家输入坐标位置是否为空格,如果为空格,则说明此处无棋子,此位置是可以落子的
(3)利用while(1){……},与if{……}if{……}嵌套,如果不满足条件则continue,则跳出当层循环,玩家可以继续输入,如果满足条件,完成落子以后则break,跳出整个循环
可获胜的方向有横向连成5子,也可纵向连成5字,当然还有斜线相连的,当棋盘所空位置不能再实现5子相连的情况时,则会出现和棋
1.横向判断
(1)以行的方式对棋盘中的元素进行遍历,即在行坐标不变下,将列坐标依次加“1”直到遍历到不为空格的元素,纵坐标保持不变然后在其横坐标基础上加1,2,3,4,即遍历与之相邻的纵向的四个棋子,如果与之相邻的四个棋子均相同,则返回相应的字符参数,人机对战的总函数或双人对战的总函数对其接收判断符合的条件以后,输出胜负情况,如果不相同则返回空格,两个总函数接收到空格时会提示玩家继续输入坐标下棋。
2.右斜线判断
(1)同样以行的方式遍历,找到第一个非空格的元素,当找到以后每5×5的单元格就是一个小的棋盘,因此对该位置与右斜线上相邻的元素进行判断是否相同时,由于行坐标是向下移动的,而列坐标事项左移动的,所以只需在位置行和列坐标的基础上都加相同的数(1,2,3,4),即为此小单元棋盘上右斜线上的所有元素,当所有元素相同时,返回相应的字符参数,人机对战或者双人对战的总函数对其接收判断符合的条件后,输出胜负情况,如果不相同则返回空格,两个总函数接收到空格时会提示玩家继续输入坐标下棋。
3.竖直判断
(1)以行的方式对棋盘中的元素进行遍历,即在行坐标不变下,将列坐标依次加“1”直到遍历到不为空格的元素,纵坐标保持不变然后在其横坐标基础上加1,2,3,4,即遍历与之相邻的纵向的四个棋子,如果与之相邻的四个棋子均相同,则返回相应的字符参数,人机对战的总函数或双人对战的总函数对其接收判断符合的条件以后,输出胜负情况,如果不相同则返回空格,两个总函数接收到空格时会提示玩家继续输入坐标下棋。
4.左斜线判断
(1)同样以行的方式遍历,找到第一个非空格的元素,当找到以后每5*5的单元格就是一个小的棋盘,因此对该位置与左斜线上相邻的元素进行判断是否相同时,由于列坐标是向左移动的,所以在遍历到的位置列坐标基础上依次减1,2,3,4;而行坐标是想下移动的,所以在遍历到的位置坐标行坐标的基础上依次加1,2,3,4;此时即可遍历到小单元棋盘上左斜线上的所有元素,当所有元素相同时,返回相应的字符参数,人机对战或者双人对战的总函数对其接收判断符合的条件后,输出胜负情况,如果不相同则返回空格,两个总函数接收到空格时会提示玩家继续输入坐标下棋。
5.和棋判断
在判断胜负的函数中调用是否和棋的函数,即所有位置即将下满,不可能在出现5枚棋子相连的情况极为和棋,和棋则返回字符q,当接收到返回的q时,则输出和棋信息
int isFull(char chessBoard[Max_Row][Max_Col]) {
int row, col;
for (row = 0; row < Max_Row; row++) {
for (col = 0; col < Max_Col; col++) {
if (chessBoard[row][col] == ' ') {
return 0;
}
}
}
return 1;
}
char JudgeWinner() {
//先判断横着胜利的
//遍历到倒数第五个格子,要判断和最后的四个格子是否相同,
//所以为最大格数减4
for (int row = 0; row < Max_Row; ++row) {
for (int col = 0; col < (Max_Col - 4); ++col) {
if (ChessBoard[row][col] != ' ') {
if (ChessBoard[row][col] == ChessBoard[row][col + 1] &&
ChessBoard[row][col] == ChessBoard[row][col + 2] &&
ChessBoard[row][col] == ChessBoard[row][col + 3] &&
ChessBoard[row][col] == ChessBoard[row][col + 4]) {
return ChessBoard[row][col];
}
}
}
}
//向右斜着胜利的
for (int row = 0; row < (Max_Row - 4); ++row) {
for (int col = 0; col < (Max_Col - 4); ++col) {
if (ChessBoard[row][col] != ' ') {
if (ChessBoard[row][col] == ChessBoard[row + 1][col + 1] &&
ChessBoard[row][col] == ChessBoard[row + 2][col + 2] &&
ChessBoard[row][col] == ChessBoard[row + 3][col + 3] &&
ChessBoard[row][col] == ChessBoard[row + 4][col + 4]) {
return ChessBoard[row][col];
}
}
}
}
//判断竖着胜利的
for (int row = 0; row < (Max_Row - 4); ++row) {
for (int col = 0; col < Max_Col; ++col) {
if (ChessBoard[row][col] != ' ') {
if (ChessBoard[row][col] == ChessBoard[row + 1][col] &&
ChessBoard[row][col] == ChessBoard[row + 2][col] &&
ChessBoard[row][col] == ChessBoard[row + 3][col] &&
ChessBoard[row][col] == ChessBoard[row + 4][col]) {
return ChessBoard[row][col];
}
}
}
}
//判断向左斜着胜利的
for (int row = 0; row < (Max_Row - 4); ++row) {
for (int col = 4; col < Max_Col; ++col) {
if (ChessBoard[row][col] != ' ') {
if (ChessBoard[row][col] == ChessBoard[row + 1][col - 1] &&
ChessBoard[row][col] == ChessBoard[row + 2][col - 2] &&
ChessBoard[row][col] == ChessBoard[row + 3][col - 3] &&
ChessBoard[row][col] == ChessBoard[row + 4][col - 4]) {
return ChessBoard[row][col];
}
}
}
}
return ' ';
if (isFull(ChessBoard)) {
return 'q';
}
return ' ';
}
int main() {
while (1) {
int choice = Menu();
if (choice == 1) {
printf("电脑对战\n");
GameComputer();
}
else if (choice == 2) {
printf("玩家对战\n");
GamePlayer();
}
else if (choice == 0) {
printf("下次再见,十分遗憾\n");
break;
}
else {
printf("请输入1或0\n");
}
}
system("pause");
return 0;
}