C语言设计三子棋
1 游戏规则介绍
三子棋是一种民间传统游戏,又叫九宫棋、圈圈叉叉、一条龙、井字棋等1。用“井”字分出3×3的格子,双方轮流下棋子(可以用O或者X来区别),只要将自己的棋子连成直线就赢了2,游戏规则示例如图1所示。
游戏需要两个人,并遵守以下规则:
1)假定红方优先,双方交替下棋
2)每个格子只能放1个棋子
3)3个棋子在一条直线,即为胜利
2 设计游戏基本框架
2.1 程序流程图
首先设计基本的框架,流程图如图2所示。
程序开始后,首先显示初始化菜单,然后进行输入选择,当输入为0时,游戏结束,当输入为1时,开始游戏,输入其他数字,则会提示输入错误,并进行重新选择。
2.2 程序框架设计
参考代码如下所示,游戏基本功能将在子函数play()中实现。
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
void init()//初始化函数
{
/***************************************
函数功能:
输出初始化游戏启动菜单。
函数输入:
无
函数输出:
无
***************************************/
printf("*********************\n");
printf("*******三子棋********\n");
printf("**1.play 0.exit***\n");
printf("*********************\n");
}
void play()//玩游戏
{
/***************************************
函数功能:
实现游戏功能
函数输入:
无
函数输出:
无
***************************************/
}
int main()
{
int state = 0;
init();//初始化
loop: scanf("%d", &state);//输入选择状态
switch (state)
{
case 0:
printf("游戏结束。");
break;
case 1:
printf("游戏开始:\n");
play();//玩游戏
break;
default:
printf("输错了,请重新输入:>");
goto loop;
break;
}
return 0;
}
2.3 程序测试结果
可以看到程序运行后显示初始化菜单,当输入1,游戏开始,输入0,游戏结束,当输入其他(比如5或68时),会提示重新输入,第一步框架结构成功实现。
3 子函数实现:
下面开始实现游戏的功能,即完成play()函数。
3.1 子程序流程图
首先设计基本的框架,流程图如图4所示。
如图所示,首先进行初始化,然后选手下子,并在屏幕上打印棋盘,再判断是否分出胜负,并根据结果进行输出相应的结果。
3.2 程序代码
int play()//玩游戏
{
/***************************************
函数功能:
实现游戏功能
函数输入:
无
函数输出:
0:表示游戏结束
***************************************/
/*-----------------初始化------------------------*/
int red[3][3] = { 0 };//红方棋盘信息矩阵
int blue[3][3] = { 0 };//蓝方棋盘信息矩阵
int green[3][3] = { 0 };//棋盘总信息矩阵
int mat[3][3] = { 0 };//用于判断的矩阵
DYQP(red, blue);//显示初始棋盘
int shift = 0;//切换选手(使两个人交替下棋)
int state = 0;//鹿死谁手?(state用于储存棋局的结果)
/*---------------------------------------------*/
while (1)
{
QSLZ(&shift, red, blue);//棋手落子
DYQP(red, blue);//打印棋盘
state = JGPD(&shift, red, blue);//结果判断
switch (state)
{
case 0:
printf("继续,注意:观棋不语\n");
break;
case 1:
printf("和局\n");
return 0;
case 2:
printf("红方胜\n");
return 0;
case 3:
printf("蓝方胜\n");
return 0;
default://state
printf("程序又出错了么(ಥ﹏ಥ)\n");
return 0;//游戏中断
}
}
return 0;
}
该程序用到了三个子函数,分别是
- DYQP(red, blue);//打印棋盘程序函数
- QSLZ (&shift, red, blue);//棋手落子程序函数
- JGPD(&shift, red, blue);//结果判断程序函数
这三个会在后文实现,下面先讲一些游戏设计规则。
4 游戏设计规则
因为棋盘大小是3×3,所以可以将棋盘信息存储在一个3行3列的数组里。其中红方和蓝方的棋盘信息分开存储,便于结果检测。下面以图1的示例,展示棋盘信息存储的状况,如图5所示。
棋盘信息矩阵初始值皆为0,当一个位置落子后,相应的位置的值改为1。双方棋盘信息矩阵用来保证一个位置只能落一个棋子。棋盘的位置以坐标的形式确定,如图6所示。
5剩余子函数实现
5.1 打印棋盘程序函数
程序代码:
void DYQP(int (*red)[size], int (*blue)[size])
{
int i, j;
printf(" 0 1 2\n\n");
for (i = 0; i < size; i++)
{
printf("%d", i);
for (j = 0; j < size; j++)
{
if (red[i][j] == 1)
printf(" O");
else if (blue[i][j] == 1)
printf(" X");
else
printf(" #");
}
printf("\n");
}
}
红方的棋盘信息矩阵的值为1,则相应位置打印字符’O’, 蓝方的打印字符’X’,未落子的位置打印字符’#’。
5.2 棋手落子程序函数
程序代码:
void QSLZ(int* shift, int(*red)[size], int(*blue)[size], int(*green)[size])
{
/***************************************
函数功能:
棋手落子,存储棋盘信息
函数输入:
shift:(shift的值只能取0和1)
=0,红方落子
=1,蓝方落子
red:红方棋盘信息
blue:蓝方棋盘信息
green:红蓝双方的信息
函数输出:
无
***************************************/
int x, y;
switch (*shift)
{
case 0:
do
{
printf("红方(O)请输入坐标:>");
scanf("%d%d", &x, &y);
if (x > 2 || y > 2)
printf("坐标位置输入越界(ー00ー)\n");
else if (green[x][y] == 1)
printf("该位置已被人占(^_-)\n");
else
red[x][y] = 1;
}while ((x > 2 || y > 2)||(green[x][y] == 1));
green[x][y] = 1;
break;
case 1:
do
{
printf("蓝方(X)请输入坐标:>");
scanf("%d%d", &x, &y);
if (x > 2 || y > 2)
printf("坐标位置输入越界(ー00ー)\n");
else if (green[x][y] == 1)
printf("该位置已被人占(^_-)\n");
else
blue[x][y] = 1;
} while ((x > 2 || y > 2) || (green[x][y] == 1));
green[x][y] = 1;
break;
default :
printf("出错了么(* ̄rǒ ̄)");
break;
}
}
红方先落子,当输入的坐标不再棋盘范围内,或该位置被占,会有相应的提示,并且要求重新输入。
5.3 结果判断程序函数
程序代码:
int JGPD(int* shift, int (*red)[size], int (*blue)[size])//结果判断
{
switch (*shift)
{
case 0:
if(test(red) == 1)
{
return 1;//平局
}
else if (test(red) == 0)
{
return 2;//红胜
}
else
{
*shift = 1;//红方下完,转换成对手下棋状态
return 0;//继续战斗
}
break;
case 1:
if (test(blue) == 0)
{
return 3;
}
else
{
*shift = 0;//蓝方下完,转换成对手下棋状态
return 0;
}
break;
default:
return 0;
break;
}
}
平局输出1,红胜输出2,蓝胜输出3,未分出胜负则输出0。里面用到了胜利检测函数test(),其代码如下所示:
int test(int (*arr)[size])
{
/***************************************
函数功能:
判断棋盘结果
函数输入:
arr:
=red,红方棋盘判断
=blue,蓝方棋盘判断
***************************************/
int i, j;
int a = 0;
int b = 0;
int c = 0;
int d = 0;
int count = 0;
for (i = 0; i < size; i++)//(行列每次检测三次)
{
for (j = 0; j < size; j++)
{
if (arr[j][i])//列检测
a += 1;
if (arr[i][j])
{
b += 1;//行检测
count ++;// 和局判断
}
if (i == 0)//对角线只需检测一次
{
c += arr[j][j];//主对角线检测
d += (*arr)[2 * (j + 1)];//副对角线检测
}
}
if (a == 3 || b == 3 || c == 3 || d == 3)
{
return 0;//返回0就是胜利
}
else
{
a = 0;//清零,为下一列检测做准备
b = 0;
//c = 0;
//d = 0;
}
}
if (count == 5)//当count等于5时,说明平局。该检测针对红方,因为红方为先手,当红方棋子达到5个时,则为平局
{
return 1;
}
else
{
return 2;
}
}
6 总代码
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#define size 3
void init()//初始化函数
{
/***************************************
函数功能:
输出初始化游戏启动菜单。
函数输入:
无
函数输出:
无
***************************************/
printf("*********************\n");
printf("*******三子棋********\n");
printf("**1.play 0.exit***\n");
printf("*********************\n");
}
int test(int (*arr)[size])
{
/***************************************
函数功能:
判断棋盘结果
函数输入:
arr:
=red,红方棋盘判断
=blue,蓝方棋盘判断
函数输出:
无
***************************************/
int i, j;
int a = 0;
int b = 0;
int c = 0;
int d = 0;
int count = 0;
for (i = 0; i < size; i++)//(行列每次检测三次)
{
for (j = 0; j < size; j++)
{
if (arr[j][i])//列检测
a += 1;
if (arr[i][j])
{
b += 1;//行检测
count ++;// 和局判断
}
if (i == 0)//对角线只需检测一次
{
c += arr[j][j];//主对角线检测
d += (*arr)[2 * (j + 1)];//副对角线检测
}
}
if (a == 3 || b == 3 || c == 3 || d == 3)
{
return 0;//返回0就是胜利
}
else
{
a = 0;//清零,为下一列检测做准备
b = 0;
//c = 0;
//d = 0;
}
}
if (count == 5)//当count等于5时,说明平局。该检测针对红方,因为红方为先手,当红方棋子达到5个时,则为平局
{
return 1;
}
else
{
return 2;
}
}
int JGPD(int* shift, int (*red)[size], int (*blue)[size])//结果判断
{
switch (*shift)
{
case 0:
if(test(red) == 1)
{
return 1;//平局
}
else if (test(red) == 0)
{
return 2;//红胜
}
else
{
*shift = 1;//红方下完,转换成对手下棋状态
return 0;//继续战斗
}
break;
case 1:
if (test(blue) == 0)
{
return 3;
}
else
{
*shift = 0;//蓝方下完,转换成对手下棋状态
return 0;
}
break;
default:
return 0;
break;
}
}
void QSLZ(int* shift, int(*red)[size], int(*blue)[size], int(*green)[size])
{
/***************************************
函数功能:
棋手落子,存储棋盘信息
函数输入:
shift:(shift的值只能取0和1)
=0,红方落子
=1,蓝方落子
red:红方棋盘信息
blue:蓝方棋盘信息
green:红蓝双方的信息
函数输出:
无
***************************************/
int x, y;
switch (*shift)
{
case 0:
do
{
printf("红方(O)请输入坐标:>");
scanf("%d%d", &x, &y);
if (x > 2 || y > 2)
printf("坐标位置输入越界(ー00ー)\n");
else if (green[x][y] == 1)
printf("该位置已被人占(^_-)\n");
else
red[x][y] = 1;
}while ((x > 2 || y > 2)||(green[x][y] == 1));
green[x][y] = 1;
break;
case 1:
do
{
printf("蓝方(X)请输入坐标:>");
scanf("%d%d", &x, &y);
if (x > 2 || y > 2)
printf("坐标位置输入越界(ー00ー)\n");
else if (green[x][y] == 1)
printf("该位置已被人占(^_-)\n");
else
blue[x][y] = 1;
} while ((x > 2 || y > 2) || (green[x][y] == 1));
green[x][y] = 1;
break;
default :
printf("出错了么(* ̄rǒ ̄)");
break;
}
}
void DYQP(int (*red)[size], int (*blue)[size])//打印棋盘
{
int i, j;
printf(" 0 1 2\n\n");
for (i = 0; i < size; i++)
{
printf("%d", i);
for (j = 0; j < size; j++)
{
if (red[i][j] == 1)
printf(" O");
else if (blue[i][j] == 1)
printf(" X");
else
printf(" #");
}
printf("\n");
}
//printf(" | | \n");
//printf(" | | \n");
//printf("————————\n");
//printf(" | | \n");
//printf(" | | \n");
//printf("————————\n");
//printf(" | | \n");
//printf(" | | \n");
}
int play()//玩游戏
{
/***************************************
函数功能:
实现游戏功能
函数输入:
无
函数输出:
0:表示游戏结束
***************************************/
/*-----------------初始化------------------------*/
int red[3][3] = { 0 };//红方棋盘信息矩阵
int blue[3][3] = { 0 };//蓝方棋盘信息矩阵
int green[3][3] = { 0 };//棋盘总信息矩阵
int mat[3][3] = { 0 };//用于判断的矩阵
DYQP(red, blue);//显示初始棋盘
int shift = 0;//切换选手(使两个人交替下棋)
int state = 0;//鹿死谁手?(state用于储存棋局的结果)
/*---------------------------------------------*/
while (1)
{
QSLZ(&shift, red, blue, green);//棋手落子
DYQP(red, blue);//打印棋盘
state = JGPD(&shift, red, blue);//结果判断
switch (state)
{
case 0:
printf("继续,注意:观棋不语\n");
break;
case 1:
printf("和局\n");
return 0;
case 2:
printf("红方胜\n");
return 0;
case 3:
printf("蓝方胜\n");
return 0;
default://state
printf("程序又出错了么(ಥ﹏ಥ)\n");
return 0;//游戏中断
}
}
return 0;
}
int main()
{
int state = 0;
init();//初始化菜单
loop: scanf("%d", &state);//输入选择状态
switch (state)
{
case 0:
printf("游戏结束。");
break;
case 1:
printf("游戏开始:\n");
play();//玩游戏
break;
default:
printf("输错了,请重新输入:>");
goto loop;
break;
}
return 0;
}
6.1 运行结果
总结
代码还有待改进的地方,以后还会继续改进。如果你有改进的想法可以告诉我,我试着实现。