前言:今天我们来用C语言写一个三子棋小游戏,三子棋,是黑白棋的一种。三子棋是一种民间传统游戏,又叫九宫棋、圈圈叉叉、一条龙、井字棋等。这里我们写的是玩家与电脑对战的一个代码,如果想跟朋友一起玩也可以自己稍作修改噢。
让我们往下看吧
目录:
首先想要做一个游戏就先明白游戏的规则和玩法,三子棋,就是在一个九宫格里面下子,两个人对战,每一个人每一轮下一子,当任意一方有横竖斜其中一种三子连线,即该方获胜。若九宫格填满,仍无连线,则为平局。
没错,这就是我们想写出来的游戏,那么接下来就是构思了↓
有了想法构思就很容易啦。
首先我们要确定我们代码中要实现的:
完成构思接下来就进入我们的代码领域了。
为了让整个代码更加可观,我们首先把代码分为三个板块:
1.test.c源文件
测试游戏和一些细节的补充。
2.game.h头文件
存放游戏函数的声明。
3.game.c源文件
整个游戏的实现。
首先我们来将代码的整体框架给写出来:
//先写一个菜单函数,让我们选择是否进入游戏
void menu()
{
printf("***********************************\n");
printf("*********** 1. play *********\n");
printf("*********** 0. exit *********\n");
printf("***********************************\n");
}
void game()//游戏主体的代码
{
}
int main()//主函数
{
int input = 0;
do
{
menu();//引用上面的菜单函数
printf("请选择>");
scanf("%d", &input);//选择是否进入游戏
switch (input)
{
case 1://输入1进入游戏
game();
break;
case 0://输入0退出游戏
printf("退出游戏\n");
break;
default://输入其他会提示输入有误
printf("输入有误\n");
break;
}
} while (input);
return 0;
}
然后我们要补充好game()的部分:
按照构思,我们先要把初始化的棋盘给写出来,那初始化棋盘如何写呢,一个九宫格的棋盘可以看作为九个空格和一个井字合起来,而且空格中需要输入东西,所以我们可以用一个二维数组了表示,如何横竖的井字,我们可以用符号" — " 和符号 " | "在二维数组的缝隙中接入。
那么直接写?不不不,还记得我们区分板块吗,在这里我们只需要命名几个函数,然后在game.c上写就可以啦
void game()//三子棋游戏的过程
{
char board[ROW][COL];//创建一个二维数组作为棋盘
//ROW为行,COL为列
InitBoard(board, ROW, COL);//初始化棋盘 - board的元素都给成空格
//将二维数组和行列传进函数
DisplayBoard(board, ROW, COL);//打印横竖的棋盘
//将二维数组和行列传进函数
}
然后接下来就是下棋的部分了。
再看回我们的构思,玩家和电脑轮流下棋。所以我们得写两个函数分别描述玩家下棋和电脑下棋。
void game()//三子棋游戏的过程
{
char board[ROW][COL];
InitBoard(board, ROW, COL);
DisplayBoard(board, ROW, COL);
PlayerMove(board, ROW, COL);//玩家下棋
DisplayBoard(board, ROW, COL);//打印玩家下棋后的棋盘
ComputerMove(board, ROW, COL);//电脑下棋
DisplayBoard(board, ROW, COL);//打印电脑下棋后的棋盘
}
然后我们需要是第三个构思。每一轮! 我们不可能一轮就分出胜负,所以我们要在玩家和电脑下棋之间放一个循环,同时我们再看第四个构思,当循环出来那么就是胜负已分了。
所以我们要在game()中添加一个循环和一个胜负条件还有平局条件:
这里我们可以设置一个判断胜负函数 IsWin,然后 给 IsWin函数设置返回值,结果为
void game()//三子棋游戏的过程
{
char board[ROW][COL];
InitBoard(board, ROW, COL);
DisplayBoard(board, ROW, COL);
char ret = 0;
while (1)//设置循环,当判断平局或胜负就跳出
{
PlayerMove(board, ROW, COL);
DisplayBoard(board, ROW, COL);
//设置一个判断胜负函数 IsWin
//在这里设置一个变量ret,接收IsWin返回的结果
ret = IsWin(board, ROW, COL);
if (ret != 'C')
{
break;//如果不等于C(continue),就是平局或胜负已分
//直接跳出循环
}
ComputerMove(board, ROW, COL);
DisplayBoard(board, ROW, COL);
ret = IsWin(board, ROW, COL);
if (ret != 'C')
{
break;//同上
}
}
//跳出循环后判断接收到的返回值
if (ret == '*')//假设玩家使用的是*
{
printf("游戏结束,玩家获胜!\n");
}
else if (ret == '#')//电脑使用的是#
{
printf("游戏结束,电脑获胜!\n");
}
else//如果上面两个都不是,且退出游戏了,那就是平局了。
{
printf("游戏结束,平局!\n");
}
}
以上就是我们test.c的代码。
写好主函数之后,那么头文件game.h中的函数声明就很容易写好了。
部分说明直接在代码中注释就可以了。
#pragma once //作用:让引头文件只引一次,防止头文件被多次包含。
//在这里我们几个模块需要的头文件的放这里就可以了
//到时候再在另外两个中直接引用 "game.h"就可以使用game.h中引用的头文件了。
#include
#include
#define ROW 3//定义行数
#define COL 3//定义列数
//初始化棋盘函数
void InitBoard(char board[ROW][COL], int row, int col);
//将二维数组和行列的值传进函数,下同
//打印横竖棋盘函数
void DisplayBoard(char board[ROW][COL], int row, int col);
//玩家下棋函数
void PlayerMove(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);
重头戏来了,整个代码的灵魂,也是最难写的部分来了。
前面写了那么多也仅仅是把构思的框架实现了而已,这里才是真正把游戏写出来的地方。
那我们一个一个来吧:
噢,放错了。应该是这个:
这里的话,初始化的时候,九宫格中都是空的,但是后续我们还要往里面填进玩家和电脑输入的符号,所以我们暂且要用空格表示。
代码:
void InitBoard(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;
for (i = 0; i < row; i++)
{
//打印数据
int j = 0;
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++)
{
printf("---");
if (j < col - 1)//比横少一次打印
printf("|");
}
}
printf("\n");
}
}
首先我们要提示到玩家进行游戏,然后为了统一和简化玩家操作,我们直接把玩家想画的地方改为坐标指示。比如1 1就是画第一行第一列。
然后我们也要判断玩家输入的坐标是否有效,要考虑坐标存不存在,坐标里面是否已经被画。
代码:
void PlayerMove(char board[ROW][COL], int row, int col)
{
printf("轮到玩家进行操作:>\n");
int x = 0;
int y = 0;
while (1)//设定一个死循环,直到玩家输对坐标才跳出去
{
printf("请输入坐标:>");
scanf("%d%d", &x, &y);//定义x,y作为坐标输入
if (x >= 1 && x <= row && y >= 1 && y <= col)
//判断是否在坐标范围内
{
if (board[x - 1][y - 1] == ' ')
//判断是否已被填写
{
board[x - 1][y - 1] = '*';
//都没有就将代表玩家的*填上
break;//跳出死循环
}
else
{
printf("坐标被占用,请重新输入\n");
}
}
else
{
printf("坐标非法,超出范围\n");
}
}
}
电脑操作就比玩家简单多了,直接设定一个符合坐标的随机值,再判断这个坐标为空格就可以了。
代码:
void ComputerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("轮到电脑进行操作:>\n");
while (1)//死循环,填进才跳出
{
x = rand() % row;
y = rand() % col;
//这里用到了随机函数,要记得在补充头文件,还有初始化时间戳。
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
判断胜负的条件也很简单,我们可以分别写出来:
代码:
char IsWin(char board[ROW][COL], int row, int col)
{
int i = 0;
//判断三行中是否有全为相同的符号
for (i = 0; i < row; i++)
{
if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][1] != ' ')
{
return board[i][1];//
}
}
//判断三列中是否有全为相同的符号
for (i = 0; i < col; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' ')
{
return board[1][i];
}
}
//判断对角线中是否有全为相同的符号
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
{
return board[1][1];
}
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
{
return board[1][1];
}
}
然后还有平局和继续游戏这两个情况还没有,我们可以写一个IsFull函数来决定是否结束游戏,:
int 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 0;//棋盘没满
}
}
}
return 1;//棋盘满了
}
然后再合并两个函数,因为我们需要在没有胜负之后再判断是平局还是继续游戏:
char IsWin(char board[ROW][COL], int row, int col)
{
int i = 0;
//判断三行
for (i = 0; i < row; i++)
{
if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][1] != ' ')
{
return board[i][1];//
}
}
//判断三列
for (i = 0; i < col; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' ')
{
return board[1][i];
}
}
//判断对角线
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
{
return board[1][1];
}
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
{
return board[1][1];
}
//判断平局
//如果棋盘满了返回1, 不满返回0
int ret = IsFull(board, row, col);//调用IsFull函数
if (ret == 1)
{
return 'Q';//这就是上面test.c里面一个else的情况,就是平局
}
//继续游戏
return 'C';//continue
}
到此就把game.c中需要的函数都实现了。
完整代码如下:
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void menu()
{
printf("***********************************\n");
printf("*********** 1. play *********\n");
printf("*********** 0. exit *********\n");
printf("***********************************\n");
}
void game()
{
char board[ROW][COL];
InitBoard(board, ROW, COL);
DisplayBoard(board, ROW, COL);
char ret = 0;
while (1)
{
PlayerMove(board, ROW, COL);
DisplayBoard(board, ROW, COL);
ret = IsWin(board, ROW, COL);
if (ret != 'C')
{
break;
}
ComputerMove(board, ROW, COL);
DisplayBoard(board, ROW, COL);
ret = IsWin(board, ROW, COL);
if (ret != 'C')
{
break;
}
}
if (ret == '*')
{
printf("游戏结束,玩家获胜!\n");
}
else if (ret == '#')
{
printf("游戏结束,电脑获胜!\n");
}
else
{
printf("游戏结束,平局!\n");
}
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));//电脑随机
do
{
menu();
printf("请选择>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误\n");
break;
}
} while (input);
return 0;
}
#pragma once
#include
#include
#include //随机值函数引头文件
#define ROW 3//行
#define COL 3//列
void InitBoard(char board[ROW][COL], int row, int col);
void DisplayBoard(char board[ROW][COL], int row, int col);
void PlayerMove(char board[ROW][COL], int row, int col);
void ComputerMove(char board[ROW][COL], int row, int col);
int IsFull(char board[ROW][COL], int row, int col);
char IsWin(char board[ROW][COL], int row, int col);
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
//将game.h引过来,实际上也把game.h中包含的头文件都引过来
void InitBoard(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;
for (i = 0; i < row; i++)
{
int j = 0;
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++)
{
printf("---");
if (j < col - 1)
printf("|");
}
}
printf("\n");
}
}
void PlayerMove(char board[ROW][COL], int row, int col)
{
printf("轮到玩家进行操作:>\n");
int x = 0;
int y = 0;
while (1)
{
printf("请输入坐标:>");
scanf("%d%d", &x, &y);//2 1 -- > 1 0
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (board[x - 1][y - 1] == ' ')
{
board[x - 1][y - 1] = '*';
break;
}
else
{
printf("坐标被占用,请重新输入\n");
}
}
else
{
printf("坐标非法,超出范围\n");
}
}
}
void ComputerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("轮到电脑进行操作:>\n");
while (1)
{
x = rand() % row;
y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
int 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 0;
}
}
}
return 1;
}
char IsWin(char board[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][1] != ' ')
{
return board[i][1];//
}
}
for (i = 0; i < col; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' ')
{
return board[1][i];
}
}
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
{
return board[1][1];
}
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
{
return board[1][1];
}
int ret = IsFull(board, row, col);
if (ret == 1)
{
return 'Q';
}
return 'C';
}
这就是三子棋小游戏的C语言写法啦,小白制作不易,有错的地方还请xdm指正,互相关注,共同进步。