五子棋人机交互

类别:VC语言 点击:0 评论:0 推荐:
五子棋人机交互

程序分两部分:1。核心程序 2。windows图形界面程序 此处只介绍核心程序部分。下面,我们边看边侃。 //========定义文件部分============================= #define MAX_LENGTH 19 //棋盘格数 #define COMPUTER 1 //计算机棋子 #define PLAYER 2 //玩家棋子 int qp[MAX_LENGTH][MAX_LENGTH]; //定义棋盘 int iswin; //输赢标记,1=计算机胜,2=玩家胜,0=未分胜负; #define RandInt(n) (rand()%n) //随机数宏 struct LIST { int id; struct LIST *next; }*PList=NULL,*CList=NULL; //定义链表,Plist为玩家棋局链表指针,用于阻击,Clist为计算机棋局链表指针,用于攻击 //=========核心程序代码部分========================= //本函数将数据add添加到链表中,并将数据按从大到小排序 //add低位为棋盘位置,高位代表该位置在当前棋局中的优先级 static int AddList(struct LIST **List,int add) { struct LIST *tmp=*List; struct LIST **temp=List; int atemp=add>>16; int id; struct LIST *newlist=malloc(sizeof(*newlist)); if(!newlist) return 1; while(tmp) { id=(tmp->id)>>16; if(id<=atemp) break; if(id>atemp) { temp=&(tmp->next); tmp=tmp->next; } } newlist->id=add; newlist->next=tmp; *temp=newlist; return 0; } //函数获得指定链中最大优先级的值 static int GetMax(struct LIST *List) { if(List) return (List->id>>16); return 0; } //函数获得指定链中的链首数据 static int GetLast(struct LIST **List) { if(*List) { int ret; struct LIST *temp; ret=((*List)->id&0xffff);//取低字节棋盘位置数据 temp=*List; *List=(*List)->next; free(temp); return ret; } return 0; } #define DestroyList(l) while(GetLast(&l)) //宏——销毁链表 //函数探测参数tmp指定的棋盘位置的优先级并加入相应的链表中 //凡进入该函数扫描的点,皆为棋盘上的空位置。我们将在此处分析该位置在棋局中的地位。 //tmp=y*MAX_LENGTH+x static int AddTo_List(int tmp) { int temp; int py,px; py=tmp/MAX_LENGTH; px=tmp%MAX_LENGTH; //探测计算机在此位置的优先级 qp[py][px]=COMPUTER; temp=scan(px,py,0);//最后一个参数必须为0,否则将进入死循环。 AddList(&CList,(temp<<16)+tmp); //探测玩家在此位置的优先级 qp[py][px]=PLAYER; temp=scan(px,py,0);//同上。 AddList(&PList,(temp<<16)+tmp); qp[py][px]=0;//恢复空子状态。 return 0; } //函数对指定的棋盘位置进行格式化全方位扫描,并返回该位置在棋局中的优先级 //进行格式化扫描,可以减少扫描的冗余度,提高扫描效率。这对于大棋盘,如本例的19*19 尤为适用。 //mode控制扫描方式,0=试验性扫描,不将扫描结果加入链表。1=实战性扫描,将扫描结 果加入链表。程序可利用链表中的数据,进行下一步棋的决策。 //px,py在循环中反复使用,我们为其加上const标记,防止不必要的麻烦。 static int scan(const int px,const int py,int mode) { register int i; int play=qp[py][px];//获得该位置棋子 int ret=0;rtemp=0;//返回值 int temp[4]; int base; base=RandInt(8);//生成随机数,使用不同的起点,使棋局具有一定的随机性 //对该棋子八个方向进行扫描 for(i=0;i<8;i++) { int x=px; int y=py; int side=0;//边界标记 register j; switch((base+i)%8) { case 0://x-- { //格式化,首先定位到第一个不与play相同的位置。 //这样,在此方向上,我们便可以只考虑四格棋盘位置,大大减少了不必要的开销。 do { x--; }while(x>=0&&qp[y][x]==play); //该方向前面没有充足的位置,置标记位为1。这样,我们可以略去无效探测。 if(x+5>MAX_LENGTH) { side=1; } else { x+=2;//沿该方向向前,跳过第一个与play相等的位置,对前方四个位置进行纪录 for(j=0;j<4;j++) { temp[j]=(MAX_LENGTH*y+x);//将棋盘位置合成整型数据保存 x++; } } break; } case 1://x--;y--; { do { x--; y--; }while(x>=0&&y>=0&&qp[y][x]==play); if(x+5>MAX_LENGTH||y+5>MAX_LENGTH) { side=1; } else { x+=2; y+=2; for(j=0;j<4;j++) { temp[j]=(MAX_LENGTH*y+x); x++; y++; } } break; } case 2://y--; { do { y--; }while(y>=0&&qp[y][x]==play); if(y+5>MAX_LENGTH) { side=1; } else { y+=2; for(j=0;j<4;j++) { temp[j]=(MAX_LENGTH*y+x); y++; } } break; } case 3://x--;y++; { do { x--; y++; }while(x>=0&&y<MAX_LENGTH&&qp[y][x]==play); if(x+5>MAX_LENGTH||y-5<0) { side=1; } else { x+=2; y-=2; for(j=0;j<4;j++) { temp[j]=(MAX_LENGTH*y+x); x++; y--; } } break; } case 4://x++; { do { x++; }while(x<MAX_LENGTH&&qp[y][x]==play); if(x-5<0) { side=1; } else { x-=2; for(j=0;j<4;j++) { temp[j]=(MAX_LENGTH*y+x); x--; } } break; } case 5://x++;y--; { do { x++; y--; }while(x<MAX_LENGTH&&y>=0&&qp[y][x]==play); if(x-5<0||y+5>MAX_LENGTH) { side=1; } else { x-=2; y+=2; for(j=0;j<4;j++) { temp[j]=(MAX_LENGTH*y+x); x--; y++; } } break; } case 6://x++;y++; { do { x++; y++; }while(x<MAX_LENGTH&&y<MAX_LENGTH&&qp[y][x]==play); if(x-5<0||y-5<0) { side=1; } else { x-=2; y-=2; for(j=0;j<4;j++) { temp[j]=(MAX_LENGTH*y+x); x--; y--; } } break; } case 7://y++; { do { y++; }while(y<MAX_LENGTH&&qp[y][x]==play); if(y-5<0) { side=1; } else { y-=2; for(j=0;j<4;j++) { temp[j]=(MAX_LENGTH*y+x); y--; } } break; } } if(!side) { //该部分是决定优先级的关键部分,本例只使用了简单的优先级决定方案,可以通过修改该部分使程序具有更高的智能。 int t=0; int k[4]={8,4,2,1}; int kt[16]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}; //对纪录的棋盘位置进行检测 for(j=0;j<4;j++) { int jx=temp[j]%MAX_LENGTH; int jy=temp[j]/MAX_LENGTH; int p=qp[jy][jx]; if(p==play) t+=k[j]; else if(p==0)//可利用位置 { if(mode) AddTo_List(temp[j]);//对可利用位置进行探测纪录 } else//存在阻隔 { t--;//此处有可能使t=-1,因为t用于数组下标,所以我们必须将其排除。 if(t<0) t=0; break; } } if(t==0xf&&mode)//若五子连成一线,返回零 return 0;     if(ret<kt[t])
    {
     ret=kt[t];
     if(ret>rtemp)
     {
      int t=ret;
      ret=rtemp;
      rtemp=t;
     }
    }
   }

 }
 return (ret+rtemp);//当前局势
} //初始化棋盘 void initqp(void) { register int i; register int j; for(i=0;i<MAX_LENGTH;i++) for(j=0;j<MAX_LENGTH;j++) qp[i][j]=0; iswin=0; srand(time(NULL));//初始化随机生成器 } //主函数,检测玩家所走位置,返回计算机所走位置 //px,py代表玩家棋子位置。 int five(int px,int py) { struct LIST **list; int tmp; if(qp[py][px]!=0)//该位置已存在棋子 { return -1; } //对玩家所走棋子进行扫描 qp[py][px]=PLAYER; if(!scan(px,py,1)) { //玩家胜 DestroyList(PList); DestroyList(CList); iswin=PLAYER; return 0; } if(GetMax(PList)>GetMax(CList))//确定攻击性 list=&PList;//防御 else list=&CList;//攻击 while(tmp=GetLast(list))//获取最大优先级的棋盘位置 { px=tmp%MAX_LENGTH; py=tmp/MAX_LENGTH; if(qp[py][px]!=0)//该位置不为空则继续循环 { if(GetMax(PList)>GetMax(CList))//重新确定攻击性 list=&PList; else list=&CList; continue; } break; } if(!tmp) //在链表中未找到数据则生成随机数据 { do { px=RandInt(MAX_LENGTH); py=RandInt(MAX_LENGTH); }while(qp[py][px]!=0); } //计算机走子 qp[py][px]=COMPUTER; if(!scan(px,py,1)) { //计算机胜 DestroyList(PList); DestroyList(CList); iswin=COMPUTER; } return ((py*MAX_LENGTH)+px);//返回走子位置 } 核心程序部分就这么多,图形界面部分只需调用函数initqp()初始化棋盘,然后不断调用函数five(int px,int py)即可。

本文地址:http://com.8s8s.com/it/it1491.htm