/*这是我们c++课程设计五子棋,我用了许多循环语句,可能比较繁碎,不过仔细分析的话,还是挺简单的。
如果有什么不懂的地方可以加我q 1570169994 */ #include<stdio.h>#include<stdlib.h>#include<conio.h> // 这些是一些必要的头文件#include<windows.h>#include<iostream>using namespace std;#define M 15 //此处定义棋盘大小为15*15,自己视情况而定typedef struct Node{int a; //这里定义的结点在悔棋时要用到int b;struct Node *next;}node;class Qipan{ //定义一个棋盘类,这个类里有实现不同功能的函数public:int a,b,t; //棋子的坐标我们用a,b表示,t表示接收的输入信息int player; //player为1时,代表绿方下棋,2代表红方int name[M][M]; //棋盘用一个15*15的二维数组表示void reset(); //此函数实现重置功能,即将棋盘上的棋子清零void chess(); //此函数实现下棋功能,是非常重要的void win(); //此函数实现判断功能,即每当一方落子后,都要调用此函数void explain(); //此函数是解释说明的函数void output(int count[]); //此函数输出赢的一方void gotoxy(int x,int y){HANDLE hout; //这是实现光标移动的函数,具体可以百度一下COORD coord; //x,y即为棋子的坐标,和a,b一样coord.X = x; //此函数是将当前光标移动到x,y坐标处coord.Y = y;hout = GetStdHandle(STD_OUTPUT_HANDLE);SetConsoleCursorPosition(hout,coord);}};// main 函数int main(){Qipan qipan; //定义一个棋盘对象do{system("cls"); //清屏函数cout<<"1.开始游戏 "<<endl;cout<<"2.游戏说明 "<<endl;fflush(stdin); //清空输入缓冲区,准备接收用户的输入qipan.t = getch(); //接受用户的输入,把值赋给 tif(qipan.t == 27) //Esc键的ASCII为27,即用户如果按下Esc键,则退出循环break;switch(qipan.t) //选择语句{case '1': //如果用户输入1,即要开始游戏while(1){system("cls");cout<<"1.绿棋先走 "<<endl;cout<<"2.红棋先走 "<<endl;fflush(stdin);qipan.t = getch();if(qipan.t==48)break;if(qipan.t == 27)break;if(qipan.t == 49) //用户输入1,则绿棋先走,qipan.player = 1;if(qipan.t == 50) //输入2,红棋先走qipan.player = 2;do{qipan.reset(); //重置棋盘,即绘制棋盘qipan.chess(); //下棋函数}while(qipan.t == 49);if(qipan.t==48)break;}break;case '2':qipan.explain(); //用户输入2,调用说明函数qipan.t = getch();break;}}while(qipan.t!=48);qipan.gotoxy(40,8);return 0;}//reset函数,绘制棋盘void Qipan::reset(){int i,j;a = 14; //定义光标初始位置为中间,即(14,7)b = 7;for(i=0;i<M;i++){for(j=0;j<M;j++){name[i][j] = 0; //初始化二维数组为0,当有棋子落下时,根据红绿变为1或2}}system("cls");SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);// 此函数为设置背景颜色为白色函数,可以自行百度for(i=0;i<M;i++){for(j=0;j<M;j++){if(name[i][j] == 0)cout<<"+"; //输出棋盘,即15*15 个 + 号}cout<<endl;}gotoxy(42,2);cout<<"按Eas返回上级菜单";gotoxy(42,3); // 在右边输出一些提示cout<<"按 2 悔棋 ";gotoxy(42,4);cout<<"按 1 重新开始"<<endl;gotoxy(42,5);cout<<"按 0 结束游戏"<<endl;gotoxy(14,7);}//chess函数,下棋函数void Qipan::chess(){node *h,*p,*q,*r; // 定义一些结点指针,悔棋时用到h = (node *)malloc(sizeof(node));p = h;h->a = 0; //头结点初始化为0h->b = 0;h->next = NULL;while((t = getch()) != 27) //接收用户的输入,并且判断不为0,因为0是结束游戏{switch(t){case 'w': // w s a d 和上下左右键是移动光标的if(b>0){b = b-1;gotoxy(a,b);}break;case 's':if(b<14){b = b+1;gotoxy(a,b);}break;case 'a':if(a>0){a = a-2;gotoxy(a,b);}break;case 'd':if(a<28){a = a+2;gotoxy(a,b);}break;case 72: //上下左右方向键if(b>0){b = b-1;gotoxy(a,b);}break;case 80:if(b<14){b = b+1;gotoxy(a,b);}break;case 75:if(a>0){a = a-2;gotoxy(a,b);}break;case 77:if(a<28){a = a+2;gotoxy(a,b);}break;case ' ': // 空格键和enter键是落子if(name[(a/2)][b] == 0) //判断二维数组的值是否为0,如果是,则表示此处没有棋子{q = (node *)malloc(sizeof(node));q->a = a;q->b = b;q->next = NULL; //将当前光标的坐标即a,b赋给结点,即用结点记录棋子的坐标p->next = q;p = q;if(player == 1){SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_GREEN);c out<<"●"; //设置颜色gotoxy(a,b);name[(a/2)][b] = 1; //落子后,二维数组的值相应的变为1或2win(); // 每下一次棋,就要调用此函数判断是否有五子连线}else{SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_RED);cout<<"●";gotoxy(a,b);name[(a/2)][b] = 2;win();}player=(player==1)?2:1; //下完一次棋,player由红变为绿,或由绿变为红}break;case 13: //enter键的ASCII,和空格键作用一样if(name[(a/2)][b] == 0){q = (node *)malloc(sizeof(node));q->a = a;q->b = b;q->next = NULL;p->next = q;p = q;if(player == 1){SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_GREEN);cout<<"●";gotoxy(a,b);name[(a/2)][b] = 1;win();}else{SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGR OUND_INTENSITY|FOREGROUND_RED);cout<<"●";gotoxy(a,b);name[(a/2)][b] = 2;win();}player=(player==1)?2:1;}break;}if(t == 48)break;if(t == 49)break;if(t == 50) // 2的ASCII为50,即用户要悔棋{r = h;if(p !=r){if(r->next == p){p = r;}else{for(int i=0;;i++){r = r->next;if(r->next == p){ p = r;break;}}}a = q->a; // 此为悔棋步骤,先找到最后一个结点,即最后一棋子的位置,因为坐标保存在了结点里b = q->b;gotoxy(a,b);SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGR OUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);cout<<"+";gotoxy(a,b); // 悔棋后,player也需要变name[(a/2)][b] = 0;player=(player==1)?2:1;free(q);q = p;}}}SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGR OUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN |FOREGROUND_BLUE);// 设置背景颜色}//win函数,判断是否有五子void Qipan::win(){ // 此函数判断是否有五子相连,需要从横竖些捺四个方向判断int i,j,count[8]={0},k;for(j=0;j<M;j++) // 从第一个位置开始,判断横向是否有五子{for(i=0;i<M;i++){for(k=0;k<5;k++){if(name[i][j+k]==1){count[0]++;}if(name[i][j+k]==2){count[1]++;}}output(count);}}//for(j=0;j<M;j++) // 从第一个位置开始,判断竖向是否有五子{for(i=0;i<M;i++){for(k=0;k<5;k++){if(name[i+k][j]==1){count[2]++;}if(name[i+k][j]==2){count[3]++;}}output(count);}}//for(j=0;j<M;j++){for(i=0;i<M;i++){for(k=0;k<5;k++){if(name[i+k][j+k]==1){count[4]++;}if(name[i+k][j+k]==2){count[5]++;}}output(count);}}//for(j=0;j<M;j++){for(i=0;i<M;i++){for(k=0;k<5;k++){if(name[i+k][j-k]==1){count[6]++;}if(name[i+k][j-k]==2){count[7]++;}}output(count);}}}//output函数,输出赢的一方void Qipan::output(int count[8]) // 如果有五子相连,则有一方胜利,此函数输出胜利者{if(count[0]==5 || count[2]==5 || count[4]==5 || count[6]==5){SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGR OUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN |FOREGROUND_BLUE);gotoxy(42,8);cout<<"绿棋赢了"<<endl;gotoxy(a,b);fflush(stdin);}if(count[1]==5 || count[3]==5 || count[5]==5 || count[7]==5) {SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FORE GROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);gotoxy(42,8);cout<<"红棋赢了"<<endl;gotoxy(a,b);fflush(stdin);}for(int i=0;i<8;i++){count[i] = 0;}}//explain函数,说明函数void Qipan::explain(){system("cls");cout<<"按w s a d 或上下左右键进行移动"<<endl;cout<<"按空格键或 Enter 键进行落子"<<endl;cout<<"按任意键上级菜单"<<endl;}。