|
|
//五子棋小游戏
|
|
|
|
|
|
#include <stdio.h>
|
|
|
#include <windows.h>
|
|
|
#include <stdlib.h>
|
|
|
#include<conio.h> //使用getch()函数
|
|
|
|
|
|
int startchoice,winner,player,Q[200][200]= {0}; //Q数组记录旗子
|
|
|
char button; //读入键盘输入的指令,如→
|
|
|
|
|
|
struct Point { //点坐标的结构体
|
|
|
int x,y;
|
|
|
} point,game_xy;
|
|
|
|
|
|
struct Piece { //棋子的坐标记录
|
|
|
struct Point coord;
|
|
|
struct Piece *fore;
|
|
|
};
|
|
|
|
|
|
struct Piece *head,*p,*ptr,*ptr1;
|
|
|
struct Point win_point[5];
|
|
|
|
|
|
void goto_xy(int x, int y) { //光标移动函数
|
|
|
COORD c;
|
|
|
c.X=2*x;
|
|
|
c.Y=y;
|
|
|
SetConsoleCursorPosition (GetStdHandle(STD_OUTPUT_HANDLE), c);
|
|
|
}
|
|
|
|
|
|
void Init() { //初始化函数,将记录棋子的数组初始化
|
|
|
for(int i=0; i<200; i++)
|
|
|
for(int j=0; j<200; j++)
|
|
|
Q[i][j]=0;
|
|
|
|
|
|
startchoice=0;
|
|
|
player=1;
|
|
|
p=(struct Piece *)malloc(sizeof(struct Piece));
|
|
|
head=p;
|
|
|
}
|
|
|
|
|
|
void Welcome() { //欢迎界面
|
|
|
system("color B0"); //#include<windows.h> B 背景淡浅绿色 0 字体黑色
|
|
|
goto_xy(10,3);
|
|
|
printf("-→");
|
|
|
goto_xy(17,1);
|
|
|
printf("主菜单");
|
|
|
goto_xy(13,3);
|
|
|
printf(" ***人人对战***");
|
|
|
goto_xy(13,4);
|
|
|
printf(" ***退出***");
|
|
|
point.x=12;
|
|
|
point.y=3;
|
|
|
goto_xy(0,0);
|
|
|
}
|
|
|
|
|
|
void ShowWho() { //显示轮到哪一方下棋
|
|
|
goto_xy(17,24);
|
|
|
if(player==0)
|
|
|
printf("轮到甲方落子");
|
|
|
else
|
|
|
printf("轮到乙方落子");
|
|
|
goto_xy(point.x,point.y);
|
|
|
}
|
|
|
|
|
|
void Draw() { //绘画游戏界面
|
|
|
game_xy.x=10;
|
|
|
game_xy.y=3;
|
|
|
system("cls");
|
|
|
system("color 3F"); //3 湖蓝色 F 亮白色
|
|
|
goto_xy(15,1);
|
|
|
printf("欢迎play our 五子棋!");
|
|
|
/*goto_xy(29,22);
|
|
|
printf("重新开始 r");*/
|
|
|
goto_xy(1,24);
|
|
|
printf("悔棋 b");
|
|
|
goto_xy(1,25);
|
|
|
printf("退出 ESC");
|
|
|
|
|
|
const int i=8; //const 定义的数据不可以被改变 而且修改数据比较方便
|
|
|
const int j=19;
|
|
|
const int k=3;
|
|
|
goto_xy(game_xy.x-i,game_xy.y+k); //输出甲方的下棋方法
|
|
|
printf("甲方: ●");
|
|
|
goto_xy(game_xy.x-i,game_xy.y+k+2);
|
|
|
printf("移动: 上 W");
|
|
|
goto_xy(game_xy.x-i,game_xy.y+k+4);
|
|
|
printf(" 下 S");
|
|
|
goto_xy(game_xy.x-i,game_xy.y+k+6);
|
|
|
printf(" 左 A");
|
|
|
goto_xy(game_xy.x-i,game_xy.y+k+8);
|
|
|
printf(" 右 D ");
|
|
|
goto_xy(game_xy.x-i,game_xy.y+k+10);
|
|
|
printf("落子: 空 格");
|
|
|
|
|
|
goto_xy(game_xy.x+j,game_xy.y+k); //输出乙方的下棋方法
|
|
|
printf("乙方: ○");
|
|
|
goto_xy(game_xy.x+j,game_xy.y+k+2);
|
|
|
printf("移动: 上 ↑");
|
|
|
goto_xy(game_xy.x+j,game_xy.y+k+4);
|
|
|
printf(" 下 ↓");
|
|
|
goto_xy(game_xy.x+j,game_xy.y+k+6);
|
|
|
printf(" 左 ←");
|
|
|
goto_xy(game_xy.x+j,game_xy.y+k+8);
|
|
|
printf(" 右 →");
|
|
|
goto_xy(game_xy.x+j,game_xy.y+k+10);
|
|
|
printf("落子: Enter");
|
|
|
|
|
|
for(int k1=0; k1<200; k1++) //初始化棋子记录,在第二局时有明确的作用
|
|
|
for(int k2=0; k2<200; k2++)
|
|
|
Q[k1][k2]=0;
|
|
|
|
|
|
for(int i=0; i<20; i++) { //画棋盘
|
|
|
|
|
|
if(i==0) { //画第一行
|
|
|
goto_xy(10,i+3);
|
|
|
printf("┌┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┐");
|
|
|
|
|
|
}
|
|
|
if(i!=0&&i!=19) { //画出中间16行
|
|
|
goto_xy(10,i+3);
|
|
|
printf("├┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┤");
|
|
|
}
|
|
|
if(i==19) { //画最后一行
|
|
|
goto_xy(10,i+3);
|
|
|
printf("└┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┘");
|
|
|
}
|
|
|
}
|
|
|
point.x=19;
|
|
|
point.y=12;
|
|
|
goto_xy(19,12);
|
|
|
}
|
|
|
|
|
|
void Clean() { //清除-→运动的轨迹
|
|
|
goto_xy(10,3);
|
|
|
printf(" ");
|
|
|
goto_xy(24,3);
|
|
|
printf(" ");
|
|
|
goto_xy(10,4);
|
|
|
printf(" ");
|
|
|
goto_xy(24,4);
|
|
|
printf(" ");
|
|
|
}
|
|
|
|
|
|
void menu_choose(char press) { //选择游戏还是退出
|
|
|
if(press==72) { //↑的ASCLL码
|
|
|
if(point.y==3)
|
|
|
point.y=4;
|
|
|
else
|
|
|
point.y=3;
|
|
|
Clean();
|
|
|
goto_xy(10,point.y);
|
|
|
printf("-→");
|
|
|
}
|
|
|
if(press==80) { //↓的ASCLL码
|
|
|
if(point.y==4)
|
|
|
point.y=3;
|
|
|
else
|
|
|
point.y=4;
|
|
|
Clean();
|
|
|
goto_xy(10,point.y);
|
|
|
printf("-→");
|
|
|
}
|
|
|
if(press==13) { // 13:回车键的ASCLL码
|
|
|
startchoice=point.y-2; //startchoice 为1或2
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void go_back(int x1,int y1) { //悔棋函数
|
|
|
goto_xy(x1,y1);
|
|
|
if(x1==10) {
|
|
|
if(y1==3) {
|
|
|
printf("┌");
|
|
|
} else if(y1==20) {
|
|
|
printf("└");
|
|
|
} else {
|
|
|
printf("├");
|
|
|
}
|
|
|
} else if(x1==27) {
|
|
|
if(y1==3) {
|
|
|
printf("┐");
|
|
|
} else if(y1==20) {
|
|
|
printf("┘");
|
|
|
} else {
|
|
|
printf("┤");
|
|
|
}
|
|
|
} else {
|
|
|
if(y1==3) {
|
|
|
printf("┬");
|
|
|
} else if(y1==20) {
|
|
|
printf("┴");
|
|
|
} else {
|
|
|
printf("┼");
|
|
|
}
|
|
|
}
|
|
|
Q[point.x][point.y]=0; //在数组中将弹出的棋子对应的数据设为0
|
|
|
goto_xy(x1,y1);
|
|
|
}
|
|
|
|
|
|
void Record() { //记录棋子的情况
|
|
|
|
|
|
p->coord.x=point.x;
|
|
|
p->coord.y=point.y;
|
|
|
ptr=p;
|
|
|
p=(struct Piece *)malloc(sizeof(struct Piece));
|
|
|
p->fore=ptr;
|
|
|
|
|
|
ShowWho();
|
|
|
Q[point.x][point.y]=player+1;
|
|
|
if(player) {
|
|
|
player=0;
|
|
|
return;
|
|
|
}
|
|
|
player=1;
|
|
|
goto_xy(point.x,point.y);
|
|
|
}
|
|
|
|
|
|
void PutDown() { //显示落子函数
|
|
|
if(Q[point.x][point.y]==0) { //先判断该位置是否有棋子
|
|
|
if(player) {
|
|
|
printf("●");
|
|
|
printf("\a"); //'\a'表示蜂鸣声
|
|
|
Record();
|
|
|
} else {
|
|
|
printf("○");
|
|
|
printf("\a");
|
|
|
Record();
|
|
|
}
|
|
|
goto_xy(point.x,point.y);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void Play(char ch) { //键盘的操作 移动光标 下棋和悔棋操作
|
|
|
if(player==1) { //甲方
|
|
|
if(ch== 'W' || ch=='w') //W 光标上移
|
|
|
{ if(point.y<=3)
|
|
|
point.y=22;
|
|
|
else
|
|
|
point.y--;
|
|
|
goto_xy(point.x,point.y);
|
|
|
|
|
|
}
|
|
|
if(ch=='A' || ch=='a') { //A 光标左移
|
|
|
if(point.x<=10)
|
|
|
point.x=20;
|
|
|
else
|
|
|
point.x--;
|
|
|
goto_xy(point.x,point.y);
|
|
|
|
|
|
}
|
|
|
if(ch=='D' || ch=='d') { //D 光标右移
|
|
|
if(point.x>=20)
|
|
|
point.x=10;
|
|
|
else
|
|
|
point.x++;
|
|
|
goto_xy(point.x,point.y);
|
|
|
|
|
|
}
|
|
|
if(ch=='S' || ch=='s') { //S 光标下移
|
|
|
if(point.y>=22)
|
|
|
point.y=3;
|
|
|
else
|
|
|
point.y++;
|
|
|
goto_xy(point.x,point.y);
|
|
|
|
|
|
}
|
|
|
if(ch==32) { //空格键的ASCLL码 下棋
|
|
|
PutDown();
|
|
|
}
|
|
|
} else {
|
|
|
if(ch==72) { //↑的ASCLL码 光标上移
|
|
|
if(point.y<=3)
|
|
|
point.y=22;
|
|
|
else
|
|
|
point.y--;
|
|
|
goto_xy(point.x,point.y);
|
|
|
|
|
|
}
|
|
|
if(ch==75) { //←的ASCLL码 光标左移
|
|
|
if(point.x<=10)
|
|
|
point.x=20;
|
|
|
else
|
|
|
point.x--;
|
|
|
goto_xy(point.x,point.y);
|
|
|
|
|
|
}
|
|
|
if(ch==77) { //→的ASCLL码 光标右移
|
|
|
if(point.x>=20)
|
|
|
point.x=10;
|
|
|
else
|
|
|
point.x++;
|
|
|
goto_xy(point.x,point.y);
|
|
|
|
|
|
}
|
|
|
if(ch==80) { //↓的ASCLL码 光标下移
|
|
|
if(point.y>=22)
|
|
|
point.y=3;
|
|
|
else
|
|
|
point.y++;
|
|
|
goto_xy(point.x,point.y);
|
|
|
|
|
|
}
|
|
|
if(ch==13) { //回车键的ASCLL码 下棋
|
|
|
PutDown();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
if(button=='b'||button=='B') { //悔棋的操作
|
|
|
ptr1=p;
|
|
|
if(p!=head) {
|
|
|
p=p->fore;
|
|
|
free(ptr1);
|
|
|
point.x=p->coord.x;
|
|
|
point.y=p->coord.y;
|
|
|
go_back(point.x,point.y);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void judgeWinRecodePointXY(int count, int rr, int cc){
|
|
|
win_point[count].x=rr; //记录坐标
|
|
|
win_point[count].y=cc; //记录坐标
|
|
|
}
|
|
|
|
|
|
void judgeWinSetPointCOlor() {
|
|
|
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);//创建并实例化句柄
|
|
|
CONSOLE_SCREEN_BUFFER_INFO csbiInfo; //获取当前颜色
|
|
|
GetConsoleScreenBufferInfo(handle, &csbiInfo); //获取当前颜色
|
|
|
WORD wOldColorAttrs = csbiInfo.wAttributes; //获取当前颜色
|
|
|
|
|
|
SetConsoleTextAttribute(handle,FOREGROUND_INTENSITY |FOREGROUND_RED|BACKGROUND_INTENSITY|BACKGROUND_GREEN); //设置输出的新颜色
|
|
|
for(int i=0; i<5; i++) {
|
|
|
//重新输出一遍
|
|
|
goto_xy(win_point[i].x, win_point[i].y);
|
|
|
if(!player) { //谁赢谁就是最后下了一子,那么player变量就反向了
|
|
|
printf("●");
|
|
|
} else {
|
|
|
printf("○");
|
|
|
}
|
|
|
}
|
|
|
SetConsoleTextAttribute(handle, wOldColorAttrs); //恢复原来的颜色
|
|
|
}
|
|
|
|
|
|
int Judge() {
|
|
|
int count=0;
|
|
|
int pp=player==0?2:1; //三目运算
|
|
|
for(int c=0; c<200; c++) {
|
|
|
for(int r=0; r<200; r++) {
|
|
|
if(Q[r][c]!=pp)
|
|
|
continue;
|
|
|
|
|
|
//检查列
|
|
|
int rr=r;
|
|
|
int cc=c;
|
|
|
judgeWinRecodePointXY(count, rr, cc); //记录坐标
|
|
|
while(--cc>=3 &&Q[rr][cc]==pp) {
|
|
|
count++;
|
|
|
judgeWinRecodePointXY(count, rr, cc); //记录坐标
|
|
|
}
|
|
|
cc=c;
|
|
|
judgeWinRecodePointXY(count, rr, cc); //记录坐标
|
|
|
while(++cc<23 &&Q[rr][cc]==pp) {
|
|
|
count++;
|
|
|
judgeWinRecodePointXY(count, rr, cc); //记录坐标
|
|
|
}
|
|
|
cc=c;
|
|
|
if(count>=4) {
|
|
|
judgeWinSetPointCOlor();
|
|
|
return pp;
|
|
|
}
|
|
|
|
|
|
//检查行
|
|
|
count=0;
|
|
|
judgeWinRecodePointXY(count, rr, cc); //记录坐标
|
|
|
while(--rr>=10 &&Q[rr][cc]==pp) {
|
|
|
count++;
|
|
|
judgeWinRecodePointXY(count, rr, cc); //记录坐标
|
|
|
}
|
|
|
rr=r;
|
|
|
judgeWinRecodePointXY(count, rr, cc); //记录坐标
|
|
|
while(++rr<30 &&Q[rr][cc]==pp) {
|
|
|
count++;
|
|
|
judgeWinRecodePointXY(count, rr, cc); //记录坐标
|
|
|
}
|
|
|
rr=r;
|
|
|
if(count>=4) {
|
|
|
judgeWinSetPointCOlor();
|
|
|
return pp;
|
|
|
}
|
|
|
|
|
|
//检查反斜边
|
|
|
count=0;
|
|
|
judgeWinRecodePointXY(count, rr, cc); //记录坐标
|
|
|
cc--;
|
|
|
rr--;
|
|
|
while((cc>=3||rr>=10) &&Q[rr][cc]==pp) {
|
|
|
count++;
|
|
|
judgeWinRecodePointXY(count, rr, cc); //记录坐标
|
|
|
cc--;
|
|
|
rr--;
|
|
|
|
|
|
}
|
|
|
rr=r;
|
|
|
cc=c;
|
|
|
judgeWinRecodePointXY(count, rr, cc); //记录坐标
|
|
|
cc++;
|
|
|
rr++;
|
|
|
while((cc<23||rr<30) &&Q[rr][cc]==pp) {
|
|
|
count++;
|
|
|
judgeWinRecodePointXY(count, rr, cc); //记录坐标
|
|
|
cc++;
|
|
|
rr++;
|
|
|
}
|
|
|
rr=r;
|
|
|
cc=c;
|
|
|
if(count>=4) {
|
|
|
judgeWinSetPointCOlor();
|
|
|
return pp;
|
|
|
}
|
|
|
|
|
|
//检查正斜边
|
|
|
count=0;
|
|
|
judgeWinRecodePointXY(count, rr, cc); //记录坐标
|
|
|
cc++;
|
|
|
rr--;
|
|
|
while((cc<23||rr>=10) &&Q[rr][cc]==pp) {
|
|
|
judgeWinRecodePointXY(count, rr, cc); //记录坐标
|
|
|
count++;
|
|
|
cc++;
|
|
|
rr--;
|
|
|
}
|
|
|
rr=r;
|
|
|
cc=c;
|
|
|
judgeWinRecodePointXY(count, rr, cc); //记录坐标
|
|
|
cc--;
|
|
|
rr++;
|
|
|
while((cc>=3||rr<30) &&Q[rr][cc]==pp) {
|
|
|
judgeWinRecodePointXY(count, rr, cc); //记录坐标
|
|
|
count++;
|
|
|
cc--;
|
|
|
rr++;
|
|
|
}
|
|
|
rr=r;
|
|
|
cc=c;
|
|
|
if(count>=4) {
|
|
|
judgeWinSetPointCOlor();
|
|
|
return pp;
|
|
|
}
|
|
|
|
|
|
count=0;
|
|
|
}
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int main(void) {
|
|
|
int j=0,k=0;
|
|
|
system("color 4E"); //#include<windows.h> 4 背景红色 E 字体淡黄色
|
|
|
printf("\n 欢迎play五子棋!");
|
|
|
goto_xy(15,3);
|
|
|
printf("作者:杜盼");
|
|
|
goto_xy(17,5);
|
|
|
printf(" 周拓");
|
|
|
Sleep(3000);
|
|
|
system("cls");
|
|
|
while(1) {
|
|
|
Init(); //初始化
|
|
|
int winner=0;
|
|
|
Welcome(); //欢迎界面
|
|
|
|
|
|
while(1) { //读取菜单选项
|
|
|
char choice=getch();
|
|
|
menu_choose(choice);
|
|
|
if(startchoice!=0)
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
if(startchoice==1) { //选择人人对战
|
|
|
|
|
|
Draw();
|
|
|
goto_xy(17,24);
|
|
|
printf("轮到甲方落子");
|
|
|
goto_xy(point.x,point.y);
|
|
|
|
|
|
while(1) {
|
|
|
button=getch();
|
|
|
Play(button); //读取键盘的操作 移动光标 下棋和悔棋操作
|
|
|
|
|
|
if(button==27) { //ESC的ASCLL码
|
|
|
if(MessageBox(NULL,TEXT("确定退出?"),TEXT(""),MB_ICONQUESTION|MB_OKCANCEL)==IDOK) {
|
|
|
system("cls");
|
|
|
printf("\n 谢谢使用!\n");
|
|
|
return 0;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if(button==13 || button==32) //回车键或者空格键ASCLL码 按下后开始判断输赢
|
|
|
winner=Judge();
|
|
|
|
|
|
if(winner!=0) {
|
|
|
goto_xy(15,26);
|
|
|
if(winner==2) {
|
|
|
printf("恭喜!甲方赢!\n");
|
|
|
j=j+1;
|
|
|
}
|
|
|
if(winner==1) {
|
|
|
printf("恭喜!乙方赢!\n");
|
|
|
k=k+1;
|
|
|
}
|
|
|
goto_xy(29,24);
|
|
|
printf("甲 %d : %d 乙",j,k);
|
|
|
}
|
|
|
|
|
|
if(winner!=1&&winner!=2) {
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
goto_xy(13,24);
|
|
|
printf(" 继续游戏?(Y/N): ");
|
|
|
while(1) {
|
|
|
button=getch();
|
|
|
if(button=='n'||button=='N'||button=='y'||button=='Y')
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
if(button=='n'||button=='N') {
|
|
|
if(MessageBox(NULL,TEXT(" 确定退出?"),TEXT(""),MB_ICONQUESTION|MB_OKCANCEL)==IDOK) {
|
|
|
system("cls");
|
|
|
printf("\n 谢谢使用!\n");
|
|
|
return 0;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if(button=='y'||button=='Y') {
|
|
|
winner=0;
|
|
|
system("cls");
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if(startchoice==2) {
|
|
|
if(MessageBox(NULL,TEXT(" 确定退出?"),TEXT(""),MB_ICONQUESTION|MB_OKCANCEL)==IDOK) {
|
|
|
printf("\n\n 谢谢使用!\n");
|
|
|
return 0;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
|
|
|
|