今天我们来完成一个项目 用c语言实现三子棋
先说一下代码的基本逻辑
1.显示棋盘
2. 电脑或玩家下棋
3. 检查结果
4. 电脑或玩家下棋
5. 检查结果
6. 判断胜负
下面是代码实操
添加头文件
由于函数较多,写在一起比较乱,首先我们先创建一个头文件命名为game.h 再定义一个源文件 game.c ,为了方便使用,我们再写一个公共的头文件库 untili.h,这样我们在使用的时候通过引用untili就相当于引用全部的头文件了,最后创建一个源文件,是我们的主函数,命名为gamemain.c,这里的操作放出来一个,以此类推
下面我们开始写函数
0.主要函数以及头文件
#game.h
#ifndef _GAME_H_
#define _GAME_H_
#include"untili.h"
void InitGame();
void ShowchessBoard();
void ComputerChoice();
bool IsFull();
char CheckResult();
void gamerchoice();
void startgame();
//int VictoryJudgment(char winner);
#endif /* _GAME_H_ */
untili.h
#ifndef _UTILI_H_
#define _UTILI_H_
#include<stdio.h>
#include"time.h"
#include<stdbool.h>
#include<stdlib.h>
#endif /* _UTILI_H_ */
1.显示棋盘
void InitGame()
{
for (int i = 0; i < ROW; ++i)
{
for (int j = 0; j < COL; ++j)
{
chess_board[i][j] = ' ';
}
}
}
void ShowchessBoard()
{
for (int i = 0; i < ROW; ++i)
{
printf("| %c | %c | %c |\n", chess_board[i][0],
chess_board[i][1],
chess_board[i][2]);
if (i + 1 != ROW)
printf(" --- --- ---\n");
}
}
数组的定义和宏请参考开头的函数表(row和col都是3)
InitGame()的作用是把一个3*3的二维数组全都变成空格,方便落子
ShowchessBoard()的作用则是围成一个棋盘的形状
2.电脑下棋
在这里,我们先让电脑下棋,到全部完成一会是可以选择谁先下的
void ComputerChoice()
{
int x, y;
while (1)
{
srand(time(0));
x = rand() % ROW;
y = rand() % COL;
if (chess_board[x][y] == ' ')
{
chess_board[x][y] = 'x';
break;
}
}
}
ComputerChoice()函数中使用了一个用时间随机种子产生随机数的方法,在使用这个方法之前我们先要引用一个头文件 stdio<time.h>
**srand(time(0));**就是用时间做随机种子,好处就是没有任何一个时刻的时间是相同的,所以我们可以放心他产生的随机数都是完全随机的。**x = rand() % ROW;**的意思就是产生一个0-ROW之间的随机数(0,1,2)。
在这里我们进行了一个判断,如果随机出来的数组元素里边是空格的话,我们就让他为’x’代表电脑下在了这里。
3.检查结果
在电脑或者我们每次下完棋以后,必须进行一次检查,检查有没有人胜出,或者是和棋,三子棋的规则是横竖斜三个连成一片就算赢,所以我们判断的逻辑就是,判断横着竖着斜着的连着的三个元素是不是一样。代码如下
bool IsFull()
{
for (int i = 0; i < ROW; ++i)
{
for (int j = 0; j < COL; ++j)
{
if (chess_board[i][j] == ' ')
{
return false;
}
}
}
return true;
}
char CheckResult()
{
for (int i = 0; i < ROW; ++i)
{
if (chess_board[i][0] != ' ' && chess_board[i][0] == chess_board[i][1]
&& chess_board[i][0] == chess_board[i][2])
{
return chess_board[i][0];
}
for (int i = 0; i < ROW; ++i)
{
if (chess_board[0][i] != ' ' && chess_board[0][i] == chess_board[1][i]
&& chess_board[0][i] == chess_board[2][i])
{
return chess_board[0][i];
}
}
if (chess_board[1][1] != ' '
&& chess_board[0][0] == chess_board[1][1]
&& chess_board[0][0] == chess_board[2][2])
return chess_board[1][1];
if (chess_board[1][1] != ' '
&& chess_board[0][2] == chess_board[1][1]
&& chess_board[0][2] == chess_board[2][0])
return chess_board[1][1];
}
if (IsFull())
return 'h';
return 'c';
}
在这里char CheckResult()函数的作用就是刚才说的判断横竖斜,这里不再赘述,我们说一下
IsFull()函数,这个函数的作用是判断有没有产生平局,产生了就返回真,没产生就返回假,他是通过循环遍历数组,看数组中还有没有空格,有,就是还没有和棋。
返回’x’电脑赢
返回’o’玩家赢
返回’c’继续(棋盘没满)
返回’h’和棋(棋盘满了)
4.玩家下棋
void gamerchoice()
{
printf("请您落子\n");
int x, y;
while (1)
{
printf("您输入的坐标为:");
scanf_s("%d %d", &x, &y);
if (chess_board[x][y] == ' ')
{
chess_board[x][y] = 'o';
break;
}
else
{
printf("您输入的位置已落子,请重新输入");
}
}
}
玩家下棋的方式和电脑区别就在于一个随机产生,一个主动输入,这里不再赘述
5.再次检查结果
和上一次判断完全相同
6.判断胜负以及game.c全局代码
判断胜负我们可以用一个char类型的变量来储存检查结果返回的值
game.c全局代码如下
#include"game.h"
#define ROW 3
#define COL 3
static char chess_board[ROW][COL];
// 基本逻辑
//1.登陆界面
// (1)显示棋盘
void InitGame()
{
for (int i = 0; i < ROW; ++i)
{
for (int j = 0; j < COL; ++j)
{
chess_board[i][j] = ' ';
}
}
}
void ShowchessBoard()
{
for (int i = 0; i < ROW; ++i)
{
printf("| %c | %c | %c |\n", chess_board[i][0],
chess_board[i][1],
chess_board[i][2]);
if (i + 1 != ROW)
printf(" --- --- ---\n");
}
}
//2.电脑下棋
void ComputerChoice()
{
int x, y;
while (1)
{
srand(time(0));
x = rand() % ROW;
y = rand() % COL;
if (chess_board[x][y] == ' ')
{
chess_board[x][y] = 'x';
break;
}
}
}
//3.判断输赢
// 返回'x'电脑赢
// 返回'o'玩家赢
// 返回'c'继续(棋盘没满)
// 返回'h'和棋(棋盘满了)
bool IsFull()
{
for (int i = 0; i < ROW; ++i)
{
for (int j = 0; j < COL; ++j)
{
if (chess_board[i][j] == ' ')
{
return false;
}
}
}
return true;
}
char CheckResult()
{
for (int i = 0; i < ROW; ++i)
{
if (chess_board[i][0] != ' ' && chess_board[i][0] == chess_board[i][1]
&& chess_board[i][0] == chess_board[i][2])
{
return chess_board[i][0];
}
for (int i = 0; i < ROW; ++i)
{
if (chess_board[0][i] != ' ' && chess_board[0][i] == chess_board[1][i]
&& chess_board[0][i] == chess_board[2][i])
{
return chess_board[0][i];
}
}
if (chess_board[1][1] != ' '
&& chess_board[0][0] == chess_board[1][1]
&& chess_board[0][0] == chess_board[2][2])
return chess_board[1][1];
if (chess_board[1][1] != ' '
&& chess_board[0][2] == chess_board[1][1]
&& chess_board[0][2] == chess_board[2][0])
return chess_board[1][1];
}
if (IsFull())
return 'h';
return 'c';
}
//4.玩家下棋
void gamerchoice()
{
printf("请您落子\n");
int x, y;
while (1)
{
printf("您输入的坐标为:");
scanf_s("%d %d", &x, &y);
if (chess_board[x][y] == ' ')
{
chess_board[x][y] = 'o';
break;
}
else
{
printf("您输入的位置已落子,请重新输入");
}
}
}
//5.判断输赢
//6.游戏界面
void startgame()
{
InitGame();
char winner;
int mode;
printf("请选择您的游戏模式 :输入 1 您先下,输入 0 电脑先下\n");
scanf_s("%d", &mode);
while(1)
{
if (mode)
{
ShowchessBoard();
gamerchoice();
winner = CheckResult();
if (winner != 'c')
break;
ComputerChoice();
winner = CheckResult();
if (winner != 'c')
break;
}
else
{
ComputerChoice();
ShowchessBoard();
winner = CheckResult();
if (winner != 'c')
break;
gamerchoice();
winner = CheckResult();
if (winner != 'c')
break;
}
}
ShowchessBoard();
if (winner == 'x')
{
printf("很遗憾,您输了,是否再来一局: 输入:1再来,输入:0结束\n");
}
if (winner == 'o')
{
printf("恭喜您,您赢了,是否再来一局: 输入:1再来,输入:0结束\n");
}
if (winner == 'h')
{
printf("双方棋逢对手,是否再来一局: 输入:1再来,输入:0结束\n");
}
}
在这里我们实现了一个功能就是选择模式,是电脑先下还是玩家先下,但是操作过程比较简陋,希望各位看官能指导一下
7.登录界面
登录界面的操作比较简单.
int main()
{
int choose;
int select = 1;
while (select)
{
printf("*******************************\n");
printf("* 简 易 三 子 棋 *\n");
printf("*******************************\n");
printf("* [1] Play [0] Exit *\n");
printf("*******************************\n");
printf("请选择:>");
scanf_s("%d", &select);
if (select == 0)
{
break;
}
if (select != 1)
{
printf("error again\n");
continue;
}
do {
startgame();
scanf_s("%d", &choose);
system("cls");
} while (choose);
}
printf("************ GoodBye *********\n");
return 0;
}
在gamemain.c这个主函数中,我们主要实现了几点功能,一个是显示了游戏的登录界面
另一个重要功能就是通过do while循环来控制游戏次数,可以多次进行游戏:
总结
到这里呢,我们的三子棋项目就算完成了,但是还有几点问题
1.发现使用时间做随机种子电脑下的越来越慢了,到最后程序几乎就停住了
2.代码不够简洁
3.还有些功能可以开发出来(比如计分板)
有任何不明白的地方都可以在评论区中提出,还请各位给上珍贵的指导意见。