本篇文章旨在探讨用C语言实现三子棋的简单写法,电脑只会随机的生成一个格子而不会判断下哪步棋子胜率更高。
首先简单介绍一下三子棋:三子棋,民间传统游戏,又叫九宫棋、圈圈叉叉、一条龙等。将正方形对角线连起来,相对两边依次摆上三个双方棋子,只要将自己的三个棋子走成一条线,对方就算输了。如果两个人都掌握了技巧,那么一般来说就是平棋。
一、三子棋游戏实现的基本逻辑
首先我们应该考虑到三子棋的代码较多,为了方便代码的管理与调试,我们讲代码分别放入三个文件中分别将其命名为
test.c 用来测试整个三子棋游戏的逻辑
game.h 游戏函数的声明
game.c 游戏函数的实现
初步计划:
1、打印游戏菜单
2、初始化棋盘
3、打印棋盘
4、下棋
(1)玩家下棋‘*’表示
(2)判断输赢
(3)电脑下棋‘#’表示
(4)判断输赢
5、打印最终棋型
6、询问是否继续
二、具体函数的实现
//定义宏
//引用头文件
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ROW 3
#define COL 3
首先写出函数的具体框架
#include <stdio.h>
#include <stdlib.h>
int main()
{
menu(); //打印菜单
system("pause");
return 0;
}
我们不妨让输入1为开始,输入0为退出,则menu()函数的写法即
#include <stdio.h>
#include <stdlib.h>
void menu()
{
printf("********************************\n");
printf("**** 1. play 0.exit *****\n");
printf("********************************\n");
printf("\n\n\n");
}
int main()
{
menu(); //打印菜单
system("pause");
return 0;
}
当输入1时为开始我们的game()函数,输入0时为结束,而输入其它数字应该报错重新输入,所以我们选择do while语句和switch语句实现
#include <stdio.h>
#include <stdlib.h>
void menu()
{
printf("********************************\n");
printf("**** 1. play 0.exit *****\n");
printf("********************************\n");
printf("\n\n\n");
}
int main()
{
int input=0;
do
{
menu(); //打印菜单
printf("请选择:>");
scanf("%d", &input);
switch( input )
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误!\n");
break;
}while(input);
system("pause");
return 0;
}
接下来我们该编辑我们的game主体函数
首先我们要初始化棋盘
接着我们需要打印棋盘
之后我们要下棋并且判断输赢:我们用IsWin()函数来判断输赢的结果,如果玩家赢则返回‘*’,如果玩家输则返回‘#’,如果继续则返回‘c',此外我们不能忘记还有一种平局情况,如果平局函数则返回‘Q’
PlayerMove()表示玩家下棋
ComputerMove()表示电脑下棋
我们分别用函数来实现这些功能
void game()
{
char ret = 0;
char board[ROW][COL]={0};
//初始化棋盘的函数
InitBoard(board ,ROW ,COL );
//打印棋盘
DisplayBoard(board ,ROW ,COL);
//下棋
printf("前一位数字表示行数,后一位数字表示列数\n");
//我们可以简单的用死循环来描述下棋与判断输赢的过程
while(1)
{
PlayerMove(board, ROW , COL);
//判断输赢
//用ret来接收返回值
ret = IsWin(board ,ROW , COL);
if(ret!='C')
{
break;
}
DisplayBoard(board ,ROW ,COL);
ComputerMove(board ,ROW ,COL);
//判断输赢
ret = IsWin(board ,ROW , COL);
if(ret!='C')
{
break;
}
DisplayBoard(board ,ROW ,COL);
}
//最后根据ret的值打印结果
if(ret=='*')
{
printf("恭喜你,你赢了!\n");
printf("\n\n\n\n");
}
else if(ret=='#')
{
printf("真不好意思,你电脑赢了。\n");
printf("\n\n\n\n");
}
else
{
printf("平局。\n");
printf("\n\n\n\n");
}
DisplayBoard(board ,ROW ,COL);
}
即test.c的主体格式为
#include <stdio.h>
#include <stdlib.h>
void menu()
{
printf("********************************\n");
printf("**** 1. play 0.exit *****\n");
printf("********************************\n");
printf("\n\n\n");
}
void game()
{
char ret = 0;
char board[ROW][COL]={0};
//初始化棋盘的函数
InitBoard(board ,ROW ,COL );
//打印棋盘
DisplayBoard(board ,ROW ,COL);
//下棋
printf("前一位数字表示行数,后一位数字表示列数\n");
//我们可以简单的用死循环来描述下棋与判断输赢的过程
while(1)
{
PlayerMove(board, ROW , COL);
//判断输赢
//用ret来接收返回值
ret = IsWin(board ,ROW , COL);
if(ret!='C')
{
break;
}
DisplayBoard(board ,ROW ,COL);
ComputerMove(board ,ROW ,COL);
//判断输赢
ret = IsWin(board ,ROW , COL);
if(ret!='C')
{
break;
}
DisplayBoard(board ,ROW ,COL);
}
//最后根据ret的值打印结果
if(ret=='*')
{
printf("恭喜你,你赢了!\n");
printf("\n\n\n\n");
}
else if(ret=='#')
{
printf("真不好意思,你电脑赢了。\n");
printf("\n\n\n\n");
}
else
{
printf("平局。\n");
printf("\n\n\n\n");
}
DisplayBoard(board ,ROW ,COL);
}
int main()
{
int input=0;
do
{
menu(); //打印菜单
printf("请选择:>");
scanf("%d", &input);
switch( input )
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误!\n");
break;
}while(input);
system("pause");
return 0;
}
为了避免game.c中声明函数过多,我们直接在game.h中完成函数的声明与宏的定义,此外,还要询问玩家是否重来
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#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);
//判断输赢: 玩家赢'*' 电脑赢'#' 平局'Q' 继续'C'
char IsWin(char board[ROW][COL],int row , int col );
//是否重来
void Compete (int * input);
接下来编写game.c文件
在vsCode编译器下想要用到同一个文件夹中的文件均需要引用,所以我们既要引用.h 文件,也要引用 .c 文件
#include "game.h"
#include "test.c"
初始化棋盘函数我们期望用二维数组来实现
void InitBoard(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++)
{
board[i][j]= ' ';
}
}
}
打印棋盘也是一件需要思考的事情,我们如果用到数组,那么我们下棋的步骤就会十分简化
void DisplayBoard(char board[ROW][COL], int row ,int col)
{
int i=0;
for(i=0;i< row; i++)
{
//打印数据
//printf(" %c | %c | %c \n",board[i][0],board[i][1],board[i][2]);
//这种写法太捞了
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)
{
int j=0;
for(j=0;j<col;j++)
{
printf("---");
if(j<col-1)
printf("|");
}
printf("\n");
}
}
}
接下来我们期望用坐标来实现棋子的移动
void PlayerMove(char board[ROW][COL], int row ,int col )
{
int x=0;
int y=0;
while(1)
{
printf("玩家下棋(请输入坐标):>");
scanf("%d %d",&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");
}
}
}
电脑移动时,我们需要生成一个随机数,这里既需要函数内编写,又需要回到test.c文件中生成一个时间戳
void ComputerMove(char board[ROW][COL] ,int row ,int col)
{
printf("电脑下棋:>\n");
int x=0;
int y=0;
while(1)
{
x=rand()%row; //0~2
y=rand()%col; //0~2
if(board[x][y]==' ')
{
board[x][y]= '#';
break;
}
}
}
test.c文件的修改
#include <stdio.h>
#include <stdlib.h>
void menu()
{
printf("********************************\n");
printf("**** 1. play 0.exit *****\n");
printf("********************************\n");
printf("\n\n\n");
}
void game()
{
char ret = 0;
char board[ROW][COL]={0};
//初始化棋盘的函数
InitBoard(board ,ROW ,COL );
//打印棋盘
DisplayBoard(board ,ROW ,COL);
//下棋
printf("前一位数字表示行数,后一位数字表示列数\n");
//我们可以简单的用死循环来描述下棋与判断输赢的过程
while(1)
{
PlayerMove(board, ROW , COL);
//判断输赢
//用ret来接收返回值
ret = IsWin(board ,ROW , COL);
if(ret!='C')
{
break;
}
DisplayBoard(board ,ROW ,COL);
ComputerMove(board ,ROW ,COL);
//判断输赢
ret = IsWin(board ,ROW , COL);
if(ret!='C')
{
break;
}
DisplayBoard(board ,ROW ,COL);
}
//最后根据ret的值打印结果
if(ret=='*')
{
printf("恭喜你,你赢了!\n");
printf("\n\n\n\n");
}
else if(ret=='#')
{
printf("真不好意思,你电脑赢了。\n");
printf("\n\n\n\n");
}
else
{
printf("平局。\n");
printf("\n\n\n\n");
}
DisplayBoard(board ,ROW ,COL);
}
int main()
{
srand((unsigned int )time(NULL));
int input=0;
do
{
menu(); //打印菜单
printf("请选择:>");
scanf("%d", &input);
switch( input )
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误!\n");
break;
}while(input);
system("pause");
return 0;
}
判断棋盘是否填满
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];
}
}
//判断列
int j=0;
for(j=0;j<col;j++)
{
if(board[0][j]==board[1][j] && board[1][j]==board[2][j] && board[1][j] != ' ' )
{
return board[1][j];
}
}
//判断对角线
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];
}
判断平局
//没有人赢,则此时应该判断平局
if(IsFull(board ,row, col))
{
return 'Q';
}
else{
return 'C';
}
则整个项目整体形式
game.h
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#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);
//判断输赢: 玩家赢'*' 电脑赢'#' 平局'Q' 继续'C'
char IsWin(char board[ROW][COL],int row , int col );
//是否重来
void Compete (int * input);
test.c
#include "game.h"
void menu()
{
printf("********************************\n");
printf("**** 1. play 0.exit *****\n");
printf("********************************\n");
printf("\n\n\n");
}
void game()
{
char ret = 0;
char board[ROW][COL]={0};
//初始化棋盘的函数
InitBoard(board ,ROW ,COL );
DisplayBoard(board ,ROW ,COL);
//下棋
printf("\n温馨提示:坐标的输入的格式是(数字)+(空格)+(数字)+(回车)\n");
printf("前一位数字表示行数,后一位数字表示列数\n");
while(1)
{
PlayerMove(board, ROW , COL);
//判断输赢
ret = IsWin(board ,ROW , COL);
if(ret!='C')
{
break;
}
DisplayBoard(board ,ROW ,COL);
ComputerMove(board ,ROW ,COL);
//判断输赢
ret = IsWin(board ,ROW , COL);
if(ret!='C')
{
break;
}
DisplayBoard(board ,ROW ,COL);
}
if(ret=='*')
{
printf("恭喜你,你赢了!\n");
printf("\n\n\n\n");
}
else if(ret=='#')
{
printf("真不好意思,你电脑赢了。\n");
printf("\n\n\n\n");
}
else
{
printf("平局。\n");
printf("\n\n\n\n");
}
DisplayBoard(board ,ROW ,COL);
}
int main()
{
srand((unsigned int )time(NULL));
int input=0;
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch( input )
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误!\n");
break;
}
}while(input);
system("pause");
return 0;
}
game.c
#include "game.h"
#include "test.c"
void InitBoard(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++)
{
board[i][j]= ' ';
}
}
}
void DisplayBoard(char board[ROW][COL], int row ,int col)
{
int i=0;
for(i=0;i< row; i++)
{
//打印数据
//printf(" %c | %c | %c \n",board[i][0],board[i][1],board[i][2]);
//这种写法太捞了
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)
{
int j=0;
for(j=0;j<col;j++)
{
printf("---");
if(j<col-1)
printf("|");
}
printf("\n");
}
}
}
void PlayerMove(char board[ROW][COL], int row ,int col )
{
int x=0;
int y=0;
while(1)
{
printf("玩家下棋(请输入坐标):>");
scanf("%d %d",&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)
{
printf("电脑下棋:>\n");
int x=0;
int y=0;
while(1)
{
x=rand()%row; //0~2
y=rand()%col; //0~2
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];
}
}
//判断列
int j=0;
for(j=0;j<col;j++)
{
if(board[0][j]==board[1][j] && board[1][j]==board[2][j] && board[1][j] != ' ' )
{
return board[1][j];
}
}
//判断对角线
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];
}
//没有人赢,则此时应该判断平局
if(IsFull(board ,row, col))
{
return 'Q';
}
else{
return 'C';
}
}
三、优化
不知道有没有细心的小伙伴发现我们还没有编写头文件当中的最后一个函数,没错,我们要询问是不是玩家要重来,我们可以采用一个巧妙地goto语句来化解
test.c文件
#include "game.h"
void menu()
{
printf("********************************\n");
printf("**** 1. play 0.exit *****\n");
printf("********************************\n");
printf("\n\n\n");
}
void game()
{
char ret = 0;
char board[ROW][COL]={0};
//初始化棋盘的函数
InitBoard(board ,ROW ,COL );
DisplayBoard(board ,ROW ,COL);
//下棋
printf("\n温馨提示:坐标的输入的格式是(数字)+(空格)+(数字)+(回车)\n");
printf("前一位数字表示行数,后一位数字表示列数\n");
while(1)
{
PlayerMove(board, ROW , COL);
//判断输赢
ret = IsWin(board ,ROW , COL);
if(ret!='C')
{
break;
}
DisplayBoard(board ,ROW ,COL);
ComputerMove(board ,ROW ,COL);
//判断输赢
ret = IsWin(board ,ROW , COL);
if(ret!='C')
{
break;
}
DisplayBoard(board ,ROW ,COL);
}
if(ret=='*')
{
printf("恭喜你,你赢了!\n");
printf("\n\n\n\n");
}
else if(ret=='#')
{
printf("真不好意思,你电脑赢了。\n");
printf("\n\n\n\n");
}
else
{
printf("平局。\n");
printf("\n\n\n\n");
}
DisplayBoard(board ,ROW ,COL);
}
int main()
{
srand((unsigned int )time(NULL));
int input=0;
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch( input )
{
case 1:
next:
game();
Compete(&input);
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误!\n");
break;
}
if(input==1)
{
goto next;
}
}while(input);
system("pause");
return 0;
}
game.h文件
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#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);
//判断输赢: 玩家赢'*' 电脑赢'#' 平局'Q' 继续'C'
char IsWin(char board[ROW][COL],int row , int col );
//是否重来
void Compete (int * input);
game.c文件
#include "game.h"
#include "test.c"
void InitBoard(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++)
{
board[i][j]= ' ';
}
}
}
void DisplayBoard(char board[ROW][COL], int row ,int col)
{
int i=0;
for(i=0;i< row; i++)
{
//打印数据
//printf(" %c | %c | %c \n",board[i][0],board[i][1],board[i][2]);
//这种写法太捞了
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)
{
int j=0;
for(j=0;j<col;j++)
{
printf("---");
if(j<col-1)
printf("|");
}
printf("\n");
}
}
}
void PlayerMove(char board[ROW][COL], int row ,int col )
{
int x=0;
int y=0;
while(1)
{
printf("玩家下棋(请输入坐标):>");
scanf("%d %d",&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)
{
printf("电脑下棋:>\n");
int x=0;
int y=0;
while(1)
{
x=rand()%row; //0~2
y=rand()%col; //0~2
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];
}
}
//判断列
int j=0;
for(j=0;j<col;j++)
{
if(board[0][j]==board[1][j] && board[1][j]==board[2][j] && board[1][j] != ' ' )
{
return board[1][j];
}
}
//判断对角线
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];
}
//没有人赢,则此时应该判断平局
if(IsFull(board ,row, col))
{
return 'Q';
}
else{
return 'C';
}
}
void Compete (int * input)
{
printf("\n 还要再玩一次吗?\n");
printf("********************************\n");
printf("**** 1. YES 0.NO *****\n");
printf("********************************\n");
printf("请输入:>");
int rot = 0;
scanf("%d" ,&rot);
(* input)=rot;
}
此时程序运行起来,一个漂亮的三子棋游戏就展现在面前啦!