新书推介:《语义网技术体系》
作者:瞿裕忠,胡伟,程龚
   XML论坛     W3CHINA.ORG讨论区     计算机科学论坛     SOAChina论坛     Blog     开放翻译计划     新浪微博  
 
  • 首页
  • 登录
  • 注册
  • 软件下载
  • 资料下载
  • 核心成员
  • 帮助
  •   Add to Google

    >> 本版讨论高级C/C++编程、代码重构(Refactoring)、极限编程(XP)、泛型编程等话题
    [返回] 计算机科学论坛计算机技术与应用『 C/C++编程思想 』 → 五子棋的核心算法 查看新帖用户列表

      发表一个新主题  发表一个新投票  回复主题  (订阅本版) 您是本帖的第 3873 个阅读者浏览上一篇主题  刷新本主题   树形显示贴子 浏览下一篇主题
     * 贴子主题: 五子棋的核心算法 举报  打印  推荐  IE收藏夹 
       本主题类别:     
     葛靖青001 美女呀,离线,快来找我吧!水瓶座1984-2-14
      
      
      等级:大三(研究MFC有点眉目了!)
      文章:168
      积分:595
      门派:XML.ORG.CN
      注册:2010/11/2

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给葛靖青001发送一个短消息 把葛靖青001加入好友 查看葛靖青001的个人资料 搜索葛靖青001在『 C/C++编程思想 』的所有贴子 点击这里发送电邮给葛靖青001 引用回复这个贴子 回复这个贴子 查看葛靖青001的博客楼主
    发贴心情 五子棋的核心算法

    一、相关的数据结构

      关于盘面情况的表示,以链表形式表示当前盘面的情况,目的是可以允许用户进行悔棋、回退等操作。

      CList StepList;

      其中Step结构的表示为:

      struct Step

      {

      int  m; //m,n表示两个坐标值

      int  n;

      char side; //side表示下子方

      };

      以数组形式保存当前盘面的情况,

      目的是为了在显示当前盘面情况时使用:

      char FiveArea[FIVE_MAX_LINE][FIVE_MAX_LINE];

      其中FIVE_MAX_LINE表示盘面最大的行数。

      同时由于需要在递归搜索的过程中考虑时间和空间有效性,只找出就当前情况来说相对比较好的几个盘面,而不是对所有的可下子的位置都进行搜索,这里用变量CountList来表示当前搜索中可以选择的所有新的盘面情况对象的集合:

      CList CountList;

      其中类CBoardSituiton为:

      class CBoardSituation

      {

      CList  StepList; //每一步的列表

      char FiveArea[FIVE_MAX_LINE][FIVE_MAX_LINE];

      struct Step machineStep;    //机器所下的那一步

      double value;  //该种盘面状态所得到的分数

      }

      二、评分规则

      对于下子的重要性评分,需要从六个位置来考虑当前棋局的情况,分别为:-,¦,/,\,//,\
      实际上需要考虑在这六个位置上某一方所形成的子的布局的情况,对于在还没有子的地方落子以后的当前局面的评分,主要是为了说明在这个地方下子的重要性程度,设定了一个简单的规则来表示当前棋面对机器方的分数。

      基本的规则如下:

      判断是否能成5, 如果是机器方的话给予100000分,如果是人方的话给予-100000 分;

      判断是否能成活4或者是双死4或者是死4活3,如果是机器方的话给予10000分,如果是人方的话给予-10000分;

      判断是否已成双活3,如果是机器方的话给予5000分,如果是人方的话给予-5000 分;

      判断是否成死3活3,如果是机器方的话给予1000分,如果是人方的话给予-1000 分;

      判断是否能成死4,如果是机器方的话给予500分,如果是人方的话给予-500分;

      判断是否能成单活3,如果是机器方的话给予200分,如果是人方的话给予-200分;

      判断是否已成双活2,如果是机器方的话给予100分,如果是人方的话给予-100分;

      判断是否能成死3,如果是机器方的话给予50分,如果是人方的话给予-50分;

      判断是否能成双活2,如果是机器方的话给予10分,如果是人方的话给予-10分;

      判断是否能成活2,如果是机器方的话给予5分,如果是人方的话给予-5分;

      判断是否能成死2,如果是机器方的话给予3分,如果是人方的话给予-3分。

      实际上对当前的局面按照上面的规则的顺序进行比较,如果满足某一条规则的话,就给该局面打分并保存,然后退出规则的匹配。注意这里的规则是根据一般的下棋规律的一个总结,在实际运行的时候,用户可以添加规则和对评分机制加以修正。
    三、胜负判断

      实际上,是根据当前最后一个落子的情况来判断胜负的。实际上需要从四个位置判断,以该子为出发点的水平,竖直和两条分别为 45度角和135度角的线,目的是看在这四个方向是否最后落子的一方构成连续五个的棋子,如果是的话,就表示该盘棋局已经分出胜负。具体见下面的图示:

      四、搜索算法实现描述

      注意下面的核心的算法中的变量currentBoardSituation,表示当前机器最新的盘面情况, CountList表示第一层子节点可以选择的较好的盘面的集合。核心的算法如下:

      void MainDealFunction()

      {

      value=-MAXINT; //对初始根节点的value赋值

      CalSeveralGoodPlace(currentBoardSituation,CountList);

      //该函数是根据当前的盘面情况来比较得到比较好的可以考虑的几个盘面的情况,可以根据实际的得分情况选取分数比较高的几个盘面,也就是说在第一层节点选择的时候采用贪婪算法,直接找出相对分数比较高的几个形成第一层节点,目的是为了提高搜索速度和防止堆栈溢出。

      pos=CountList.GetHeadPosition();

      CBoardSituation* pBoard;

      for(i=0;ivalue=Search(pBoard,min,value,0);

      Value=Select(value,pBoard->value,max);

      //取value和pBoard->value中大的赋给根节点

      }

      for(i=0;ivalue)

      //找出那一个得到最高分的盘面

      {

      currentBoardSituation=pBoard;

      PlayerMode=min; //当前下子方改为人

      Break;

      }

      }

      其中对于Search函数的表示如下:实际上核心的算法是一个剪枝过程,其中在这个搜索过程中相关的四个参数为:(1)当前棋局情况;(2)当前的下子方,可以是机器(max)或者是人(min);(3)父节点的值oldValue;(4)当前的搜索深度depth。

      double Search(CBoardSituation&

      board,int mode,double oldvalue,int depth)

      {

      CList  m_DeepList;

      if(deptholdvalue))==    TRUE)

      {

      if(mode==max)

      value=select(value,search(successor

      Board,min,value,depth+1),max);

      else

      value=select(value,search(successor

      Board,max,value,depth+1),min);

      }

      return value;

      }

      else

      {

      if ( goal(board)<>0)

      //这里goal(board)<>0表示已经可以分出胜负

      return goal(board);

      else

      return evlation(board);

      }

      }

      注意这里的goal(board)函数是用来判断当前盘面是否可以分出胜负,而evlation(board)是对当前的盘面从机器的角度进行打分。

      下面是Select函数的介绍,这个函数的主要目的是根据 PlayerMode情况,即是机器还是用户来返回节点的应有的值。

      double Select(double a,double b,int mode)

      {

      if(a>b && mode==max)&brvbar;&brvbar; (a< b && mode==min)

      return a;

      else

      return b;

      }

      五、小结

      在Windows操作系统下,用VC++实现了这个人机对战的五子棋程序。和国内许多只是采用规则或者只是采用简单递归而没有剪枝的那些程序相比,在智力上和时间有效性上都要好于这些程序。同时所讨论的方法和设计过程为用户设计其他的游戏(如象棋和围棋等)提供了一个参考


       收藏   分享  
    顶(0)
      




    ----------------------------------------------
    ---人之所以能,是相信能!!

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2010/11/7 17:38:00
     
     GoogleAdSense水瓶座1984-2-14
      
      
      等级:大一新生
      文章:1
      积分:50
      门派:无门无派
      院校:未填写
      注册:2007-01-01
    给Google AdSense发送一个短消息 把Google AdSense加入好友 查看Google AdSense的个人资料 搜索Google AdSense在『 C/C++编程思想 』的所有贴子 点击这里发送电邮给Google AdSense 访问Google AdSense的主页 引用回复这个贴子 回复这个贴子 查看Google AdSense的博客广告
    2024/11/25 16:35:23

    本主题贴数1,分页: [1]

    管理选项修改tag | 锁定 | 解锁 | 提升 | 删除 | 移动 | 固顶 | 总固顶 | 奖励 | 惩罚 | 发布公告
    W3C Contributing Supporter! W 3 C h i n a ( since 2003 ) 旗 下 站 点
    苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
    66.406ms