MFC设计五子棋完全代码
- 格式:doc
- 大小:354.50 KB
- 文档页数:15
C语言五子棋游戏源代码标准化管理处编码[BBX968T-XBB8968-NNJ668-MM9N]#define N 10void welcome();void initqipan();void showqi(int i);void save(int p);void panduan(int p);void heqi();void over();int zouqihang();int zouqilie();/******************结构体*****************/ struct zuobiao{int x[N*N];int y[N*N];}weizhi[N*N];/******************主函数*****************/ void main(){int p=0;welcome();initqipan();for(p=1;p<=N*N;p++){weizhi[p].x[p]=zouqihang();weizhi[p].y[p]=zouqilie();save(p);showqi(p);panduan(p);}if(p==N*N)heqi();over();}/******************建立棋盘*****************/ void initqipan(){int i,j;for(i=0;i<N;i++){printf("%d",i);printf(" ");}printf("\n");for(i=1;i<N;i++){for(j=0;j<N;j++){if(j==0)printf("%d",i);elseprintf("·");}printf("\n");}}/******************显示棋子*****************/ void showqi(int p){int i,j,k,m;int a[N*N],b[N*N];FILE *fp;fp=fopen("wuzi_list","rb");for(i=1;i<=N*N;i++){fread(&weizhi[i],sizeof(struct zuobiao),1,fp);a[i]=weizhi[i].x[i];b[i]=weizhi[i].y[i];}for(m=1;m<p;m++){while(weizhi[p].x[p]==a[m]&&weizhi[p].y[p]==b[m]) {printf("error!\n");weizhi[p].x[p]=zouqihang();weizhi[p].y[p]=zouqilie();m=1;}}for(i=0;i<N;i++){printf("%d",i);printf(" ");}printf("\n");for(i=1;i<N;i++){for(j=1;j<N;j++){if(j==1)printf("%d",i);for(k=1;k<=p;k++){if(i==weizhi[k].x[k]&&j==weizhi[k].y[k]) {if(k%2==1){printf("○");break;} else if(k%2==0){printf("●");break;} }}if(k>p)printf("·");else continue;}printf("\n");}}/******************走棋行*****************/ int zouqihang(){int x;printf("请输入要走棋子所在行数!\n");printf("x=");scanf("%d",&x);while(x>N-1||x<1){printf("error!\n");printf("请输入要走棋子所在行数!\n"); printf("x=");scanf("%d",&x);}return x;}/******************走棋列*****************/ int zouqilie(){int y;printf("请输入要走棋子所在列数!\n");printf("y=");scanf("%d",&y);while(y>N-1||y<1){printf("error!\n");printf("请输入要走棋子所在列数!\n"); printf("y=");scanf("%d",&y);}return y;}/******************文件保存*****************/ void save(int i){FILE *fp;fp=fopen("wuzi_list","wb");fwrite(&weizhi[i],sizeof(struct zuobiao),1,fp);}/****************判断输赢*******************/void panduan(int p){int i,j,k[8]={1,1,1,1,1,1,1,1,};int a[N*N],b[N*N];FILE *fp;fp=fopen("wuzi_list","rb");for(i=1;i<=p;i++){fread(&weizhi[i],sizeof(struct zuobiao),1,fp); a[i]=weizhi[i].x[i];b[i]=weizhi[i].y[i];}/*****************判断行******************/for(i=1;i<=p;i++){if(i%2==1){for(j=1;j<=p;j=j+2){if((a[i]==a[j])&&(b[i]==b[j]-1)){k[0]++;continue;}else if((a[i]==a[j])&&(b[i]==b[j]-2)) {k[0]++;continue;}else if((a[i]==a[j])&&(b[i]==b[j]-3)) {k[0]++;continue;}else if((a[i]==a[j])&&(b[i]==b[j]-4)) {k[0]++;continue;}else if(k[0]==5){printf("Player 1 wins!!!\n");}elsecontinue;}if(k[0]==5)break;k[0]=1;}else if(k[0]==5)break;else if(i%2==0){for(j=2;j<=p;j=j+2){if((a[i]==a[j])&&(b[i]==b[j]-1)) {k[1]++;continue;}else if((a[i]==a[j])&&(b[i]==b[j]-2)) {k[1]++;continue;}else if((a[i]==a[j])&&(b[i]==b[j]-3)) {k[1]++;continue;}else if((a[i]==a[j])&&(b[i]==b[j]-4)) {k[1]++;continue;}else if(k[1]==5){printf("Player 2 wins!!!\n");}elsecontinue;}if(k[1]==5)break;k[1]=1;}}/**********************判断列************************/ for(i=1;i<=p;i++){if(k[0]==5||k[1]==5)break;else if(i%2==1){for(j=1;j<=p;j=j+2){if((a[i]==a[j]-1)&&(b[i]==b[j])){k[2]++;continue;}else if((a[i]==a[j]-2)&&(b[i]==b[j])) {k[2]++;continue;}else if((a[i]==a[j]-3)&&(b[i]==b[j])) {k[2]++;continue;}else if((a[i]==a[j]-4)&&(b[i]==b[j])) {k[2]++;continue;}else if(k[2]==5){printf("Player 1 wins!!!\n");}elsecontinue;}if(k[2]==5)break;k[2]=1;}else if(k[2]==5)break;else if(i%2==0){for(j=2;j<=p;j=j+2){if((a[i]==a[j]-1)&&(b[i]==b[j])){k[3]++;continue;}else if((a[i]==a[j]-2)&&(b[i]==b[j])) {k[3]++;continue;}else if((a[i]==a[j]-3)&&(b[i]==b[j])) {k[3]++;continue;}else if((a[i]==a[j]-4)&&(b[i]==b[j])) {k[3]++;continue;}else if(k[3]==5){printf("Player 2 wins!!!\n");}elsecontinue;}if(k[3]==5)break;k[3]=1;}}/****************判断对角(左上-右下)******************/ for(i=1;i<=p;i++){if(k[0]==5||k[1]==5||k[2]==5||k[3]==5)break;else if(i%2==1){for(j=1;j<=p;j=j+2){if((a[i]==a[j]-1)&&(b[i]==b[j]-1)){k[4]++;continue;}else if((a[i]==a[j]-2)&&(b[i]==b[j]-2)) {k[4]++;continue;}else if((a[i]==a[j]-3)&&(b[i]==b[j]-3)) {k[4]++;continue;}else if((a[i]==a[j]-4)&&(b[i]==b[j]-4)) {k[4]++;continue;}else if(k[4]==5){printf("Player 1 wins!!!\n");}elsecontinue;}if(k[4]==5)break;k[4]=1;}else if(k[2]==5)break;else if(i%2==0){for(j=2;j<=p;j=j+2){if((a[i]==a[j]-1)&&(b[i]==b[j]-1)){k[5]++;continue;}else if((a[i]==a[j]-2)&&(b[i]==b[j]-2)) {k[5]++;continue;}else if((a[i]==a[j]-3)&&(b[i]==b[j]-3)) {k[5]++;continue;}else if((a[i]==a[j]-4)&&(b[i]==b[j]-4)) {k[5]++;continue;}else if(k[5]==5){printf("Player 2 wins!!!\n");}elsecontinue;}if(k[5]==5)break;k[5]=1;}}/**********判断对角(左下-右上)************/for(i=1;i<=p;i++){if(k[0]==5||k[1]==5||k[2]==5||k[3]==5||k[4]==5||k[5]==5) break;else if(i%2==1){for(j=1;j<=p;j=j+2){if((a[i]==a[j]+1)&&(b[i]==b[j]-1)){k[6]++;continue;}else if((a[i]==a[j]+2)&&(b[i]==b[j]-2)) {k[6]++;continue;}else if((a[i]==a[j]+3)&&(b[i]==b[j]-3)) {k[6]++;continue;}else if((a[i]==a[j]+4)&&(b[i]==b[j]-4))k[6]++;continue;}else if(k[6]==5){printf("Player 1 wins!!!\n"); }elsecontinue;}if(k[6]==5)break;k[6]=1;}else if(k[6]==5)else if(i%2==0){for(j=2;j<=p;j=j+2){if((a[i]==a[j]+1)&&(b[i]==b[j]-1)){k[7]++;continue;}else if((a[i]==a[j]+2)&&(b[i]==b[j]-2)) {k[7]++;continue;}else if((a[i]==a[j]+3)&&(b[i]==b[j]-3))k[7]++;continue;}else if((a[i]==a[j]+4)&&(b[i]==b[j]-4)) {k[7]++;continue;}else if(k[7]==5){printf("Player 2 wins!!!\n");}elsecontinue;}if(k[7]==5)break;k[7]=1;}}}/****************和棋*******************/void heqi(){printf("************************************\n"); printf(" Tie!!!\n");printf("************************************\n"); }/****************游戏结束*******************/void over(){printf("************************************\n"); printf(" game over!!!\n");printf("************************************\n"); }/****************游戏开始*******************/void welcome(){printf("************************************\n"); printf(" Welcome!!!\n");printf("************************************\n"); }。
五子棋C语言程序代码#include <graphics.h>#include <stdio.h>#include <conio.h>void drawPanel();int isWin(int,int);int color = 1; //1-红色2-白色int chessman[15][15];//主函数void main(){initgraph(620,620); //产生窗体//画棋盘drawPanel();//画棋子//1.定义鼠标事件MOUSEMSG m;HWND wnd = GetHWnd(); //定义当前窗体的句柄while(true){m = GetMouseMsg(); //获取鼠标事件对象if(m.uMsg == WM_LBUTTONDOWN){//获取点击的坐标int x = m.x;int y = m.y;//换算成二维数组中的下标int i = x/40;int j = y/40;//显示点击的坐标/*char msg[100];sprintf(msg,"%d,%d",i,j);MessageBoxA(wnd,msg,"消息",MB_OK);*/if(color==1){setfillstyle(RGB(255,0,0));fillcircle(40*i+20,40*j+20,20);chessman[i][j] = 1;}else if(color==2){setfillstyle(RGB(255,255,255));fillcircle(40*i+20,40*j+20,20);chessman[i][j] = 2;}//判断输赢result => 1int result = isWin(i,j);if(result ==1){if(color==1){MessageBoxA(wnd,_T("恭喜,红方获胜!"),"消息",MB_OK);}else if(color==2){MessageBoxA(wnd,_T("恭喜,白方获胜!"),"消息",MB_OK);}break;}//切换对方下子color = color == 1 ? 2 : 1 ;}}getch();closegraph(); //关闭窗体}int isWin(int x,int y){int count=0;//计数器int i;//横向for(i=0;i<15;i++){if(chessman[i][y]==color){count++;if(count==5)return 1;}else{count=0;}}//竖向for(i=0;i<15;i++){if(chessman[x][i]==color){count++;if(count==5)return 1;}else{count=0;}}return 0;}void drawPanel(){int i;//画横线for(i=0;i<15;i++){line(20,20+40*i,20+14*40,20+40*i);}//画竖线for(i=0;i<15;i++){line(20+40*i,20,20+40*i,20+14*40);}}。
目录一、绪论 (1)1.1课题背景 (1)1.2需求分析 (1)2.1游戏流程 (1)2.2系统功能结构图 (2)三、详细设计 (3)3.1.1游戏界面的制作 (3)3.1.2游戏开始 (4)3.1.3游戏结束 (5)3.1.4排行榜 (6)3.2核心算法 (6)四、用户使用说明 (8)4.1游戏开始 (8)4.2游戏中 (8)4.3结束 (9)五、附录 (10)参考资料 (10)一、绪论1.1课题背景本课程设计是C++面向对象程序设计的重要的实践环节之一,是在学生学习完《C++面向对象程序设计》课程后进行的一次全面的综合练习,此次课程设计的题目是自拟的。
在和我的队友反复的讨论下,我们一致同意写以C++和MFC 为主要知识点的MFC人—人对战五子棋。
1.2需求分析(1)设计用户图形界面,用户通过鼠标就可以操作游戏。
(2)以二维数组的形式储存棋盘的下子信息,包括坐标和棋子类型。
(3)设置开始、结束和排行榜用于操作和查看下棋的信息。
(4)游戏有自动保存玩家输赢信息的功能。
(5)为了使算法简单,游戏中的棋盘、棋子等都以位图的形式操作。
二、概要设计2.1游戏流程三、详细设计3.1.1游戏界面的制作利用MFC AppWinzard生成五子棋游戏应用程序框架具体步骤如下:(1)执行VC程序,选择File|New命令,弹出New对话框.单击Projects标签,转到Projects选项卡,选择MFC AppWizard(exe)选项,然后在Project name文本框中输入Fivechess_44 。
Lacation文本框是指项目的本地路径。
(2)单击按钮,弹出MFC AppWinzard_Step1对话框。
选中单选按钮,如图所示。
(3)单击完成按钮,则建立一个单文档应用框架。
(4)将单文档的菜单栏去掉,并加入背景图片。
背景图片中包含了棋盘。
部分代码如下:3.1.2游戏开始(1)界面中的设置,以位图的形式放到背景中。
一下代码为纯c写的单机版五子棋代码,可用vc6.0编译运行#include <stdio.h>#include <conio.h>#include <windows.h>#include <time.h>#define TEXTS 7 // 文本颜色#define CURSOR 48 // 光标颜色#define CHESSBOARD 352 // 棋盘颜色#define WHITECHESS 103 // 白棋颜色#define SELECTEDWHITE 55 // 白棋被选中时的颜色#define BLACKCHESS 96 // 黑棋颜色#define SELECTEDBLACK 48 // 黑棋被选中时的颜色#define qx1_num 27 // 防御棋形的数量#define qx2_num 26 // 攻击棋形的数量typedef struct node{ // 棋盘信息int step; // 步数,步数为0表示该位置为空int color; // 棋子的颜色} NODE;typedef struct point{ //点int x;int y;} _POINT;typedef struct qixing{ // 棋形信息char qx[8]; // 棋形int value; // 相应的权值}QIXING;HANDLE hOutput=GetStdHandle(STD_OUTPUT_HANDLE); // 得到标准输出的句柄_POINT cursor; // 游戏中,光标所在的当前位置int direction[8][2]={{0,-1},{0,1},{-1,0},{1,0},{-1,-1},{1,1},{-1,1},{1,-1}};// 向量数组,依次为左、右、上、下、左上、右下、右上、左下QIXING qx1[qx1_num]={{"x1111",200000},{"1x111",200000},{"11x11",200000}, // 连五型{"0x1110",6000},{"01x110",6000},{"101x101",6000}, // 活四型{"0x111",1100},{"x0111",1100},{"0x1011",1100},{"0x1101",1100},{"01x11",1100}, // 冲四型{"011x1",1100},{"1x011",1100},{"10x11",1100},{"11x01",1100},{"1x101",1100}, // 冲四型{"x011102",250},{"0x110",250},{"01x10",250},{"0x01102",240},{"0x101",240}, // 活三型{"0x112",20},{"01x12",10},{"011x2",20},{"1x12",10},{"0x10",20},{"0x010",5}}; // 死三活二//防御的基本棋形及权值,0为空,1为对手,2为自己,x为下棋位置QIXING qx2[qx2_num]={{"x1111",2000000},{"1x111",2000000},{"11x11",2000000}, // 连五型{"0x1110",24000},{"01x110",24000}, {"101x101",24000}, //活四型{"0x111",2000},{"x0111",1900},{"0x1011",1900},{"0x1101",2000},{"01x11",2000}, // 冲四型{"011x1",2000},{"1x011",1900},{"10x11",2000},{"1x101",2000},{"x01112",2000}, // 冲四型{"0x110",850},{"01x10",850},{"0x0110",840},{"0x101",840},//活三型{"0x112",125},{"01x12",125},{"011x2",115},{"1x12",115},{"0x10",125},{"0x010",110}};// 死三活二// 攻击的基本棋形及权值,0为空,1为自己,2为对手,x为下棋位置//----------------------------------界面部分---------------------------------void textcolor(int color){// 更改字体颜色SetConsoleTextAttribute(hOutput,color);}void gotoxy(int x, int y){// 将光标移动到指定位置COORD coordScreen = { 0, 0 };coordScreen.X=x;coordScreen.Y=y;SetConsoleCursorPosition( hOutput, coordScreen );}void printnode(NODE chessboard[][15], int x, int y)// 打印棋盘上的一个点{textcolor(CHESSBOARD);if(chessboard[x][y].step==0) {if (x==cursor.x && y==cursor.y)textcolor(CURSOR); // 如果光标在这个点,改成光标颜色switch(x){case 0:if(y==0) printf("┏"); // 左上角else if(y==14) printf("┓"); // 右上角else printf("┯"); // 上边线break;case 3:if(y==0) printf("┠"); // 左边线else if(y==3 || y==11) printf("+"); // 星位else if(y==14) printf("┨"); // 右边线else printf("┼");// 交叉点break;case 7:if(y==0) printf("┠"); // 左边线else if(y==7) printf("+"); // 星位else if(y==14) printf("┨"); // 右边线else printf("┼");// 交叉点break;case 11:if(y==0) printf("┠"); // 左边线else if(y==3 || y==11) printf("+"); // 星位else if(y==14) printf("┨"); // 右边线else printf("┼");// 交叉点break;case 14:if(y==0) printf("┗"); // 左下角else if(y==14) printf("┛"); // 右下角else printf("┷"); // 下边线break;default:if(y==0) printf("┠"); // 左边线else if(y==14) printf("┨"); // 右边线else printf("┼");// 交叉点}}else if(chessboard[x][y].color==0){ // 如果是白棋if (x==cursor.x && y==cursor.y)textcolor(SELECTEDWHITE); // 被选中的白棋else textcolor(WHITECHESS); // 未被选中的白棋printf("●");} // 打印棋子else{if (x==cursor.x && y==cursor.y)textcolor(SELECTEDBLACK); // 被选中的黑子else textcolor(BLACKCHESS); // 未被选中的黑子printf("●");} // 打印棋子}void printchessboard(NODE chessboard[][15]){// 输出整个棋盘int i,j;char letter[]={"ABCDEFGHIJKLMNO\n"};for(i=0;i<15;i++){ // 行textcolor(TEXTS); // 改为文本颜色printf("%2d",15-i); // 打印行坐标for(j=0;j<15;j++) // 列printnode(chessboard,i,j); // 打印棋盘的每一块textcolor(TEXTS);printf("\n");}textcolor(TEXTS); //改为文本颜色printf(" %s",letter); //打印列坐标printf("移动:方向键下棋:ENTER 悔棋:U 退出:F12");}void renew(NODE chessboard[][15], int x, int y){// 更新棋盘指定位置的图像COORD coordScreen; // 系统提示符位置CONSOLE_SCREEN_BUFFER_INFO csbi; // 屏幕信息if(x<0 || x>14 || y<0 || y>14) return; // 如果不在棋盘上直接返回if( !GetConsoleScreenBufferInfo( hOutput, &csbi )) // 获取屏幕信息return; // 不成功则返回coordScreen=csbi.dwCursorPosition; // 获取系统提示符位置gotoxy((y-1)*2+4,x+1); // 将系统提示符移动到棋盘的(x,y)所在位置printnode(chessboard,x,y); // 重新打印这一块SetConsoleCursorPosition( hOutput, coordScreen );// 系统提示符回复到原来位置}void showmenu(){// 输出主菜单textcolor(TEXTS);system("cls");printf("1.人机对战\n");printf("2.双人对战\n");printf("3.退出\n");printf("\n请选择[1-3]:");}void showsubmenu(){// 打印子菜单textcolor(TEXTS);system("cls");printf("1.你先手\n");printf("2.电脑先手\n");printf("3.返回上级菜单\n");printf("\n请选择[1-3]:");}int getchoose(int min, int max){// 获取选项int choose;do{choose=getch()-48;}while(choose<min || choose>max); //过滤不在min到max之间的字符printf("%d",choose); //屏幕回显return choose;}//----------------------------------控制部分---------------------------------bool quit; //是否按下了退出热键bool regret; //是否按下了悔棋热键bool getmove(NODE chessboard[][15]){// 获取光标移动,并响应// 当按下悔棋、下子、退出热键时,返回truechar c;for(;;){c=getch();if(c==-32)switch(getch()){case 72: // 上cursor.x--;if(cursor.x<0) cursor.x=0;renew(chessboard,cursor.x+1,cursor.y);renew(chessboard,cursor.x,cursor.y);break;case 80: // 下cursor.x++;if(cursor.x>14) cursor.x=14;renew(chessboard,cursor.x-1,cursor.y);renew(chessboard,cursor.x,cursor.y);break;case 75: // 左cursor.y--;if(cursor.y<0) cursor.y=0;renew(chessboard,cursor.x,cursor.y+1);renew(chessboard,cursor.x,cursor.y);break;case 77: // 右cursor.y++;if(cursor.y>14) cursor.y=14;renew(chessboard,cursor.x,cursor.y-1);renew(chessboard,cursor.x,cursor.y);break;case 134: // 退出quit=true;return true;}else if(c==13 && chessboard[cursor.x][cursor.y].step==0)return true; // 下子else if(c=='U' || c=='u'){ // 悔棋regret=true;return true;}}}void beback(NODE chessboard[][15], int step){//悔棋int i,j,tempx,tempy;if(step==1) return; // 如果才开始,直接返回if(step>2){ // 如果下了多于两步for(i=0;i<15;i++) // 搜索前两步所下的位置for(j=0;j<15;j++) {if(chessboard[i][j].step==step-1){ // 找到上一步chessboard[i][j].step=0; // 清空棋子标志renew(chessboard,i,j);} // 重绘棋盘else if(chessboard[i][j].step==step-2){ // 找到上两步chessboard[i][j].step=0; // 清空棋子标志tempx=cursor.x; // 记录光标位置tempy=cursor.y;cursor.x=i; // 将光标回复到两步前的位置cursor.y=j;renew(chessboard,i,j); // 重绘棋盘renew(chessboard,tempx,tempy); // 重绘光标原本所在处}}}else if(step==2){ //如果下了一步for(i=0;i<15;i++) //搜索上一步所下的位置for(j=0;j<15;j++)if(chessboard[i][j].step==step-1){ // 找到上一步chessboard[i][j].step=0; // 清空棋子标志renew(chessboard,i,j);} // 重绘棋盘tempx=cursor.x; // 记录光标位置tempy=cursor.y;cursor.x=7; // 将光标移回棋盘中央cursor.y=7;renew(chessboard,i,j); // 重绘棋盘renew(chessboard,tempx,tempy); // 重绘光标原本所在处}}//------------------------------判断部分-------------------------------bool inside(int x, int y){// 如果不在棋盘内返回false,否则返回trueif(x<0 || x>14 || y<0 || y>14) return false;return(true);}int line(NODE chessboard[][15], int dirt, int x, int y, int color){// 判断颜色为color的点(x,y),在dirt方向上有多少相连的同色棋子int i;for(i=0;chessboard[x+direction[dirt][0]][y+direction[dirt][1]].step>0 && chessboard[x+direction[dirt][0]][y+direction[dirt][1]].color==color;i++) { x=x+direction[dirt][0];y=y+direction[dirt][1];if(!inside(x,y)) return i;}return i;}bool win(NODE chessboard[][15], int x, int y, int color){// 判断是否有人赢棋if(line(chessboard,0,x,y,color)+line(chessboard,1,x,y,color)>3)return true;if(line(chessboard,2,x,y,color)+line(chessboard,3,x,y,color)>3)return true;if(line(chessboard,4,x,y,color)+line(chessboard,5,x,y,color)>3)return true;if(line(chessboard,6,x,y,color)+line(chessboard,7,x,y,color)>3)return true;return false;}//--------------------------------AI部分----------------------------------int attacktrend,defenttrend; // 攻击防御平衡权值bool macth1(NODE chessboard[][15], int x, int y, int dirt, int kind, int color){/* 匹配在颜色为color的点(x,y),在dirt方向上的第kind种防守棋形,成功返回true,否则返回false */int k;char c;char *p;p=strchr(qx1[kind].qx,'x');for(k=0;k<=p-qx1[kind].qx;k++) {x-=direction[dirt][0];y-=direction[dirt][1];}for(k=0;(unsigned)k<strlen(qx1[kind].qx);k++) {x+=direction[dirt][0];y+=direction[dirt][1];if(!inside(x,y)) return(false);if(chessboard[x][y].step>0 && chessboard[x][y].color==color) c='2';else if(chessboard[x][y].step>0) c='1';else c='0';if(c=='0' && qx1[kind].qx[k]=='x') continue;if(c!=qx1[kind].qx[k]) return(false);}return true;}int value_qx1(NODE chessboard[][15], int x, int y, int dirt, int color){// 计算颜色为color的点8个方向上的防守权值之和int i;for(i=0;i<qx1_num;i++)if(macth1(chessboard,x,y,dirt,i,color))return qx1[i].value;return 0;}bool macth2(NODE chessboard[][15], int x, int y, int dirt, int kind, int color){/* 匹配在颜色为color的点(x,y),在dirt方向上的第kind种进攻棋形,成功返回true,否则返回false */int k;char c;char *p;p=strchr(qx2[kind].qx,'x');for(k=0;k<=p-qx2[kind].qx;k++) {x-=direction[dirt][0];y-=direction[dirt][1];}for(k=0;(unsigned)k<strlen(qx2[kind].qx);k++) {x+=direction[dirt][0];y+=direction[dirt][1];if(!inside(x,y)) return false;if(chessboard[x][y].step>0 && chessboard[x][y].color==color) c='2';else if(chessboard[x][y].step>0) c='1';else c='0';if(c=='0' && qx2[kind].qx[k]=='x') continue;if(c!=qx2[kind].qx[k]) return false;}return true;}int value_qx2(NODE chessboard[][15], int x, int y, int dirt, int color){// 计算颜色为color的点8个方向上的进攻权值之和int i;for(i=0;i<qx2_num;i++)if(macth2(chessboard,x,y,dirt,i,color))return qx2[i].value ;return 0;}void AI(NODE chessboard[][15], int *x, int *y, int color){// AI的主要函数,将思考后的结果返回给*x和*yint max=0; // 价值的最大值int maxi,maxj; // 获得最大值时所对应的坐标int i,j,k; // 循环控制变量int probability=1; // 几率参数int value[15][15]={0}; // 棋盘上各点的价值int valueattack[15][15]={{0}}; // 棋盘上各点的进攻价值int valuedefent[15][15]={{0}}; // 棋盘上各点的防守价值for(i=0;i<15;i++) // 计算棋盘上各点的防守价值for(j=0;j<15;j++) {if(chessboard[i][j].step>0) continue;for(k=0;k<8;k++)valuedefent[i][j]+=value_qx1(chessboard,i,j,k,color);if(maxi<valuedefent[i][j])maxi=valuedefent[i][j]; // 记录防守价值的最大值}for(i=0;i<15;i++) // 计算棋盘上各点的进攻价值for(j=0;j<15;j++) {if(chessboard[i][j].step>0) continue;for(k=0;k<8;k++)valueattack[i][j]+=value_qx2(chessboard,i,j,k,(color+1) % 2);if(maxj<valuedefent[i][j])maxj=valuedefent[i][j]; // 记录进攻价值的最大值}if(rand()%(maxi+maxj+1)>maxi){ // 如果防守价值的最大值比较低attacktrend=1; // AI优先进攻defenttrend=1;}else{ // 相反attacktrend=1; // AI优先防守defenttrend=2;}for(i=0;i<15;i++) // 根据各点的进攻和防守价值for(j=0;j<15;j++){ // 计算最终价值value[i][j]=valuedefent[i][j]*defenttrend+valueattack[i][j]*attacktrend;if(max<value[i][j]){max=value[i][j]; // 记录价值的最大值maxi=i; // 以及相应的坐标maxj=j;probability=1;}else if(max==value[i][j]){ // 如果出现相同价值的最大点if(rand()%(probability+1)<probability) // 随机决定选取哪一个probability++; /* 由于前面的点容易被淘汰,所以相应提高前面的点的被选择的几率*/else{probability=1; // 选择后面的点,则几率权值回复max=value[i][j]; // 记录maxi=i;maxj=j;}}}*x=maxi; // 返回价值最大的点*y=maxj;}//-----------------------主要部分------------------------------------bool vshuman; //对手是否是人void Vs(bool human){//对局主要函数int i,j;int color=1; // 黑棋先走int lastx,lasty; // 光标的上一个位置int computer; // 电脑执黑还是执白NODE chessboard[15][15]={{0,0}}; // 棋盘if(!human){ // 对手是电脑showsubmenu(); // 选择谁是先手switch(getchoose(1,3)){case 1:computer=0;attacktrend=1; // 电脑先手则优先进攻defenttrend=1;break;case 2:computer=1; // 电脑后手则优先防御attacktrend=1;defenttrend=2;break;case 3:return; // 返回上级菜单}}for(i=0;i<15;i++) // 清空棋盘for(j=0;j<15;j++)chessboard[i][j].step=0;cursor.x=7; // 光标居中cursor.y=7;quit=false; // 清空退出标志system("cls"); // 清屏printf("\n");printchessboard(chessboard); // 打印棋盘for(i=1;i<=225;){ // 行棋主循环gotoxy(0,0); // 系统光标移到屏幕左上角textcolor(TEXTS);printf(" 第%03d手,",i);if(color==1) printf("黑棋下");else printf("白棋下");regret=false; // 清空悔棋标志if(i>1){ // 第一子必须下在棋盘中央if(color!=computer || human) getmove(chessboard); // 该人走棋else{ // 该电脑走棋lastx=cursor.x; // 记录光标位置lasty=cursor.y;AI(chessboard,&cursor.x,&cursor.y,color); // 电脑走棋renew(chessboard,lastx,lasty); // 更新棋盘}}if(quit) return; // 如果按了退出热键则返回if(regret){ // 如果按了悔棋热键则调用悔棋函数beback(chessboard,i);if(i>2) i-=2;else if(i==2){i=1; color=(color+1) % 2 ;}}else{ // 如果没有按热键,则在光标位置下子chessboard[cursor.x][cursor.y].step=i++;chessboard[cursor.x][cursor.y].color=color;renew(chessboard,cursor.x,cursor.y);color=(color+1) % 2 ;}if(win(chessboard,cursor.x,cursor.y,(color+1) % 2) && !regret){// 有人赢textcolor(TEXTS);gotoxy(0,0);printf(" ");gotoxy(0,0);if(color==1) printf(" 白棋赢了!");else printf(" 黑棋赢了!");getch();return;}}gotoxy(0,0); // 如果下了225步还没人赢棋则平局printf(" ");gotoxy(0,0);printf(" 平局!");}void main(void){// 主函数srand((unsigned)time(NULL)); // 初始化随机种子for(;;){showmenu(); // 输出主菜单switch(getchoose(1,3)){case 1:Vs(false); break;case 2:Vs(true); break;case 3: printf("\n"); return;}} }。
C语言教程:简易五子棋程序收集于网络/* 纯用字符和数组编的五子棋,棋盘也是用字符画的。
编了1上午了,主要是算法跟按键比较烦,发现有bug-- 按键速度过快会产生延时显示,可能是算法不好。
操作:玩家1:a,s,w,d(方向)空格(落子)玩家2:上、下、左、右回车(落子)ESC:退出编译测试环境:TC3.0*/#include <stdio.h>#include <stdlib.h>#include <bios.h>#include <conio.h>#define CRRU 0xbf /*右上角点197*/#define CRLU 0xda /*左上角点218*/#define CRLD 0xc0 /*左下角点192*/#define CRRD 0xd9 /*右下角点217*/#define CRL 0xc3 /*左边195*/#define CRR 0xb4 /*右边190*/#define CRU 0xc2 /*上边194*/#define CRD 0xc1 /*下边193*/#define CR 0xc5 /*十字交叉点197*/#define size 19char a[size][size];int i,j; //跟踪光标在数组中对应的位置int x=10;int y=3; //光标所在位的坐标int side=1; //持子方1为玩家1,2为玩家2;int CB=1; int CW=2; // 棋子图形void inita() ;void inits();void pressco(int );void pressct(int );int judge(int);int main(){inita();inits();getch();while(1){int press=bioskey(0);if(press==283)break;if(side==1){pressco(press);if(side==2)if(judge(1)==1) {gotoxy(1,1);printf("the play1 win");break;}}if(side==2){pressct(press);if(side==1)if(judge(2)==1){gotoxy(1,1);printf("the play2 win");break;}}}getch();return 0;}void inita() //数组初始化;{a[0][0]=CRLU;a[0][size-1]=CRRU;a[size-1][0]=CRLD;a[size-1][size-1]=CRRD;for(int i=1;i<size-1;i++){a[0][i]=CRU;a[size-1][i]=CRD;a[i][0]=CRL;a[i][size-1]=CRR;for(int j=1;j<size-1;j++)a[i][j]=CR;}return ;}void inits() //界面初始化{for(int i=0;i<size;i++){gotoxy(x,y+i);for(int j=0;j<size;j++)putch(a[i][j]);}gotoxy(x,y);i=0;j=0;return ;}void pressco(int m){switch(m){case 7777: //Aif(i>0) {i--;x--;gotoxy(x,y);} break;case 8051: //Sif(j<size-1){j++;y++;gotoxy(x,y);} break;case 4471: //wif(j>0) {j--;y--;gotoxy(x,y);} break;case 8292: //Dif(i<size-1){i++;x++;gotoxy(x,y);} break;case 14624: //空格if(a[i][j]!=CB&&a[i][j]!=CW){a[i][j]=CB;putch(CB);gotoxy(x,y);side=2;}break;default: break;}return ;}void pressct(int m){switch(m){case 19200: //左if(i>0) {i--;x--;gotoxy(x,y);} break;case 20480: //下if(j<size-1){j++;y++;gotoxy(x,y);} break;case 18432: //上if(j>0) {j--;y--;gotoxy(x,y);} break;case 19712: //右if(i<size-1){i++;x++;gotoxy(x,y);} break;case 7181: //回车if(a[i][j]!=CB&&a[i][j]!=CW){a[i][j]=CW;putch(CW);gotoxy(x,y);side=1;}break;default: break;}return ;}int judge(int pa) //判断是否胜利,胜利则返回1,否则返回0;// 其中i,j为当前的落子位;{int m;int sum=1;for(m=1;m<=i&&m<=j;m++) {if(a[i-m][j-m]!=pa) break;sum++;}for(m=1;m<(size-i)&&m<(size-j);m++) {if(a[i+m][j+m]!=pa) break;sum++;}if(sum>=5) return 1;else sum=1;for(m=1;m<=i;m++) {if(a[i-m][j]!=pa) break;sum++;}for(m=1;m<(size-j);m++) {if(a[i+m][j]!=pa) break;sum++;}if(sum>=5) return 1;else sum=1;for(m=1;m<=j;m++) {if(a[i][j-m]!=pa) break;sum++;}for(m=1;m<(size-j);m++) {if(a[i][j+m]!=pa) break;sum++;}if(sum>=5) return 1;else sum=1;for(m=1;m<=i&&m<(size-j);m++) {if(a[i-m][j+m]!=pa) break;sum++;}for(m=1;m<(size-i)&&m<=j;m++) {if(a[i+m][j-m]!=pa) break;sum++;}if(sum>=5) return 1;else return 0;本文章来自 21视频教程网C语言教程:简易五子棋程序_C语言程序设计教程原文链接:/html/96307.shtml。
#include <stdlib.h>#include <stdio.h>#include <conio.h>#include <string.h>#include <malloc.h>struct rcd;//声明节点结构typedef struct rcd* Record;//节点指针别名typedef struct rcd record;//节点别名#define MAXIMUS 15 //定义棋盘大小int p[MAXIMUS][MAXIMUS];//存储对局信息char buff[MAXIMUS*2+1][MAXIMUS*4+3];//输出缓冲器int Cx,Cy;//当前光标位置int Now;//当前走子的玩家,1代表黑,2代表白int wl,wp;//当前写入缓冲器的列数和行数位置char* showText;//在棋盘中央显示的文字信息int count;//回合数int Putable;//指示当前是否可以走棋int Exiting;//1为当场上无子并按ESC时询问是否退出程序的状态,2为非此状态int ExiRep;//1为当回放到最后一回合并按向后时询问是否退出回放的状态,2为非此状态Record RecBeg,RecNow;//记录的开始节点和当前节点struct rcd//记录节点结构,双链表形式{int X;//此记录走棋的X坐标int Y;//此记录走棋的Y坐标Record Next;//前一个记录Record Back;//后一个记录};Record newRecord()//记录节点构造函数{Record r=(Record)malloc(sizeof(record));//申请一个节点对象r->Next=NULL;//给予前后节点初值NULLr->Back=NULL;return r;}void Exit()//检查退出程序{int input;if(Exiting)//如果是第二次按下ESC{exit(0);}else//如果是第一次按下ESC则询问是否退出程序{showText="是否退出?再次按下ESC退出,其他键返回";Exiting=1;//指示已经按下过ESC}}void ExitRep()//检查退出回放{int input;if(ExiRep)//如果是第二次后移{ExiRep=3;}else//如果是第一次后移则询问是否退出回放{showText="是否退出?再次后移退出回放,其他键返回";ExiRep=1;//指示已经按下过后移}}void AddRecord()//添加记录{RecNow->X=Cx;//记录坐标RecNow->Y=Cy;RecNow->Next=newRecord();//创建下一个记录节点RecNow->Next->Back=RecNow;//完成双链表RecNow=RecNow->Next;//当前记录推至下一个记录节点}int DelRecord()//删除当前记录节点,1为删除成功,0为删除失败{Record b;//上一个节点if(RecNow->Back!=NULL)//越界检查{b=RecNow->Back;//缓存上一个节点free(RecNow);//释放当前节点RecNow=b;//当前记录回至上一个记录节点return 1;}else{return 0;//没有节点可删除时}}void CleanRecord()//清理所有记录{Record n;//下一个节点while(RecBeg->Next!=NULL)//删除所有记录,直到越界前为止{n=RecBeg->Next;//记下下一个节点free(RecBeg);//释放当前节点RecBeg=n;//当前记录推至下一个记录节点}}char* Copy(char* strDest,const char* strSrc)//修改过的字符串复制函数,会忽略末端的\0 {char* strDestCopy = strDest;while (*strSrc!='\0'){*strDest++=*strSrc++;}return strDestCopy;}void Initialize()//初始化一个对局函数{int i,j;//循环变量system("title 对局中(按方向键控制光标,空格走子),Esc撤销");showText="";//重置显示信息count=0;//回合数归零RecNow=RecBeg=newRecord();Exiting=0;for(i=0;i<MAXIMUS;i++)//重置对局数据{for(j=0;j<MAXIMUS;j++){p[i][j]=0;}}Cx=Cy=MAXIMUS/2;//重置光标到中央Now=1;//重置当前为黑方}char* getStyle(int i,int j)//获得棋盘中指定坐标交点位置的字符,通过制表符拼成棋盘{if(p[i][j]==1)//1为黑子return "●";else if(p[i][j]==2)//2为白子return "○";else if(i==0&&j==0)//以下为边缘棋盘样式return "┏";else if(i==MAXIMUS-1&&j==0)return "┓";else if(i==MAXIMUS-1&&j==MAXIMUS-1)return "┛";else if(i==0&&j==MAXIMUS-1)return "┗";else if(i==0)return "┠";else if(i==MAXIMUS-1)return "┨";else if(j==0)return "┯";else if(j==MAXIMUS-1)return "┷";return "┼";//中间的空位}char* getCurse(int i,int j){//获得指定坐标交点位置左上格的样式,通过制表符来模拟光标的显示if(Putable)//可走棋时光标为粗线{if(i==Cx){if(j==Cy)return "┏";else if (j==Cy+1)return "┗";}else if(i==Cx+1){if(j==Cy)return "┓";else if (j==Cy+1)return "┛";}}else//不可走棋时光标为虚线{if(i==Cx){if(j==Cy)return "┌";else if (j==Cy+1)return "└";}else if(i==Cx+1){if(j==Cy)return "┐";else if (j==Cy+1)return "┘";}}return "";//如果不在光标附近则为空}void write(char* c)//向缓冲器写入字符串{Copy(buff[wl]+wp,c);wp+=strlen(c);}void ln()//缓冲器写入位置提行{wl+=1;wp=0;}void Display()//将缓冲器内容输出到屏幕{int i,l=strlen(showText);//循环变量,中间文字信息的长度int Offset=MAXIMUS*2+2-l/2;//算出中间文字信息居中显示所在的横坐标位置if(Offset%2==1)//如果位置为奇数,则移动到偶数,避免混乱{Offset--;}Copy(buff[MAXIMUS]+Offset,showText);//讲中间文字信息复制到缓冲器if(l%2==1)//如果中间文字长度为半角奇数,则补上空格,避免混乱{*(buff[MAXIMUS]+Offset+l)=0x20;}system("cls");//清理屏幕,准备写入for(i=0;i<MAXIMUS*2+1;i++){//循环写入每一行printf("%s",buff[i]);if(i<MAXIMUS*2)//写入完每一行需要换行printf("\n");}}void Print()//将整个棋盘算出并储存到缓冲器,然后调用Display函数显示出来{int i,j;//循环变量wl=0;wp=0;for(j=0;j<=MAXIMUS;j++)//写入出交点左上角的字符,因为需要打印棋盘右下角,所以很以横纵各多一次循环{for(i=0;i<=MAXIMUS;i++){write(getCurse(i,j));//写入左上角字符if(j==0||j==MAXIMUS)//如果是棋上下盘边缘则没有连接的竖线,用空格填充位置{if(i!=MAXIMUS)write("");}else//如果在棋盘中间则用竖线承接上下{if(i==0||i==MAXIMUS-1)//左右边缘的竖线更粗write("┃");else if(i!=MAXIMUS)//中间的竖线write("│");}}if(j==MAXIMUS)//如果是最后一次循环,则只需要处理边侧字符,交点要少一排{break;}ln();//提行开始打印交点内容write("");//用空位补齐位置for(i=0;i<MAXIMUS;i++)//按横坐标循环正常的次数{write(getStyle(i,j));//写入交点字符if(i!=MAXIMUS-1)//如果不在最右侧则补充一个横线承接左右{if(j==0||j==MAXIMUS-1){write("━");//上下边缘的横线更粗}else{write("─");//中间的横线}}}ln();//写完一行后提行}Display();//将缓冲器内容输出到屏幕}int Put(){//在当前光标位置走子,如果非空,则返回0表示失败if(Putable){p[Cx][Cy]=Now;//改变该位置数据AddRecord();return 1;//返回1表示成功}else{return 0;}}int Check()//胜负检查,即判断当前走子位置有没有造成五连珠的情况{int w=1,x=1,y=1,z=1,i;//累计横竖正斜反邪四个方向的连续相同棋子数目for(i=1;i<5;i++)if(Cy+i<MAXIMUS&&p[Cx][Cy+i]==Now)w++;else break;//向下检查for(i=1;i<5;i++)if(Cy-i>0&&p[Cx][Cy-i]==Now)w++;else break;//向上检查if(w>=5)return Now;//若果达到5个则判断当前走子玩家为赢家for(i=1;i<5;i++)if(Cx+i<MAXIMUS&&p[Cx+i][Cy]==Now)x++;else break;//向右检查for(i=1;i<5;i++)if(Cx-i>0&&p[Cx-i][Cy]==Now)x++;else break;//向左检查if(x>=5)return Now;//若果达到5个则判断当前走子玩家为赢家for(i=1;i<5;i++)if(Cx+i<MAXIMUS&&Cy+i<MAXIMUS&&p[Cx+i][Cy+i]==Now)y++;else break;//向右下检查for(i=1;i<5;i++)if(Cx-i>0&&Cy-i>0&&p[Cx-i][Cy-i]==Now)y++;else break;//向左上检查if(y>=5)return Now;//若果达到5个则判断当前走子玩家为赢家for(i=1;i<5;i++)if(Cx+i<MAXIMUS&&Cy-i>0&&p[Cx+i][Cy-i]==Now)z++;else break;//向右上检查for(i=1;i<5;i++)if(Cx-i>0&&Cy+i<MAXIMUS&&p[Cx-i][Cy+i]==Now)z++;else break;//向左下检查if(z>=5)return Now;//若果达到5个则判断当前走子玩家为赢家return 0;//若没有检查到五连珠,则返回0表示还没有玩家达成胜利}void ReplayMode(){int i,j;//循环变量system("title 回放中(按左键后退,右键或空格前进),Esc退出");showText="";//重置显示信息count=0;//回合数归零Putable=0;//不可走棋状态RecBeg->Back=newRecord();RecBeg->Back->Next=RecBeg;RecBeg=RecBeg->Back;for(i=0;i<MAXIMUS;i++)//重置对局数据{for(j=0;j<MAXIMUS;j++){p[i][j]=0;}}Now=1;//重置当前为黑方}void RepForward()//回放模式前进{if(RecNow->Next->Next!=NULL)//越界检查{RecNow=RecNow->Next;//当前节点推至下一个记录节点p[RecNow->X][RecNow->Y]=Now;//按照记录还原一个回合Cx=RecNow->X;//设置光标位置Cy=RecNow->Y;Now=3-Now;//转换当前的黑白方}else//若已达到最后则询问退出{ExitRep();}}void RepBackward()//回放模式后退{if(RecNow->Back!=NULL)//越界检查{p[RecNow->X][RecNow->Y]=0;//按照记录撤销一个回合if(RecNow->Back->Back==NULL)//在整个棋盘没有棋子时隐藏光标{Cx=-2;Cy=-2;}else if(RecNow->Back==NULL)//在只有一个棋子时移动光标到这个棋子的位置{Cx=RecNow->X;Cy=RecNow->Y;}else//正常情况下移动光标到上一回合的位置{Cx=RecNow->Back->X;Cy=RecNow->Back->Y;}RecNow=RecNow->Back;//当前节点后退至上一个记录节点Now=3-Now;//转换当前的黑白方}}void ShowReplay(){int input;//输入变量ReplayMode();//初始化回放模式RecNow=RecBeg;//当前观察从头开始RepForward();//显示第一次走棋while(1)//开始无限回合的死循环,直到Esc退出{if(ExiRep==3){ExiRep=0;break;}Print();//打印棋盘input=getch();//等待键盘按下一个字符if(input==27)//如果是ESC则退出回放{return;}else if(input==0x20)//如果是空格则前进{RepForward();continue;}else if(input==0xE0)//如果按下的是方向键,会填充两次输入,第一次为0xE0表示按下的是控制键{input=getch();//获得第二次输入信息switch(input)//判断方向键方向并移动光标位置{case 0x4B:RepBackward();//向左后退break;case 0x4D:RepForward();//向右前进continue;}}ExiRep=0;//未再次按后移则不准备退出showText="";}}void Regret()//悔棋撤销,如果棋盘上没有子即为退出{if(DelRecord()){//尝试删除当前节点,如果有节点可以删除则p[RecNow->X][RecNow->Y]=0;//撤除当前回合if(RecNow->Back==NULL)//如果删除的是第一颗子则将光标移动到第一颗子原来的位置上{Cx=RecNow->X;Cy=RecNow->Y;}else//否则将光标移动到上一颗子上{Cx=RecNow->Back->X;Cy=RecNow->Back->Y;}Now=3-Now;//反转当前黑白方}else{Exit();//如果没有棋子可以撤销,则询问退出}}int RunGame()//进行整个对局,返回赢家信息(虽然有用上){int input;//输入变量int victor;//赢家信息Initialize();//初始化对局while(1){//开始无限回合的死循环,直到出现胜利跳出Putable=p[Cx][Cy]==0;Print();//打印棋盘input=getch();//等待键盘按下一个字符if(input==27)//如果是ESC则悔棋或退出{Regret();Print();continue;}else if(input==0x20)//如果是空格则开始走子{if(Put())//如果走子成功则判断胜负{victor=Check();Now=3-Now;//轮换当前走子玩家count++;if(victor==1)//如果黑方达到胜利,显示提示文字并等待一次按键,返回胜利信息{showText="黑方胜利!按R查看回放,按其他键重新开局";Print();input=getch();if(input==0xE0){getch();}else if(input=='R'||input=='r'){ShowReplay();}return Now;}else if(victor==2)//如果白方达到胜利,显示提示文字并等待一次按键,返回胜利信息{showText="白方胜利!按R查看回放,按其他键重新开局";Print();input=getch();if(input==0xE0)getch();}else if(input=='R'||input=='r'){ShowReplay();}return Now;}else if(count==MAXIMUS*MAXIMUS)//如果回合数达到了棋盘总量,即棋盘充满,即为平局{showText="平局!按R查看回放,按其他键重新开局";Print();input=getch();if(input==0xE0){getch();}else if(input=='R'||input=='r'){ShowReplay();}CleanRecord();return 0;}}}else if(input==0xE0)//如果按下的是方向键,会填充两次输入,第一次为0xE0表示按下的是控制键{input=getch();//获得第二次输入信息switch(input)//判断方向键方向并移动光标位置{case 0x4B://Cx--;break;case 0x48:Cy--;break;case 0x4D:Cx++;break;case 0x50:Cy++;}if(Cx<0)Cx=MAXIMUS-1;//如果光标位置越界则移动到对侧if(Cy<0)Cy=MAXIMUS-1;if(Cx>MAXIMUS-1)Cx=0;if(Cy>MAXIMUS-1)Cy=0;}Exiting=0;//未再次按下ESC则不准备退出showText="";}}int main()//主函数{system("mode con cols=63 lines=32");//设置窗口大小system("color E0");//设置颜色while(1){//循环执行游戏RunGame();}}。
//五子棋小游戏纯C语言代码#include <stdio.h>#define N 14char state[N][N];void init(void);void printState(void);bool isWin(bool isBlack,int x,int y);bool isLevelWin(bool isBlack,int x,int y);bool isVerticalWin(bool isBlack,int x,int y);bool isLeftInclinedWin(bool isBlack,int x,int y);bool isRightObliqueWin(bool isBlack,int x,int y);bool isWin(bool isBlack,int x,int y)//是否有获胜{return isLevelWin(isBlack,x,y)||isVerticalWin(isBlack,x,y)||isLeftInclinedWin(isBlack,x,y)||isRightObliqueWin(isBlack,x,y);}bool isLevelWin(bool isBlack,int x,int y)//确定水平直线上是否有五子连珠{char c = isBlack ? '@':'O';int count;while(y>0 && state[x][y] == c){y--;}count =0;if(state[x][y] == c) count = 1;y++;while(y < N && state[x][y] == c){count++;if(count == 5){return true;}y++;}return false;}bool isVerticalWin(bool isBlack,int x,int y)//确定竖直直线是否有五子连珠{char c = isBlack ? '@':'O';int count;while(x>0 && state[x][y] == c){x--;}count =0;if(state[x][y] == c) count = 1;x++;while(x < N && state[x][y] == c){count++;if(count == 5){return true;}x++;}return false;}bool isLeftInclinedWin(bool isBlack,int x,int y)//确定左斜线是否有五子连珠{char c = isBlack ? '@':'O';int count;while(x>0 && y>0 && state[x][y] == c){y--;x--;}count =0;if(state[x][y] == c) count = 1;x++;y++;while(x < N && y < N && state[x][y] == c){count++;if(count == 5){return true;}x++;y++;}return false;}bool isRightObliqueWin(bool isBlack,int x,int y)//确定右斜线是否有五子连珠{char c = isBlack ? '@':'O';int count;while(x>0 && y<N && state[x][y] == c){y++;x--;}count =0;if(state[x][y] == c) count = 1;x++;y--;while(x < N && y >= 0 && state[x][y] == c){count++;if(count == 5){return true;}x++;y--;}return false;}void init(void)//开局初始化数组{int i,j;for(i=0;i<N;i++){for(j=0;j<N;j++){state[i][j] = '*';}}}void printState(void)//打印棋盘{int i,j;printf("%3c",' ');for(i=0;i<N;i++)printf("%3d",i);printf("\n");for(i=0;i<N;i++){printf("%3d",i);for(j=0;j<N;j++){printf("%3c",state[i][j]);}printf("\n");}}int main(void){int x,y;bool isBlack = true;init();printf("五子棋小游戏\n\n@代表黑子,0代表白子,*代表棋盘空白\n");printf("------------------------------------------------------\n");printState();while(1){printf("请%s 方走棋:\n",(isBlack?"黑":"白"));//请黑(白)方走棋的说明printf("输入所下位置坐标,如: 1-2\n");//走棋方法示例scanf("%d-%d",&x,&y);if(state[x][y]=='@' || state[x][y]=='O')//若此点已经存在棋子,则重新下一步棋在别处{printf("this position to have pieces\n");continue;}state[x][y] = (isBlack?'@':'O');//规定@代表黑子,0代表白子printState();//打印棋盘情况if(isWin(isBlack,x,y))//每下一步棋,判断一次是否有人获胜{printf("%s 方胜利\n",(isBlack?"黑":"白"));break;}isBlack = !isBlack;}}。
#include<stdio.h>int hen(char a[10][10]);int shu(char a[10][10]);int xie1(char a[10][10]);int xie2(char a[10][10]);int main(){char a[10][10];int x=0,y=0;for(y=0;y<10;y++)a[x][y]=y+'0';for(x=0,y=0;x<10;x++)a[x][y]=x+'0';for(x=1;x<10;x++)for(y=1;y<10;y++)a[x][y]='*';for(x=0;x<10;x++){for(y=0;y<10;y++)printf("%3c",a[x][y]);printf("\n");}printf("------------------------------\n");while(1){while(1){printf("请@号玩家下子\n");scanf("%d.%d",&x,&y);if(a[x][y]=='@'||a[x][y]=='O')printf("棋盘上已有棋子\n"); else{a[x][y]='@';break;}}for(x=0;x<10;x++){for(y=0;y<10;y++)printf("%3c",a[x][y]);printf("\n");}printf("------------------------------\n");if(hen(a)==1||shu(a)==1||xie1(a)==1||xie2(a)==1){printf("@玩家赢\n" );break;}while(1){printf("请O号玩家下子\n");scanf("%d.%d",&x,&y);if(a[x][y]=='@'||a[x][y]=='O')printf("棋盘上已有棋子\n"); else{a[x][y]='O';break;}}for(x=0;x<10;x++){for(y=0;y<10;y++)printf("%3c",a[x][y]);printf("\n");}printf("------------------------------\n");if(hen(a)==2||shu(a)==2||xie1(a)==2||xie2(a)==2){printf("O玩家赢了\n" );break;}}return 0;}int hen(char a[10][10])//横函数{int x,y,k=0,l=0;for(x=1;x<10;x++)for(y=1;y<10;y++){if(a[x][y]=='@')k=k+1;if(y==9)k=0;if(k==5)return 1;if(a[x][y]=='O')l=l+1;if(y==9)l=0;if(l==5)return 2;}}int shu(char a[10][10])//竖函数{int x,y,k=0,l=0;for(y=1;y<10;y++)for(x=1;x<10;x++){if(a[x][y]=='@')k=k+1;if(x==9)k=0;if(k==5)return 1;if(a[x][y]=='O')l=l+1;if(x==9)l=0;if(l==5)return 2;}}int xie1(char a[10][10])//斜函数{int x,y,m,k=0,l=0;for(m=1;m<10-4;m++)for(x=1,y=m;y<10;x++,y++){if(a[x][y]=='@')k=k+1;if(x==9)k=0;if(k==5)return 1;if(a[x][y]=='O')l=l+1;if(x==9)l=0;if(l==5)return 2;}}int xie2(char a[10][10])//斜函数{int x,y,n,k=0,l=0;for(n=1;n<10-4;n++)for(y=1,x=n;x<10;x++,y++){if(a[x][y]=='@')k=k+1;if(x==9)k=0;if(k==5)return 1;if(a[x][y]=='O')l=l+1;if(x==9)l=0;if(l==5)return 2;}}。
怎样做一个五子棋游戏?五子棋游戏算法比较简单,实现起来比较容易,适合初学者练习。
我这个五子棋游戏是自己花了2天的时间完成的,当时刚学mfc,想练一下手就做了这个游戏。
棋盘和棋子可以用GDI来实现,棋盘用GDI划线,基本上就是LineTo(x,y),MoveTo(x,y),一个棋盘就出来了。
具体代码如下在OnPaint()函数的else内加入如下代码CPaintDC dc(this);dc.SelectStockObject(BLACK_PEN);int i,j;for(i=60;i!=420;i=i+40){dc.MoveTo(i,60);dc.LineTo(i,380);}for(j=60;j!=420;j=j+40){dc.MoveTo(60,j);dc.LineTo(380,j);}一个9×9的棋盘就画好了。
至于如何画棋子,我思考了很长时间,贴图太麻烦,就用GDI来画圆,然后填充上不同的颜色,黑子、白子也就实现了。
这里的棋子不应该是一个独立的量,它有自己的区域,应该能判断鼠标是不是点击到了这个区域,当点击这个区域的时候是否应该显示,应该显示什么颜色的旗子……把这么多东西集合在一起,应该定义一个类,于是CQuyu这个类就出现了。
CQuyu有四个变量如下:int flag;CRect rect;int y;int x;x,y表示这个区域的中心,rect为以x,y为中心的边长为30的矩形,flag 用来表示该对象的状态(0:空白 1:黑子 2:白字)。
然后又定义了5个方法bool isWhite();//如果为白子,返回trueCRect getRect();//获得该对象对应的CRectbool isBlack();//如果为黑子,返回truebool isEmpty();//如果为空,返回truebool isOn(CPoint point);//如果该点出在该区域返回true,用来判断鼠标单击对应的区域在view类中定义了一个vector容器,(需要包含#include <vector>)vector<CQuyu> qy;在OnInitDialog()内对qy进行初始化int i,j;CQuyu q;for(i=60;i!=420;i=i+40){for(j=60;j!=420;j=j+40){q.x=i;q.y=j;qy.push_back(q);}}当鼠标单击的时候,判断单击的是哪一个区域,如果该区域为空则修改区域状态void CWuziqidlgDlg::OnLButtonDown(UINT nFlags, CPoint point) {// TODO: Add your message handler code here and/or call default int i;for(i=0;i!=qy.size();i++)if(qy[i].isOn(point)&&!over&&qy[i].isEmpty()){qy[i].flag=1;ison=1;break;}Invalidate();//引发重绘}在OnLButtonUp()中实现ai,电脑走棋void CWuziqidlgDlg::OnLButtonUp(UINT nFlags, CPoint point){// TODO: Add your message handler code here and/or call default//flag 1:black 2:white//color 1:white 2:blackint i,temp1,temp2,max1,max2;max1=0;max2=0;temp1=0;temp2=0;for(i=0;i!=qy.size();i++){if(qy[i].isEmpty()){qy[i].flag=2;if(getScore(1)>max1){temp1=getScore(1);max1=temp1;temp1=i;}qy[i].flag=1;if(getScore(2)>max2){temp2=getScore(2);max2=temp2;temp2=i;}qy[i].flag=0;}}if(ison==1&&!over){if(max1>=max2)qy[temp1].flag=2;elseqy[temp2].flag=2;}ison=0;if(!isWin())Invalidate();CDialog::OnLButtonUp(nFlags, point);}OnPaint()函数中实现绘制,每次先把棋盘画好,然后遍历各区域,如果不为空就绘制相应的棋子。
M F C程序设计MFC制作五子棋目录:1. 目的与要求……………………….….……..…….2. 主要功能………………………………………….3. 设计过程中的经验与教训……………………….4. 自己收获与不足……………………….………….5. 重要程序清单…………………………………….6. 窗口截图………………………………………….1.目的与要求利用已有的C++基础,结合对MFC的学习,进行窗口化设计。
由于MFC提供了MFCppWizard自动生成框架。
使得简单的编程更加简单,界面简洁。
这次用MFC设计了一个简单的五子棋游戏。
可以进行简单的双人对战。
目的在于更加熟悉MFC的使用来完成游戏的制作。
再此期间,搜集大量信息,以及函数的源代码。
不断进行整合,进行函数构造。
2主要功能MFC的窗口更适合小型游戏的界面。
五子棋可以说是再简单不过的小游戏了,不过其中确包含了大量的函数实现游戏的正常运转。
若要是游戏顺利进行,必须要有程序约束游戏规则。
因此本游戏要解决,棋子所放位置的判断,棋子颜色的区分,以及玩家的输赢。
解决这些问题,玩家便可以进行一场二人大战了。
本游戏可以让两个玩家在标准的五子棋盘上进行游戏,最先连成五子者,游戏可以显示哪一方获胜。
最终的结果可以保存入文件夹。
3. 设计过程中的经验与教训本次游戏设计,所遇到的阻力比较大。
经过多次返工。
多次函数未能定义或实现。
整个设计过程所学的东西也很多。
以五子棋游戏为例。
首先要知道其基本规则,并设法用不同的函数来解决规则的限定。
设计过程中常常会出现函数已经构造,却未加定义的情况。
做本游戏时,查看了大量资料。
在棋盘的画法上有所纠结。
是直接将棋盘背景图直接加入还是调用函数进行棋盘绘制都是要考虑的。
经过多次尝试,不断进行函数的调试和界面图标的设计。
最终完成此次实验。
虽然多次返工,虽然有一天从早上做到第二天凌晨5点,但最终的成功,使这些都变成浮云。
不断尝试,永不放弃,最终一定成功。
4. 自己收获与不足此次实验初期,本计划完成一个比较优秀的作品,但最终多种原因没有达到预期理想的界面。
首先谈谈收获,个人认为此次MFC 课程设计更适合简单游戏的设计。
五子棋的界面简单,相对规则也不多。
设计过程中,最大的收获要算程序的扩充,函数的调试。
其实MFC已给出框架,所要做的便是填充内容。
懂得了以位图的形式表示棋子,以cusor替换当前鼠标。
还有鼠标热点的设置。
在BOOL CMainFrame下构造函数以坐标的形式以改变棋盘大小。
同时构造出一系列画棋盘,判断鼠标,判断输赢等函数。
为函数添加数据成员并使其一一实现。
对相应菜单进行属性更改并进行消息映射,建立响应函数。
整个过程都得到了了解及应用。
同时,不足也很多,本游戏调用函数进行了棋盘绘制,使得界面过于简单。
由于时间,能力等问题,未能加入人工智能实现人机对战。
而且对于老师所给出的对话框的设计及应用也未能加入。
棋子的位图都是自己绘制,并不十分美观。
如果有充足的时间,我想这些一定会得到完善。
5. 重要程序清单构造函数//两个鼠标HCURSOR hcursorwhite;HCURSOR hcursorblack;//棋盘数组int wzq[19][19];// colorwhite TRUE时白棋下,否则黑棋下bool colorwhite;//棋子位图CBitmap m_bmblack;CBitmap m_bmwhite;//保存文件void Save();//检查是否结束void over(CPoint point);//鼠标操作afx_msg void OnLButtonUp(UINT nFlags, CPoint point);//鼠标图形更换afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);//菜单的开始afx_msg void OnStart();//菜单的保存afx_msg void OnSave();//菜单的打开afx_msg void OnOpen();窗口设计BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs){if( !CFrameWnd::PreCreateWindow(cs) )return FALSE;// TODO: Modify the Window class or styles here by modifying// the CREATESTRUCT cscs.dwExStyle=cs.dwExStyle|WS_EX_TOPMOST; //cs.style=WS_SYSMENU|WS_OVERLAPPED|WS_MINIMIZEBOX;//;//设置窗口大小:400*340cs.cx=450;cs.cy=500;return TRUE;棋盘与棋子的绘制void CMy3_1View::OnDraw(CDC* pDC){CMy3_1Doc* pDoc = GetDocument();ASSERT_V ALID(pDoc);// TODO: add draw code for native data here//画背景CBrush mybrush1;mybrush1.CreateSolidBrush(RGB(192,192,192));CRect myrect1(0,0,1200,800);pDC->FillRect(myrect1,&mybrush1);//画棋盘框线CPen mypen;CPen*myoldPen;mypen.CreatePen(PS_SOLID,1,RGB(0,0,0));myoldPen=pDC->SelectObject(&mypen);for(int i=0;i<19;i++){pDC->MoveTo(40,40+i*20);pDC->LineTo(400,40+i*20);pDC->MoveTo(40+i*20,40);pDC->LineTo(40+i*20,400);}//重画时显示存在的棋子CDC Dc;if(Dc.CreateCompatibleDC(pDC)==FALSE)AfxMessageBox("Can't create DC");for(int n=0;n<19;n++)for(int m=0;m<19;m++)if(wzq[n][m]==1){//显示白棋Dc.SelectObject(m_bmwhite);pDC->BitBlt(n*20+32,m*20+32,160,160,&Dc,0,0,SRCCOPY);}else if(wzq[n][m]==-1){//显示黑棋Dc.SelectObject(m_bmblack);pDC->BitBlt(n*20+32,m*20+32,160,160,&Dc,0,0,SRCCOPY);}}}设置鼠标:BOOL CMy3_1View::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message){// TODO: Add your message handler code here and/or call defaultif(nHitTest==HTCLIENT){//白棋下,显示白棋鼠标if(colorwhite){//调用主框架里面的状态栏CMainFrame*pFrm=(CMainFrame*)AfxGetApp()->m_pMainWnd;CStatusBar*pStatus=&pFrm->m_wndStatusBar;if(pStatus){p Status->GetStatusBarCtrl().SetIcon(0,AfxGetApp()->LoadIcon(IDI_WHITE));pStatus->SetPaneText(0,"白棋下");}SetCursor(hcursorwhite);}//显示黑棋鼠标else{SetCursor(hcursorblack);CMainFrame*pFrm=(CMainFrame*)AfxGetApp()->m_pMainWnd;CStatusBar*pStatus=&pFrm->m_wndStatusBar;if(pStatus){//显示图像p Status->GetStatusBarCtrl().SetIcon(0,AfxGetApp()->LoadIcon(IDI_BLACK));//显示文字pStatus->SetPaneText(0,"黑棋下");}}return 1;}return CView::OnSetCursor(pWnd, nHitTest, message);}判断输赢void CMy3_1View::over(CPoint point){//获取鼠标指向数组位置,即中心位置int x=(point.x-30)/20;int y=(point.y-30)/20;//计算开始判断的坐标xx,yyint xx,yy;if(x<4)xx=0;elsexx=x-4;if(y<4)yy=0;elseyy=y-4;int i,j,a;//横向判断for(i=xx;i<15;i++){a=0;for(j=i;j<i+5;j++){a=a+wzq[j][y];//五个都是白棋if(a==5){AfxMessageBox("白棋胜!");//重新开始OnStart();return;}//五个都是黑棋if(a==-5){AfxMessageBox("黑棋胜!");OnStart();return;}}}//竖向判断for(i=yy;i<15;i++){a=0;for(j=i;j<i+5;j++){a=a+wzq[x][j];if(a==5){AfxMessageBox("白棋胜!");OnStart();return;}if(a==-5){AfxMessageBox("黑棋胜!");OnStart();return;}}}//向右下角//判断起点位置if(x<y){if(xx==0)yy=y-x;}else{if(yy==0)xx=x-y;}//参数over=1时退出循环int over=0;do{a=0;for(i=0;i<5;i++){if((xx+i)<19||(yy+i)<19){a=a+wzq[xx+i][yy+i];if(a==5){AfxMessageBox("白棋胜!");OnStart();return;}if(a==-5){AfxMessageBox("黑棋胜!");OnStart();return;}}//到了边界elseover=1;}xx+=1;yy+=1;}while(over==0);//向左下角if(y>(18-x)){if(x>13){yy=y-(18-x);xx=18;}else{yy=y-4;xx=x+4;}}else{if(y<5){xx=x+y;yy=0;}else{yy=y-4;xx=x+4;}}over=0;do{a=0;for(i=0;i<5;i++){if((xx-i)>=0||(yy+i)<19){a=a+wzq[xx-i][yy+i];if(a==5){AfxMessageBox("白棋胜!");OnStart();return;}if(a==-5){AfxMessageBox("黑棋胜!");OnStart();return;}}//到了边界elseover=1;}xx-=1;yy+=1;}while(over==0);}文件保存void CMy3_1View::OnSave(){// TODO: Add your command handler code here//设置保存的文件,后缀名wzqCFileDialogdlg(FALSE,"wzq",NULL,OFN_HIDEREADONL Y|OFN_OVERWRITEPROMPT,"(*.WZQ)|*.w zq|All Files|*.*||",this);//如果公共类对话框为确定if(dlg.DoModal()==IDOK)//获取文件名dlg.GetFileName();//否则,退出elsereturn;//字符串变量CString str;int i,j;CStdioFile file;//如果有问题,退出if(file.Open(dlg.GetFileName(),CFile::modeCreate|CFile::modeWrite|CFile::typeText)= =0){AfxMessageBox("save error!");return;}//循环把棋盘数组的值写进文件for(i=0;i<19;i++)for(j=0;j<19;j++){if(wzq[i][j]==-1)file.WriteString("-1\n");if(wzq[i][j]==0)file.WriteString("0\n");if(wzq[i][j]==1)file.WriteString("1\n");}//保存当前下棋颜色if(colorwhite==true)file.WriteString("1\n");elsefile.WriteString("0\n");//关闭文件file.Close();}读取文件:读文件就是把我们以前保存的文件打开,读取当前打开文件的内容,并给数组赋值使和文件内容相同,然后可以继续进行游戏。