正文

五子棋(人机对战)2007-10-23 22:53:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/vfdff/30341.html

分享到:

/***************************************************************************************\          modify at  2006.3.28\***************************************************************************************/#include <graphics.h>#include <stdio.h>#include <malloc.h>#include <time.h>#include <math.h>#include <stdlib.h> #include <mousea1.h> #define  MAX  15#define  OFFSET  8      /* 14*14=196<2^8-1=255 偏移8位足够,而优先级最大也是16 */#define  PAN_X 125      /*棋盘初始位置,左上角坐标(125,75) */#define  PAN_Y 75 #define  COMPUTER  1    /*计算机棋子 */#define  PLAYER    2    /*玩家棋子   */int qp[MAX][MAX];       /*定义棋盘   */int iswin;              /*输赢标记,1=计算机胜,2=玩家胜,0=未分胜负;*/int key; struct LIST {  int id;  struct LIST *next;}*PList=NULL,*CList=NULL;   /*定义链表,Plist为玩家棋局链表指针,用于阻击,Clist为计算机棋局链表指针,用于攻击  */ void * mouse_buf;MOUSE mouse;void ResumeGraphics(int x,int y,void *p);bool GetBuf(int x,int y,int xx,int yy,void *p);void qizi(int px,int py,int color);void kuang(int px,int py,int color); static int black_x=MAX,black_y=MAX; /* 预先置初始位置,在画框外 */ static int AddList(struct LIST **List,int add){  struct LIST *tmp=*List, **temp=List;  int atemp=add>>OFFSET;  int id;  struct LIST *newlist=malloc(sizeof(*newlist));  if(!newlist) return 1;  while(tmp)  {    id=(tmp->id)>>OFFSET;    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>>OFFSET); return 0; } static int GetLast(struct LIST **List)  /*函数获得指定链中的链首数据  */{  if(*List) {    int ret;    struct LIST *temp;    ret=((*List)->id& 0xff);            /* 取低字节棋盘位置数据 , 0xff与OFFSET位数一致 */    temp=*List;                         /* 记住需要销毁的结点,使用的结点销毁  */    *List=(*List)->next;    free(temp);    return ret;  }  return 0;}#define DestroyList(L)  while(GetLast(&L))  /*宏——销毁链表 *//*函数探测参数tmp指定的棋盘位置的优先级并加入相应的链表中   *//*凡进入该函数扫描的点,皆为棋盘上的空位置。我们将在此处分析该位置在棋局中的地位。*/ static int AddTo_List(int tmp){  int temp,py,px;  py=tmp/MAX; px=tmp%MAX;               /*探测计算机在此位置的优先级 ,tmp=y*MAX+x  */  qp[py][px]=COMPUTER;  temp=scan(px,py,0);                   /*最后一个参数必须为0,否则将进入死循环。  */  AddList(&CList,(temp<<OFFSET)+tmp);   /*探测玩家在此位置的优先级  */  qp[py][px]=PLAYER;  temp=scan(px,py,0);                   /*同上。 */  AddList(&PList,(temp<<OFFSET)+tmp);  qp[py][px]=0;                         /*恢复空子状态。  */  return 0;} 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=random(8);         /* 生成随机数,使用不同的起点,使棋局具有一定的随机性 */    for(i=0;i<8;i++)        /*对该棋子八个方向进行扫描   */    {        int x=px,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) side=1 ;                else {                    x+=2 ;  /*沿该方向向前,跳过第一个与play相等的位置,对前方四个位置进行纪录 */                    for(j=0;j<4;j++) { temp[j]=(MAX*y+x);  x++; } /*将棋盘位置合成整型数据保存  */                } break ;            }            case 1 :{       /*x--;y--; */                do  { x--;  y--; }                while(x>=0&&y>=0&&qp[y][x]==play);                if(x+5>MAX||y+5>MAX) side=1 ;                else  {                    x+=2 ; y+=2 ;                    for(j=0;j<4;j++) { temp[j]=(MAX*y+x); x++;  y++;  }                } break ;            }            case 2 :{       /*y--;  */                do  {y--; }                while(y>=0&&qp[y][x]==play);                if(y+5>MAX) side=1 ;                else  {                    y+=2 ;                    for(j=0;j<4;j++) { temp[j]=(MAX*y+x); y++; }                } break ;            }            case 3 :{       /*x--;y++; */                do  { x--; y++; }                while(x>=0&&y<MAX&&qp[y][x]==play);                if(x+5>MAX||y-5<0)side=1 ;                else  {                    x+=2 ; y-=2 ;                    for(j=0;j<4;j++) {  temp[j]=(MAX*y+x);  x++;  y--; }                } break ;            }            case 4 :{       /*x++;   */                do  { x++; }                while(x<MAX&&qp[y][x]==play);                if(x-5<0)side=1 ;                else  {                    x-=2 ;                    for(j=0;j<4;j++) { temp[j]=(MAX*y+x);  x--; }                }  break ;            }            case 5 :{       /*x++;y--;   */                do  { x++; y--; }                while(x<MAX&&y>=0&&qp[y][x]==play);                if(x-5<0||y+5>MAX)side=1 ;                else  {                    x-=2 ; y+=2 ;                    for(j=0;j<4;j++) { temp[j]=(MAX*y+x);  x--;  y++; }                } break ;            }            case 6 :{       /*x++;y++;  */                do  { x++; y++; }                while(x<MAX&&y<MAX&&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*y+x); x--;  y--; }                } break ;            }            case 7 : {      /*y++;  */                do  { y++; }                while(y<MAX&&qp[y][x]==play);                if(y-5<0)side=1 ;                else  {                    y-=2 ;                    for(j=0;j<4;j++) { temp[j]=(MAX*y+x); y--; }                } break ;            }        }        if(!side)        { /*该部分是决定优先级的关键部分,本例只使用了简单的优先级决定方案,可以通过修改该部分使程序具有更高的智能。*/            int t=0 ;            int k[4]= { 8,4,2,1 };  /* 可以把mode=0,1两种情况分开讨论kt[mode][16]*/            int kt[16]= { 1,2,4,3,5,6,7,13,9,10,11,12,8,14,15,16} ;/* 关键顺序此顺序,对不同情况着子顺序 */            for(j=0;j<4;j++)        /*对纪录的棋盘位置进行检测   */            {                int jx=temp[j]%MAX,jy=temp[j]/MAX ;                int p=qp[jy][jx];                if(p==play) t += k[j];                else if(p==0) {     /* 可利用位置 */                    if(mode) AddTo_List(temp[j]);   /*对可利用位置进行探测纪录 */                }                               /* scan(px,py,0)时可能取道t=15 */                else {  t=0;break ; }    /*存在阻隔,则不能连成五子 t=t>0?--t:0 */            }            if(t==0x0f && mode) return 0 ;           /* 若五子连成一线,返回零 */            if(ret<kt[t]) {                ret=kt[t];                if(ret>rtemp) { int t=ret ; ret=rtemp ; rtemp=t ; } /* rtemp记录八向中最大的权 */            }        }    }/* 对mode= 1此返回植无意义 */    return(rtemp);      /*当前局势, 返回0就成一下 return(ret+rtemp),加ret为增加随机性??  */}void initqp(void)       /*初始化棋盘  */{  register int i, j;  for(i=0;i<MAX;i++)     for(j=0;j<MAX;j++) qp[i][j]=0;  iswin=0;  randomize();          /* 初始化随机生成器 */}int five(int px,int py) /* 主函数,检测玩家所走位置及附近的权值,返回计算机所走位置 */{  struct LIST **list;  int tmp;  if(qp[py][px]!=0)   return -1; /*该位置已存在棋子, px,py代表玩家棋子位置? */  qp[py][px]=PLAYER;             /*对玩家所走棋子进行扫描 */  ResumeGraphics(mouse.oldx, mouse.oldy, mouse_buf);  qizi(px,py,RED);  kuang(px,py,BLACK);  /*重新画一次,使框图象完整*/          GetBuf(mouse.x, mouse.y, mouse.x + 10, mouse.y + 16, mouse_buf);   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; py=tmp/MAX;    if(qp[py][px]!=0)                            /* 该位置不为空则继续循环  */    {      if(GetMax(PList)>GetMax(CList))  list=&PList;        /* 重新确定攻击性 */      else list=&CList;      continue;    } break;  }  if(!tmp){                     /*在链表中未找到数据,tmp=0 则生成随机数据 */    do { px=random(MAX); py=random(MAX); }    while(qp[py][px]!=0); tmp=0;  }  qp[py][px]=COMPUTER;                          /*计算机走子  */  qizi(px,py,YELLOW);  if(!scan(px,py,1)) { DestroyList(PList); DestroyList(CList); iswin=COMPUTER;     return 0;  }  /*计算机胜 */  return ((py*MAX)+px);                         /*返回走子位置  */}void kongpan(){    int i,j ;    setbkcolor(BLACK);    bar3d(PAN_X-30,PAN_Y-30,PAN_X+380,PAN_Y+380,7,5);    setpalette(WHITE,GREEN);    setcolor(YELLOW);    for(i=0;i<MAX;i++)    {        line(PAN_X+25*i,PAN_Y,PAN_X+25*i,PAN_Y+(MAX-1)*25);        line(PAN_X,PAN_Y+25*i,PAN_X+(MAX-1)*25,PAN_Y+25*i);    }    for(i=0;i<4;i++)    {        circle(PAN_X+175,PAN_Y+175,i);        circle(PAN_X+75,PAN_Y+75,i);        circle(PAN_X+275,PAN_Y+275,i);        circle(PAN_X+75,PAN_Y+275,i);        circle(PAN_X+275,PAN_Y+75,i);    }} void qizi(int px,int py,int color){    unsigned char p;    setcolor(color);    for(p=0;p<12;p++)      circle(PAN_X+px*25,PAN_Y+py*25,p);}void kuang(int px,int py,int color){    setcolor(color);    rectangle((PAN_X+px*25)-12,(PAN_Y+py*25)-12,(PAN_X+px*25)+12,(PAN_Y+py*25)+12);}     void ResumeGraphics(int x,int y,void *p){    putimage(x,y,p,COPY_PUT);}bool GetBuf(int x,int y,int xx,int yy,void *p)   /*给图形指针赋值*/{    if(!p) return 0;    getimage(x,y,xx,yy,p);    return 1;}void Limit(int *x,int *y){    if((*x)>PAN_X-25&(*y)>PAN_Y-25&(*x)<PAN_X+(MAX-1)*25&(*y)<PAN_Y+(MAX-1)*25) return ; /* 在范围之内*/    if((*x)<PAN_X-25) (*x)=PAN_X-25 ;    if((*y)<PAN_Y-25) (*y)=PAN_Y-25 ;    if((*x)>PAN_X+(MAX-1)*25) (*x)=PAN_X+(MAX-1)*25 ;    if((*y)>PAN_Y+(MAX-1)*25) (*y)=PAN_Y+(MAX-1)*25 ;}bool MouseControl(){    static int FIRST = 0;     if(!FIRST)    {        Get_xy(&mouse);        mouse.oldx = mouse.x;        mouse.oldy = mouse.y;        GetBuf(mouse.oldx,mouse.oldy,mouse.oldx+10,mouse.oldy+16,mouse_buf);        Shape[0].Draw(mouse.x, mouse.y);        FIRST = 1;    }    mouse.but = Which_pressed(); /* 无此句鼠标无反应 */    if( !mouse.but)  /* 没有点鼠标时 */    {        Get_xy(&mouse);         Limit(&mouse.x,&mouse.y);/* 使在框中运动 */         if(mouse.x != mouse.oldx | mouse.y != mouse.oldy)        {            ResumeGraphics(mouse.oldx, mouse.oldy, mouse_buf);            mouse.oldx = mouse.x;            mouse.oldy = mouse.y;            GetBuf(mouse.x, mouse.y, mouse.x + 10, mouse.y + 16, mouse_buf);            Shape[0].Draw(mouse.x, mouse.y);            return 1;        }        else return 0;    }    else    {        if(FIRST==1)        {            kuang(MAX/2,MAX/2,WHITE);            FIRST = 2;        }        SetMouseXY(mouse.oldx,mouse.oldy);        kuang(black_x,black_y,WHITE);        black_x=(mouse.oldx-PAN_X+12)/25; black_y= (mouse.oldy-PAN_Y+12)/25;         kuang(black_x,black_y,BLACK);        return 1;    }} void xiangying(){    kuang(MAX/2,MAX/2,BLACK);    while(bioskey(1)==0)    {        MouseControl(); delay(20);        if(pow(mouse.oldx-PAN_X-black_x*25,2)+pow(mouse.oldy-PAN_Y-black_y*25,2) <146 )            if(!five(black_x,black_y))            {               qizi(black_x,black_y,RED);               GetBuf(mouse.oldx, mouse.oldy, mouse.oldx + 10, mouse.oldy + 16, mouse_buf);               return;            }    }}void InitGraphicsBuf(int x,int y,int xx,int yy,void **p){    *p=malloc(imagesize(x,y,xx,yy));}bool init(){    int driver = VGA, drivermode = VGAHI;    initgraph(&driver, &drivermode, "");    if(graphresult() != 0)    {        printf("can't initgraph"); return FALSE;    }    InitGraphicsBuf(0,0,10,16,&mouse_buf);    cleardevice();    return TRUE;}main(){    init();     settextstyle(DEFAULT_FONT,HORIZ_DIR,2);    initqp();    kongpan();    xiangying();    printf("came over \nwinner:%d(COMPUTER:1,PLAYER:2)",iswin);    getch();    closegraph();}

阅读(3129) | 评论(0)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

暂无评论
您需要登录后才能评论,请 登录 或者 注册