正文

五子棋(人机对战)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();
}

阅读(3010) | 评论(0)


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

评论

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