废话不多说,直接按实验报告格式来。
一、 实验目的
(1)实现利用计算机评判两个人五子棋比赛游戏。
(2)用C语言提供的图形库函数实现绘制五子棋棋盘。
(3)实现五子棋规则评判算法。
二、 实验内容
五子棋对战游戏设计
三、 分析与设计
(1)编写函数void GameInit(),它的功能是:initgraph(500,440)函数用来创建一个500*440的窗口,loadimage(NULL,L"Background1.jpg")函数用来添加文件名为Background1的背景图片, setlinecolor(BLACK)函数设置棋盘线条颜色为黑色,setlinestyle(PS_SOLID,2)作用为设置线条的粗细,line()函数用来画出棋盘,settextcolor(BLACK)函数设置提示字体为黑色,setbkmode(0)函数将字体背景设置成全透明,outtextxy()函数用来显示所要在游戏界面显示的字体。
(2)编写函数int playChess(void),它的功能是:
① 变量Mouse利用GetMouseMsg()函数来获取鼠标点击信息,变量Key利用GetAsyncKeyState(VK_ESCAPE)函数来判断Esc按键是否按下。
② 若Key小于0,代表Esc按键按下,弹出消息提示窗口,可选择是否退出。
③ Mouse.x和Mouse.y为鼠标左键点击处的x轴和y轴的坐标点,将所有棋盘交点进行遍历,若鼠标点击在某一点半径为11的圆内,那么将该点坐标x,y记下,并将其二维数组号a,b进行储存。
④ 用Mouse.uMsg判断鼠标左键是否按下,若二维数组board判断不为0,代表该处已下棋子,弹出提示窗口,点击确定键可以继续游戏。
⑤ 利用flag变量对当前下的棋子色号进行判断,flag对2取余为0则下黑棋,否则下白棋,并将二维数组board进行赋值,1为黑棋,2为白棋。当flag大于等于400时,弹出窗口,提示平局。
⑥ 利用JudgeWin()函数进行判断黑棋或白棋胜利,当有玩家胜利时,JudgeWin()函数的返回值为1,在此时flag对21取余为2是黑棋胜利,否则白棋胜利,并提示是否重新开始游戏。
(3)编写函数int JudgeWin(int a,int b),它的功能是:t的值为2 - flag % 2用来判断当前下棋者的棋子颜色,
① 以x轴ContLimit(a - 4) - ContLimit(a + 4),开始检测连续点,若连续点>=5,则判定该玩家胜利。
② 以y轴a不变,ContLimit(b - 4) - ContLimit(b + 4),开始检测连续点,若连续点>=5,则判定该玩家胜利。
③ 以y = x轴,(a - 4) - (a + 4),(b - 4) - (b + 4),开始检测连续点,若连续点>=5,则判定该玩家胜利。
④ 以y = -x轴,(a - 4) - (a + 4),(b + 4) - (b - 4),开始检测连续点,若连续点>=5,则判定该玩家胜利。
(4)函数int ContLimit(int n),它的功能是用来限制a或b的值在0 – 20之间,不超出二维数组board的存储范围。
四、 代码设计
void GameInit()
{
//利用图形库创建一个窗口
initgraph(500,440);
//添加背景图片,引号前加L是因为要将格式改成多字节字符集
loadimage(NULL,L"Background1.jpg");
setlinecolor(BLACK); //将棋盘线条颜色改为黑色
setlinestyle(PS_SOLID,2);//将线条加粗
//绘制棋盘
line(21,21,21+399,21); //横轴
for(int i=1;i<=20;i++)
{
line(i*21,21,i*21,399+21); //纵轴
line(21,21+i*21,21+399,21+i*21); //横轴
}
settextcolor(BLACK); //将背景字体设置为黑色
setbkmode(0); //将背景字体设置透明
/*显示下棋方*/
outtextxy(435,50,L"玩家1:"); //图形库文字函数(x,y,"显示字符")
outtextxy(465,70,L"黑棋");
outtextxy(435,120,L"玩家2:");
outtextxy(465,140,L"白棋");
outtextxy(435,220,L"Esc:"); //
outtextxy(435,240,L"退出游戏"); //
}
int playChess(void) //鼠标下棋函数
{
//鼠标右键点击
MOUSEMSG Mouse; //鼠标结构体变量
/*a,b为二维数组号,x,y为当前鼠标点击的坐标*/
int a = 0;
int b = 0;
int x = 0;
int y = 0;
HWND hwnd; //窗口句柄
hwnd = GetHWnd();//窗口置前
int ret = 0; //判断游戏是否结束标志
int KeyRet = 0; //键盘判断是否退出游戏
int Key = 0; //用作键盘热键判断的变量
while(1)
{
Mouse = GetMouseMsg(); //获取一个鼠标消息
Key = GetAsyncKeyState(VK_ESCAPE);//获取Esc键状态,若按下返回-127或-128
if(Key<0) //判断获取键盘的信息,若键盘按下Esc,Key值小于0,则退出游戏
{
KeyRet = MessageBox(hwnd,L"是否想退出游戏?",L"提示",MB_YESNO|MB_ICONINFORMATION); //MB_YESNO显示选项,MB_ICONINFORMATION为提示字前方图标
if(KeyRet==IDYES) //判断是否想重新开始一局游戏
{
exit(0); //退出程序
}
}
//下棋时鼠标点击横纵轴交点,用绝对值将点击的x,y坐标值取整,使鼠标点击规定的棋盘位置(向右向下偏移1格)
for(int i = 1;i<21; i++)
{
for(int j = 1;j<21; j++)
{
if(abs(Mouse.x-i*21)<11&&abs(Mouse.y-j*21)<11) //将点击的范围内的值取整
{
a = i; //行列号
b = j;
x = i*21; //坐标
y = j*21;
}
}
}
if(Mouse.uMsg == WM_LBUTTONDOWN) //判断当前鼠标左键是否按下
{
if(board[a][b]!=0) //有棋子
{
MessageBox(hwnd,L"此处已有棋子,请重新选择下棋点",L"五子棋",MB_OK); //MB_OK为确定键
//退出循环
continue;
}
if(flag % 2==0) //取余
{
setfillcolor(BLACK); //棋子颜色设置黑色
solidcircle(x,y,10); //画黑色棋子
board[a][b] = 1; //给数组赋值黑棋色号
}
else
{
setfillcolor(WHITE); //棋子颜色设置白色
solidcircle(x,y,10); //画白色棋子
board[a][b] = 2; //给数组赋值白棋色号
}
flag++; //下棋手判断
if(flag>=400) //当棋盘下满时,平局。(0 - 399)
{
MessageBox(hwnd,L"本局平局",L"游戏结束",MB_OK); //MB_OK为确定键
if(ret==IDYES) //判断是否想重新开始一局游戏
{
flag = 0; //用来记录轮到哪个人下棋
memset(board,0,sizeof(board)); //清空数组
break;
}
else //不重新开始,退出程序
{
exit(0); //退出程序
}
}
}
if(JudgeWin(a,b)) //找到了五子连成一条线
{
if(flag % 2 ==1)
{
MessageBox(hwnd,L"玩家1(黑棋)胜利",L"游戏结束",MB_OK); //MB_OK为确定键
}
else
{
MessageBox(hwnd,L"玩家2(白棋)胜利",L"游戏结束",MB_OK); //MB_OK为确定键
}
ret = MessageBox(hwnd,L"是否想重新开始一局游戏?",L"提示",MB_YESNO|MB_ICONINFORMATION); //MB_YESNO显示选项,MB_ICONINFORMATION为提示字前方图标
if(ret==IDYES) //判断是否想重新开始一局游戏
{
flag = 0; //用来记录轮到哪个人下棋
memset(board,0,sizeof(board)); //清空数组
break;
}
else //不重新开始,退出程序
{
exit(0); //退出程序
}
}
}
return 0;
}
//判断输赢
int JudgeWin(int a,int b)
{
/*
算法逻辑:以当前下棋点为原点,
1.以x轴(a - 4) - (a + 4),开始检测连续点,若连续点>=5,则判定win
2.以y轴a不变,(b - 4) - (b + 4),开始检测连续点,若连续点>=5,则判定win
3.以y = x轴,(a - 4) - (a + 4),(b - 4) - (b + 4),开始检测连续点,若连续点>=5,则判定win
4.以y = -x轴,(a - 4) - (a + 4),(b + 4) - (b - 4),开始检测连续点,若连续点>=5,则判定win
*/
int i = 0;
int j = 0;
int Cont_i = 0; //连续棋子数
int t = 2 - flag % 2; //判定此次所下棋子色号
//x轴判断
for(i = ContLimit(a - 4);i <= ContLimit(a + 4);i++) //i值范围:(a - 4)至(a + 4)
{
j = b;
if(board[i][j] != t) //若不是当前下的棋子色号
{
Cont_i = 0; //连续棋子数清零
}
else if(board[i][j] == t) //若是当前下的棋子色号
{
Cont_i+=1;
}
if(Cont_i>=5) //若连续棋子数大于等于5
{
return 1; //返回1,判定胜利
}
}
Cont_i = 0; //x轴判定未胜利,连续棋子数清零,进行y轴判定
//y轴判断
for(j = ContLimit(b - 4);j <= ContLimit(b + 4);j++) //j值范围:(b - 4)至(b + 4)
{
i = a;
if(board[i][j] != t) //若不是当前下的棋子色号
{
Cont_i = 0; //连续棋子数清零
}
else if(board[i][j] == t) //若是当前下的棋子色号
{
Cont_i+=1;
}
if(Cont_i>=5) //若连续棋子数大于等于5
{
return 1; //返回1,判定胜利
}
}
Cont_i = 0; //x轴判定未胜利,连续棋子数清零,进行y轴判定
//y = x判断
for(i = ContLimit(a - 4),j = ContLimit(b - 4);i <= ContLimit(a + 4) && j <= (b + 4);i++,j++) //i值范围:(a - 4)至(a + 4),j值范围:(b - 4)至(b + 4)
{
//i = a;
if(board[i][j] != t) //若不是当前下的棋子色号
{
Cont_i = 0; //连续棋子数清零
}
else if(board[i][j] == t) //若是当前下的棋子色号
{
Cont_i+=1;
}
if(Cont_i>=5) //若连续棋子数大于等于5
{
return 1; //返回1,判定胜利
}
}
Cont_i = 0; //x轴判定未胜利,连续棋子数清零,进行y轴判定
//y = -x判断
for(i = ContLimit(a - 4),j = ContLimit(b + 4);i <= ContLimit(a + 4) && j >= ContLimit(b - 4);i++,j--) //i值范围:(a - 4)至(a + 4),j值范围:(b + 4)至(b - 4)
{
//i = a;
if(board[i][j] != t) //若不是当前下的棋子色号
{
Cont_i = 0; //连续棋子数清零
}
else if(board[i][j] == t) //若是当前下的棋子色号
{
Cont_i+=1;
}
if(Cont_i>=5) //若连续棋子数大于等于5
{
return 1; //返回1,判定胜利
}
}
return 0;
}
int ContLimit(int n) //用来限制二维数组a,b的值 其范围在1 - 20
{
if(n>20) //若输入数据大于20
{
return 20; //返回20
}
else if(n<0) //若输入数据小于0
{
return 0; //返回0
}
else //若不满足以上条件,返回原值
{
return n;
}
return n;
}