欢迎访问:常州市武进区嘉泽中心小学网站 !今天是:
栏目列表
您现在的位置是:首页>>教师>>计算机技术>>程序设计>>杂项>>文章内容
五子棋人机交互
发布时间:2008-11-20   点击:   来源:本站原创   录入者:佚名
 

五子棋人机交互

程序分两部分: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)即可。

附件:
    关闭窗口
    打印文档
    账号登录
    保持登录 忘记密码?
    账号与武进教师培训平台同步