今天,我们来再来实现一个大家都不陌生的小项目:三子棋。
1,三子棋
1,思路分析
写一个小项目,必不可少的是思路的构建。写一个游戏,我们首先需要一个菜单,这是最基本的,让用户来选择是否要玩这个游戏。如果要玩,就进入游戏主体的部分,不玩就直接退出。最简单的思路就是这样,而后一些细节的实现,比如游戏主体的实现需要在过程中配合去讲。
这里,我们将用到自己创建的头文件,以及多个.c文件,主要为了避免主函数中过于繁杂,庞大,我们将大部分功能封装成函数来实现。
2,代码实操
game.h文件中
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#define ROW 3
#define COL 3
void Initialboard(char board[ROW][COL], int row, int col);
void Displayboard(char board[ROW][COL], int row, int col);
void playeremove(char board[ROW][COL], int row, int col);
void computermove(char board[ROW][COL],int row,int col);
char Iswin(char board[ROW][COL], int row, int col);
char Isfull(char board[ROW][COL], int row, int col);
这里可以看到,我们将一些函数都放到这里声明,包括需要用到的一些库函数的头文件,这样,我们在.c文件中就只需要包含我们自己写的头文件就可以,简化程序。当然,不要忘记引用自己写的头文件需要使用双引号""
game.c文件
#include"game.h"
//初始化棋盘
void Initialboard(char board[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
board[i][j] = ' ';
}
}
}
//打印棋盘
// | |
//---|---|—-
// | |
//---|—-|---
// | |
void Displayboard(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
if (i == 0)
{
for (j = 0; j < col; j++)
{
if (j == 0)
printf(" %d ",j);
else
printf(" %d ", j);
}
printf("\n");
}
printf("%d",i);
for (j = 0; j < col; j++)
{
printf(" %c ", board[i][j]);
if (j < (col - 1))
{
printf("|");
}
}
printf("\n");
if (i<row - 1)
{
for (j = 0; j < col; j++)
{
if (j==0)
printf(" ---");
else
printf("---");
if (j < (col - 1))
printf("|");
}
}
printf("\n");
}
}
//实现玩家下棋
void playermove(char board[ROW][COL], int row, int col)
{
int i, j;
printf("请根据图示输入要走的坐标:");
while (1)
{
scanf("%d%d",&i,&j);
if (i >= 0 && i < 3 && j >= 0 && j <3 && board[i][j] == ' ')
{
board[i][j] = '*';
break;
}
else
printf("输入有误,请重新输入。");
}
}
void computermove(char board[ROW][COL], int row, int col)
{
while (1)
{
int i = rand() % row;
int j = rand() % col;
if (board[i][j] == ' ')
{
board[i][j] = '#';
break;
}
}
}
char Iswin(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col - 2; j++)
{
if (board[i][j] == board[i][j + 1] && board[i][j + 1] == board[i][j + 2] && board[i][j] != ' ')
{
return board[i][j];
}
}
}
for (j = 0; j < col; j++)
{
for (i = 0; i < row - 2; i++)
{
if (board[i][j] == board[i + 1][j] && board[i + 1][j] == board[i + 2][j] && board[i][j] != ' ')
{
return board[i][j];
}
}
}
for (i = 0, j = 0; i < row - 2 && j < col - 2; i++, j++)
{
if (board[i][j] == board[i + 1][j+1] && board[i + 1][j+1] == board[i + 2][j+2] && board[i][j] != ' ')
{
return board[i][j];
}
}
for (i = row-1, j = 0; i >=0 && j < col-2; i--, j++)
{
if (board[i][j] == board[i -1][j + 1] && board[i - 1][j + 1] == board[i -2][j + 2] && board[i][j] != ' ')
{
return board[i][j];
}
}
return 'c';
}
char Isfull(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col;j++)
{
if (board[i][j] == ' ')
return 'c';
}
}
return 'e';
}
三子棋.c文件
#include"game.h"
//说明:
//*是玩家走的棋子
//#是电脑走的棋子
void menu()
{
printf("*****************\n");
printf("**1,play 0,exit**\n");
printf("*****************\n");
printf("请选择:");
}
void game()
{
char win = 'c';
char board[ROW][COL] = { 0};//创建棋盘
Initialboard(board, ROW, COL);//初始化棋盘
Displayboard(board, ROW, COL);//打印出棋盘的信息
while (1)
{
//玩家走
printf("玩家走\n");
playermove(board, ROW, COL);
Displayboard(board, ROW, COL);
win = Isfull(board, ROW, COL);
win=Iswin(board,ROW,COL);
if (win != 'c')
break;
//电脑走
printf("电脑走\n");
computermove(board, ROW, COL);
Displayboard(board, ROW, COL);
win = Isfull(board, ROW, COL);
win=Iswin(board,ROW,COL);
if (win != 'c')
break;
}
if (win == 'e')
printf("平局\n");
else if (win == '*')
printf("玩家赢\n");
else if (win == '#')
printf("电脑赢\n");
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
//菜单,让用户选择
menu();
scanf("%d", &input);
if (input != 0)
{
printf("游戏开始\n");
game();//游戏主体
}
else
{
printf("退出游戏\n");
break;
}
} while (input);
return 0;
}
3,最后解释
这里将两个合起来一起说。首先,在三子棋.c文件中,我们实现了上面的基本思路,而进入游戏主体部分之后,我们需要的是创建一个棋盘来存放我们的信息。之后,初始化棋盘,打印棋盘。这里,我们使用了宏定义,直接定义ROW,COL,行和列,方便我们之后进行修改,来改变棋盘的大小。而后,就是进行三子棋的玩家和电脑的走法了,玩家走比较简单,我们在打印棋盘的时候就已经让棋盘上有标坐标了,玩家只需要根据坐标来选,在将信息存入就可以了。而电脑的走法就需要我们之前使用过的rand函数了,还记得吗,不记得的话大家可以回去看看
小项目的实现:猜数字小游戏+随机数生成器的实现_C_Ryson的博客-CSDN博客
用取模的方式限制住随机数的范围,我们就可以放入棋盘了。有了这两个之后,最重要的就是判断规则了,大家有兴趣的话,可以去看看??????C语言从入门到进阶(C语言入门搞定C语言C语言视频教程C语言入门到进阶C语言教程C语言教程C语言教程C语言入门教程C语言入教程C语言C语言视频C语言教程)_哔哩哔哩_bilibili
这里的规则是我自己写的,原本是想让其普适高一些,放大棋盘之后还能使用。结果发现,三子棋放大棋盘之后,先手的一定会赢,这让我之后想写的双人对战的梦想破灭了,于是,我就将其用到了五子棋(进阶版),这里碍于时间原因,就这两天写给大家吧,这里只写一下五子棋的普通版本有兴趣的话记得点个关注,明天来看哦。
在判断规则中,我们利用放进去数组元素的特点,直接返回就行,利用数组的元素来判断是否本局已经结束,而一开始,我们用变量win储存的字母c(continue)来表示游戏继续,如果win的值被改变,就证明游戏已经结束,可以跳出循环了。再进行判断的。同时,我们要注意到,因为棋盘的大小被我们所限定,还有可能出现一个问题是平局,也就是棋盘满的情况,所以我们还需要一个Isfull函数来判断一下,一旦棋盘上所有的元素都不在有空格,又还没分出胜负,那么就是平局了。这样,一个完整的判断规则就写完了。
接下来重点说一下我自己写的上面的规则,
我们知道三子棋要赢只需要有三个棋子在一条直线上,那么这时候,我们就可以创建两个变量,使其都在行和列范围内,并然后嵌套循环i,j,改变来判断竖列的,和横列的,再将i,j,同时改变,来判断斜着的直线。
这时候,不管棋盘变得多么大,判断规则依然成立。
之后的收尾,就是像上次猜数字游戏一样让用户选择是否继续玩就可以了。
2,五子棋(初阶版)
重头戏五子棋来啦。
1,思路分析
其实,五子棋的整体思路和三子棋差不多,整体构建的代码也类似,只是将判断规则放大,将棋盘放大而已,我们边看代码边说吧。
2,代码实现
首先,依然是自己的头文件。
game.h文件
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#define ROW 5
#define COL 5
void Initialboard(char board[ROW][COL], int row, int col);
void Displayboard(char board[ROW][COL], int row, int col);
void playeremove(char board[ROW][COL], int row, int col);
void computermove(char board[ROW][COL], int row, int col);
char Iswin(char board[ROW][COL], int row, int col);
char Isfull(char board[ROW][COL], int row, int col);
简化代码的运用,这里我们将ROW和COL定义成了5,当然,也可以自己定得更大,不过,跟电脑对战(还没升级的),太大的棋盘反而没什么用处。虽然升级也不算太好,毕竟本人才疏学浅,主要升级的思路只在于,让电脑在玩家下的棋的周围下,之后学得更多,在来进行优化吧,这里这个简陋的升级就不展示啦。
game.c文件
#define _CRT_SECURE_NO_WARNINGS
#include"game.h"
//初始化棋盘
void Initialboard(char board[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
board[i][j] = ' ';
}
}
}
//打印棋盘
// | |
//---|---|—-
// | |
//---|—-|---
// | |
void Displayboard(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
if (i == 0)
{
for (j = 0; j < col; j++)
{
if (j == 0)
printf(" %d ", j);
else
printf(" %d ", j);
}
printf("\n");
}
printf("%d", i);
for (j = 0; j < col; j++)
{
printf(" %c ", board[i][j]);
if (j < (col - 1))
{
printf("|");
}
}
printf("\n");
if (i<row - 1)
{
for (j = 0; j < col; j++)
{
if (j == 0)
printf(" ---");
else
printf("---");
if (j < (col - 1))
printf("|");
}
}
printf("\n");
}
}
//实现玩家下棋
void playermove(char board[ROW][COL], int row, int col)
{
int i, j;
printf("请根据图示输入要走的坐标:");
while (1)
{
scanf("%d%d", &i, &j);
if (i >= 0 && i < 5 && j >= 0 && j <5 && board[i][j] == ' ')
{
board[i][j] = '*';
break;
}
else
printf("输入有误,请重新输入。");
}
}
void computermove(char board[ROW][COL], int row, int col)
{
while (1)
{
int i = rand() % row;
int j = rand() % col;
if (board[i][j] == ' ')
{
board[i][j] = '#';
break;
}
}
}
char Iswin(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col - 4; j++)
{
if (board[i][j] == board[i][j + 1] && board[i][j + 1] == board[i][j + 2] &&board[i][j+2]==board[i][j+3]&&board[i][j+3]==board[i][j+4]&& board[i][j] != ' ')
{
return board[i][j];
}
}
}
for (j = 0; j < col; j++)
{
for (i = 0; i < row - 4; i++)
{
if (board[i][j] == board[i + 1][j] && board[i + 1][j] == board[i + 2][j] && board[i + 2][j] == board[i + 3][j] && board[i + 3][j] == board[i + 4][j] && board[i][j] != ' ')
{
return board[i][j];
}
}
}
for (i = 0, j = 0; i < row - 4 && j < col - 4; i++, j++)
{
if (board[i][j] == board[i + 1][j + 1] && board[i + 1][j + 1] == board[i + 2][j + 2] && board[i + 2][j + 2] == board[i + 3][j + 3] && board[i + 3][j + 3] == board[i + 4][j + 4]&& board[i][j] != ' ')
{
return board[i][j];
}
}
for (i = row - 1, j = 0; i >= 0 && j < col - 4; i--, j++)
{
if (board[i][j] == board[i - 1][j + 1] && board[i - 1][j + 1] == board[i - 2][j + 2] && board[i - 2][j + 2] == board[i - 3][j + 3] && board[i - 3][j + 3] == board[i - 4][j + 4]&& board[i][j] != ' ')
{
return board[i][j];
}
}
return 'c';
}
char Isfull(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
if (board[i][j] == ' ')
return 'c';
}
}
return 'e';
}
五子棋(初阶).c文件
#define _CRT_SECURE_NO_WARNINGS
#include"game.h"
//说明:
//*是玩家走的棋子
//#是电脑走的棋子
void menu()
{
printf("*****************\n");
printf("**1,play 0,exit**\n");
printf("*****************\n");
printf("请选择:");
}
void game()
{
char win = 'c';
char board[ROW][COL] = { 0 };//创建棋盘
Initialboard(board, ROW, COL);//初始化棋盘
Displayboard(board, ROW, COL);//打印出棋盘的信息
while (1)
{
//玩家走
printf("玩家走\n");
playermove(board, ROW, COL);
Displayboard(board, ROW, COL);
win = Isfull(board, ROW, COL);
win = Iswin(board, ROW, COL);
if (win != 'c')
break;
//电脑走
printf("电脑走\n");
computermove(board, ROW, COL);
Displayboard(board, ROW, COL);
win = Isfull(board, ROW, COL);
win = Iswin(board, ROW, COL);
if (win != 'c')
break;
}
if (win == 'e')
printf("平局\n");
else if (win == '*')
printf("玩家赢\n");
else if (win == '#')
printf("电脑赢\n");
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
//菜单,让用户选择
menu();
scanf("%d", &input);
if (input != 0)
{
printf("游戏开始\n");
game();//游戏主体
}
else
{
printf("退出游戏\n");
break;
}
} while (input);
return 0;
}
3,最后解读
这里,我们再次合起来说吧,大家也可以看到,实际上和三子棋的实现没有多大的区别,主要的改变,都在规则部分,我们拿出来细说。
char Iswin(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col - 4; j++)
{
if (board[i][j] == board[i][j + 1] && board[i][j + 1] == board[i][j + 2] &&board[i][j+2]==board[i][j+3]&&board[i][j+3]==board[i][j+4]&& board[i][j] != ' ')
{
return board[i][j];
}
}
}
for (j = 0; j < col; j++)
{
for (i = 0; i < row - 4; i++)
{
if (board[i][j] == board[i + 1][j] && board[i + 1][j] == board[i + 2][j] && board[i + 2][j] == board[i + 3][j] && board[i + 3][j] == board[i + 4][j] && board[i][j] != ' ')
{
return board[i][j];
}
}
}
for (i = 0, j = 0; i < row - 4 && j < col - 4; i++, j++)
{
if (board[i][j] == board[i + 1][j + 1] && board[i + 1][j + 1] == board[i + 2][j + 2] && board[i + 2][j + 2] == board[i + 3][j + 3] && board[i + 3][j + 3] == board[i + 4][j + 4]&& board[i][j] != ' ')
{
return board[i][j];
}
}
for (i = row - 1, j = 0; i >= 0 && j < col - 4; i--, j++)
{
if (board[i][j] == board[i - 1][j + 1] && board[i - 1][j + 1] == board[i - 2][j + 2] && board[i - 2][j + 2] == board[i - 3][j + 3] && board[i - 3][j + 3] == board[i - 4][j + 4]&& board[i][j] != ' ')
{
return board[i][j];
}
}
return 'c';
}
可以看到,我们将规则又扩大了一些,从原本的三个扩大到了5个位置的相等,而之后同样也是返回数组里的元素,来帮助判断胜负。同时要注意不要越界访问了。
这就是今天的内容了,之后五子棋的进阶部分找时间再分享给大家,进阶部分更加精彩,有我自己捣鼓的一个简陋的登录系统(只是一个雏形,不能储存数据),以及玩家对战部分等,码字不易,大家点点关注,给我点个赞吧,我会坚持更新的。如果有错,请联系修改,你们的支持是我更新的动力。
参考资料:
五子棋图片 - 国内版 Bing images
三子棋图片 - 国内版 Bing images
|