我是个初学者
现在分享一下老师给我们讲的五子棋双人游戏总结
源代码部分及自己加的注释
/*
五子棋:棋盘上的3种状态:无棋子0,白棋1,红棋2。
*/
#include<stdio.h>
#include<stdlib.h>
#include<graphics.h>
#include<bios.h>
#include<conio.h>
#define LEFT 0x4b00
#define RIGHT 0x4d00
#define DOWN 0x5000
#define UP 0x4800
#define ESC 0x011b
#define SPACE 0x3920
#define BILI 20
#define JZ 4
#define JS 3
#define N 19
int box[N][N]; /*定义二维数组*/
int step_x,step_y ;
int key ;
int flag=1 ;
void draw_box(); /**棋盘的初始化**/
void draw_cicle(int x,int y,int color); /*画棋子:在judgewho中使用*/
void change(); /*改变棋子标记:在judgekey中使用*/
void judgewho(int x,int y);
void judgekey(); /* 与键盘结合:在main函数中使用*/
int judgeresult(int x,int y); /*判断输赢的函数*/
void attentoin(); /*在main函数中使用*/
void attention() /*初始界面,介绍游戏规则:在main函数中使用*/
{
char ch ;
window(1,1,80,25);
textbackground(LIGHTBLUE);
textcolor(YELLOW);
clrscr();
gotoxy(15,2);
printf("游戏操作规则:");
gotoxy(15,4);
printf("Play Rules:");
gotoxy(15,6);
printf("1、按左右上下方向键移动棋子");
gotoxy(15,8);
printf("1. Press Left,Right,Up,Down Key to move Piece");
gotoxy(15,10);
printf("2、按空格确定落棋子");
gotoxy(15,12);
printf("2. Press Space to place the Piece");
gotoxy(15,14);
printf("3、禁止在棋盘外按空格");
gotoxy(15,16);
printf("3. DO NOT press Space outside of the chessboard");
gotoxy(15,18);
printf("你是否接受上述的游戏规则(Y/N)");
gotoxy(15,20);
printf("Do you accept the above Playing Rules? [Y/N]:");
while(1)
{
gotoxy(60,20);
ch=getche(); /*getche与getch的区别:
getch:从控制台无回显地取一个字符,getche:从控制台取字符(带回显)*/
/*如果同意按Y键进入游戏,不同意按N键退出游戏*/
if(ch=='Y'||ch=='y')
break ;
else if(ch=='N'||ch=='n')
{
window(1,1,80,25);
textbackground(BLACK);/*选择新的文本背景颜色 用 法: void textbackground(int color); */
textcolor(LIGHTGRAY); /*在文本模式中选择新的字符颜色 用 法1.c语言类型: void textcolor(int color);*/
clrscr();
exit(0);
}
gotoxy(51,12);
printf(" ");
}
}
/*定义变量、背景色、当前屏幕的笔画颜色、划线line。
二维数组清零:用for循环实现的。*/
void draw_box() /**棋盘的初始化函数**/
{
int x1,x2,y1,y2 ;
setbkcolor(LIGHTBLUE);/*功 能: 用调色板设置当前背景颜色 .用 法: void far setbkcolor(int color); */
setcolor(YELLOW); /*功 能: 设置当前画线颜色.用 法: void far setcolor(int color);*/
gotoxy(7,2);
printf("Left, Right, Up, Down KEY to move, Space to put, ESC-quit.");
for(x1=1,y1=1,y2=18;x1<=18;x1++)
line((x1+JZ)*BILI,(y1+JS)*BILI,(x1+JZ)*BILI,(y2+JS)*BILI); /*在指定两点间画一直线 : void far line(int x0, int y0, int x1, int y1);*/
for(x1=1,y1=1,x2=18;y1<=18;y1++)
line((x1+JZ)*BILI,(y1+JS)*BILI,(x2+JZ)*BILI,(y1+JS)*BILI);
for(x1=1;x1<=18;x1++) /*二维数组清零*/
for(y1=1;y1<=18;y1++)
box[x1][y1]=0 ;
}
void draw_circle(int x,int y,int color) /*画棋子:在judgewho中使用*/
{
setcolor(color);
setlinestyle(SOLID_LINE,0,1); /*设置当前画线宽度和类型 SOLID_LINE(实线)
用 法: void far setlinestyle(int linestyle, unsigned pattern,int width);*/
x=(x+JZ)*BILI ;
y=(y+JS)*BILI ;
/*功 能: 在给定半径以(x, y)为圆心画圆.用 法: void far circle(int x,int y,int radius);*/
circle(x,y,8); /*以(x,y)为圆心,以8为半径画圆*/
}
void judgekey() /* 与键盘结合:在main函数中使用*/
{
int i ;
int j ;
switch(key)
{
/*上下左右同理:如左*/
case LEFT : /*左*/
if(step_x-1<0) /*已经在最左端,无法移动*/
break ;
else
{
for(i=step_x-1,j=step_y;i>=1;i--) /*将step_x-1赋值给i,将step_y赋值给j,进行循环,判断是否能向左移动*/
if(box[i][j]==0) /*如果要移动到的位置为0*/
{
draw_circle(step_x,step_y,LIGHTBLUE); /*将原来的棋子地方画为背景色,以便于玩家看清棋子的移动*/
break ;
}
if(i<1)break ;/*已经在最左端,无法移动*/
step_x=i ; /*将i赋值给step_x*/
judgewho(step_x,step_y); /*画出当前位置的圆*/
break ;
}
case RIGHT : /*→*/
if(step_x+1>18)
break ;
else
{
for(i=step_x+1,j=step_y;i<=18;i++)
if(box[i][j]==0)
{
draw_circle(step_x,step_y,LIGHTBLUE);
break ;
}
if(i>18)break ;
step_x=i ;
judgewho(step_x,step_y);
break ;
}
case DOWN : /*↓*/
if((step_y+1)>18)
break ;
else
{
for(i=step_x,j=step_y+1;j<=18;j++)
if(box[i][j]==0)
{
draw_circle(step_x,step_y,LIGHTBLUE);
break ;
}
if(j>18)break ;
step_y=j ;
judgewho(step_x,step_y);
break ;
}
case UP : /*上*/
if((step_y-1)<0)
break ;
else
{
for(i=step_x,j=step_y-1;j>=1;j--)
if(box[i][j]==0)
{
draw_circle(step_x,step_y,LIGHTBLUE);
break ;
}
if(j<1)break ;
step_y=j ;
judgewho(step_x,step_y);
break ;
}
case ESC : /*退出*/
break ;
case SPACE : /*下子*/
if(step_x>=1&&step_x<=18&&step_y>=1&&step_y<=18) /*判断棋子是否在棋盘上*/
{
if(box[step_x][step_y]==0) /*如果当前位置数组元素值为0*/
{
box[step_x][step_y]=flag ; /*将当前元素赋值为flag值*/
if(judgeresult(step_x,step_y)==1) /*调用judgeresult函数触发判断*/
{
sound(1000);
delay(1000);
nosound();
gotoxy(30,4);
if(flag==1) /*如果是是白棋*/
{
setbkcolor(BLUE);
cleardevice(); /*功 能: 清除图形屏幕,用 法: void far cleardevice(void); */
setviewport(100,100,540,380,1);
/*定义一个图形窗口*/
setfillstyle(1,2); /*设置填充模式和颜色*/
/*绿色以实填充*/
setcolor(YELLOW);
rectangle(0,0,439,279); /*画一个矩形*/
floodfill(50,50,14); /*填充一个有界区域 */
setcolor(12);
settextstyle(1,0,5); /*功 能: 为图形输出设置当前的文本属性
用 法: void far settextstyle (int font, int direction, char size); */
/*三重笔划字体, 水平放大5倍*/
outtextxy(20,20,"The White Win !");
setcolor(15);
settextstyle(3,0,5);
/*无衬笔划字体, 水平放大5倍*/
outtextxy(120,120,"The White Win !");
setcolor(14);
settextstyle(2,0,8);
getch();
closegraph();
exit(0);
}
if(flag==2) /*如果是黑棋*/
{
setbkcolor(BLUE);
cleardevice();
setviewport(100,100,540,380,1);
/*定义一个图形窗口*/
setfillstyle(1,2);
/*绿色以实填充*/
setcolor(YELLOW);
rectangle(0,0,439,279);
floodfill(50,50,14);
setcolor(12);
settextstyle(1,0,8);
/*三重笔划字体, 水平放大8倍*/
outtextxy(20,20,"The Red Win !");
setcolor(15);
settextstyle(3,0,5);
/*无衬笔划字体, 水平放大5倍*/
outtextxy(120,120,"The Red Win !");
setcolor(14);
settextstyle(2,0,8);
getch();
closegraph();
exit(0);
}
}
change();/*棋子flag 1,2 变化的原理;当棋子下子成功后调用change函数,从而由一到二的改变*/
break ;
}
}
else
break ;
}
}
void change() /*改变棋子的标记1,2。:在judgekey中使用*/
{
if(flag==1)
flag=2 ;
else
flag=1 ;
}
void judgewho(int x,int y) /*根据标记1,2调用draw_circle函数画圆:在judgekey、main函数中使用*/
{
if(flag==1)
draw_circle(x,y,15); /*画白棋*/
if(flag==2)
draw_circle(x,y,4); /*画红棋*/
}
int judgeresult(int x,int y) /*判断输赢的函数*/
{
int j,k,n1,n2 ;
while(1)
{ /*水平向左、水平向右为一组判断水平方向是否满足过关条件*/
n1=0 ;
n2=0 ;
/*水平向左数*/
for(j=x,k=y;j>=1;j--)
{
if(box[j][k]==flag)
n1++;
else
break ;
}
/*水平向右数*/
for(j=x,k=y;j<=18;j++)
{
if(box[j][k]==flag)
n2++;
else
break ;
}
if(n1+n2-1>=5) /* 当满足水平方向或竖直方向或斜向连续白棋或红棋>=5个的时候过关*/
{
return(1);
break ;
}
/*向上、向下为一组判断竖直方向是否满足过关条件*/
/*垂直向上数*/
n1=0 ;
n2=0 ;
for(j=x,k=y;k>=1;k--)
{
if(box[j][k]==flag)
n1++;
else
break ;
}
/*垂直向下数*/
for(j=x,k=y;k<=18;k++)
{
if(box[j][k]==flag)
n2++;
else
break ;
}
if(n1+n2-1>=5) /* 当满足水平方向或竖直方向或斜向连续白棋或红棋>=5个的时候过关*/
{
return(1);
break ;
}
/*向左上方、向右下方数为一组,判断斜向是否满足过关条件*/
/*向左上方数*/
n1=0 ;
n2=0 ;
for(j=x,k=y;j>=1,k>=1;j--,k--)
{
if(box[j][k]==flag)
n1++;
else
break ;
}
/*向右下方数*/
for(j=x,k=y;j<=18,k<=18;j++,k++)
{
if(box[j][k]==flag)
n2++;
else
break ;
}
if(n1+n2-1>=5) /* 当满足水平方向或竖直方向或斜向连续白棋或红棋>=5个的时候过关*/
{
return(1);
break ;
}
/*右上方、向左下方为一组,判断斜向是否满足过关条件*/
/*向右上方数*/
n1=0 ;
n2=0 ;
for(j=x,k=y;j<=18,k>=1;j++,k--)
{
if(box[j][k]==flag)
n1++;
else
break ;
}
/*向左下方数*/
for(j=x,k=y;j>=1,k<=18;j--,k++)
{
if(box[j][k]==flag)
n2++;
else
break ;
}
if(n1+n2-1>=5) /* 当满足水平方向或竖直方向或斜向连续白棋或红棋>=5个的时候过关*/
{
return(1);
break ;
}
return(0);
break ;
}
}
/*Main函数
首先定义了一些变量、清除文本模式窗口、调用attention函数。
定义flag=1,调用draw_box函数。
设计一个do,while循环:在循环中调用judgewho画圆函数并嵌套的do,while循环。
嵌套do,while循环中有while循环接收键盘输入信息,调用judgekey函数与键盘结合,判断移动,下子,退出的函数。*/
void main()
{
int gdriver=VGA,gmode=VGAHI;
clrscr(); /* 清除文本模式窗口*/
attention(); /*调用函数*/
registerbgidriver(EGAVGA_driver); /* 注册BGI驱动后可以不需要.BGI文件的支持运行 */
initgraph(&gdriver,&gmode,"c://tc");
/* setwritemode(XOR_PUT);*/
flag=1 ;
draw_box(); /*划线等图形的初始化*/
do
{
step_x=0 ; /*棋子的最初位置,选手下棋的最初位置,当前棋手的光标位置*/
step_y=0 ;
/*draw_circle(step_x,step_y,8); */
judgewho(step_x-1,step_y-1); /*根据坐标和flag值调用画圆的函数画出棋手光 标位置*/
do
{
while(bioskey(1)==0); /*不断接受键盘信息*/
key=bioskey(0); /*将键盘接收的信息赋值给key*/
judgekey(); /*与键盘结合,判断移动,下子,退出的函数*/
}
while(key!=SPACE&&key!=ESC);/*当按空格键和ESC键时退出do,while循环*/
}
while(key!=ESC);/*当按ESC键时退出do,while循环*/
closegraph();/*关闭图形模式,回到文本模式*/
}
下面是一些思想总结
void main(){
draw_box(); /*1.划线等图形的初始化 2.二维数组清零*/
do /*do,while循环:切换对手,即切换红白棋*/
{
step_x=0 ; /*棋子的最初位置,选手下棋的最初位置,当前棋手的光标位置*/
step_y=0 ;
judgewho(step_x-1,step_y-1);
/*根据坐标和flag值调用画圆的函数画出棋手光标位置*/
do
{
while(bioskey(1)==0); /*不断接受键盘信息*/
key=bioskey(0); /*将键盘接收的信息赋值给key*/
judgekey(); /*与键盘结合,判断移动,下子,退出的函数*/
}
while(key!=SPACE&&key!=ESC);/*当按空格键和ESC键时退出do,while循环*/
}
while(key!=ESC);/*当按ESC键时退出do,while循环*/
}
void draw_box() /**棋盘的初始化函数**/
{
int x1,x2,y1,y2 ;
setbkcolor(LIGHTBLUE);/*功 能: 用调色板设置当前背景颜色 .用 法: void far setbkcolor(int color); */
setcolor(YELLOW); /*功 能: 设置当前画线颜色.用 法: void far setcolor(int color);*/
gotoxy(7,2);
printf("Left, Right, Up, Down KEY to move, Space to put, ESC-quit.");
for(x1=1,y1=1,y2=18;x1<=18;x1++)
line((x1+JZ)*BILI,(y1+JS)*BILI,(x1+JZ)*BILI,(y2+JS)*BILI); /*在指定两点间画一直线 : void far line(int x0, int y0, int x1, int y1);*/
for(x1=1,y1=1,x2=18;y1<=18;y1++)
line((x1+JZ)*BILI,(y1+JS)*BILI,(x2+JZ)*BILI,(y1+JS)*BILI);
for(x1=1;x1<=18;x1++) /*二维数组清零*/
for(y1=1;y1<=18;y1++)
box[x1][y1]=0 ;
}
void judgewho(int x,int y) /*根据标记1,2调用draw_circle函数画圆*/
{
if(flag==1)
draw_circle(x,y,15); /*画白棋*/
if(flag==2)
draw_circle(x,y,4); /*画红棋*/
}
void draw_circle(int x,int y,int color) /*画棋子:即画圆*/
{
setcolor(color);
setlinestyle(SOLID_LINE,0,1); /*设置当前画线宽度和类型 SOLID_LINE(实线)
用 法: void far setlinestyle(int linestyle, unsigned pattern,int width);*/
x=(x+JZ)*BILI ;
y=(y+JS)*BILI ;
/*功 能: 在给定半径以(x, y)为圆心画圆.用 法: void far circle(int x,int y,int radius);*/
circle(x,y,8); /*以(x,y)为圆心,以8为半径画圆*/
}
void judgekey() /* 与键盘结合:在main函数中使用*/
{
switch(key) /*得到键盘信息*/
{
/*上下左右同理:如左*/
case LEFT : /*左*/
if(step_x-1<0) /*已经是最左端无法移动*/
break ; /*退出*/
else /*与最近的if配对及上一个*/
{
for(i=step_x-1,j=step_y;i>=1;i--) /*将step_x-1赋值给i,将step_y赋值给j,进行循环,判断是否能向左移动*/
/*能够向左移动执行*/
if(box[i][j]==0) /*如果要移动到的位置为二维数组值为0*/
{
draw_circle(step_x,step_y,LIGHTBLUE);
/*将原来的棋子地方画为背景色,以便于玩家看清棋子的移动*/
break ;
}
if(i<1)break ;/*如果最左端退出*/
step_x=i ; /*将i赋值给step_x*/
judgewho(step_x,step_y); /*画出当前位置的圆*/
break ;
}
case ESC : /*退出*/
break ;
case SPACE : /*下子键*/
if(step_x>=1&&step_x<=18&&step_y>=1&&step_y<=18)
/*判断棋子是否在棋盘上*/
{
if(box[step_x][step_y]==0) /*如果当前位置二维数组值为0*/
{
box[step_x][step_y]=flag ; /*将当前二维数组赋值为flag值*/
if(judgeresult(step_x,step_y)==1) /*调用judgeresult函数触发判断*/
/*如果不过关继续执行main函数最外层的do,while循环*/
{
/*当过关时,判断是1还是2,并输出相对应的信息*/
if(flag==1) /*如果是是白棋*/
{
}
if(flag==2)
{
}
}
change():/*棋子flag 1,2 变化的原理;当按下空格键后调用change函数,从而由一到二的改变*/
break ;
}
}
else
break ;
}
}
void change() /*改变棋子的标记1,2。:在judgekey中使用*/
{
if(flag==1)
flag=2 ;
else
flag=1 ;
}
int judgeresult(int x,int y) /*判断输赢的函数*/
{
while(1) /*水平、竖直、斜向的判断方法相同*/
{ /*水平向左、水平向右为一组判断水平方向是否满足过关条件*/
n1=0 ;
n2=0 ;
/*水平向左数*/
for(j=x,k=y;j>=1;j--)
{
if(box[j][k]==flag) /*水平向左有棋子时,n1++*/
n1++;
else
break ;
}
/*水平向右数*/
for(j=x,k=y;j<=18;j++)/*水平向右有棋子时,n2++*/
{
if(box[j][k]==flag)
n2++;
else
break ;
}
if(n1+n2-1>=5) /* 当满足水平方向或竖直方向或斜向连续白棋或红棋>=5个的时候过关*/
{
return(1); /*返回1,并推出*/
break ;
}
return(0); /*当不过关时,返回0并退出*/
break ;
}
}