吴昊品游戏核心算法 Round 4 (特别篇) —— 贪吃蛇AI

 有了模拟算法的基础,在特别篇中,我们可以看下AI了。在GOOGLE公司,每年都有GOOGLE AI CHALLENGE挑战赛,其中就包括国际贪吃蛇AI大赛。但是,由于源码的封闭性,我无法获得了。在网上只有某些70后网友写的“半成品”AI。幸运 地,我联系上了一个北京理工大学的大学生,他做的AI貌似很不错(有单机版和双人模式两种模式可供选择),不过木有源代码,他给出了他自己的QQ以便于 DEBUG。这样子,我正在全力联系那位23岁的大神,目前,只能给出基于“权重”的一种设计思想的AI算法了,虽说是半成品,不过,也是一种思路吧!

 

  文章以及其AI的思想整理如下:

本来去年在写了贪吃蛇之后,就有想要写看AI来耍看的,后来又觉得写起麻烦没想好,没写.

今天又想起了,写来耍看.以前想的要麻烦些,当然可以直接搜索,那个是"可以",但是不太"可行".

//吴昊评注:搜索行不通,便想到了贪心的思想,不考虑全局最优解,根据最短路径(上下左右)+每次(上下左右)被自己“咬死”的可能性局部判断一个操作,贪心出局部最优解

今天上午想的就是求最优解的过程,不过要求最优解要麻烦些.

先以当前状态求到最短路径(需要做一些判断避免咬到自己,和被自己困死),并在每次移动后,地图改变状态后,再以新状态去计算下一步.

 

那个写起代码就多了,想简单点的几条规则就能达到那种效果.所以就只做当前最优选择,不考虑全局最优解,这样的智能效果应该还可以吧.

那个局部最优解是否可以达到全局最优解,不晓得囊个证明,如果能够达到的话,那工作量就少黑多了.

 

当前最优选择,按3个步骤:

1.先计算到达目标的,可行的前进方向,上,下,左,右,评估每个方向的权重.

2.计算当前这次移动所产生的影响,然后修正各方向的权重.

3.仲裁选出权重最大的那个方向,作为移动方向.

 

第2步中,要分解为两个阶段:(考虑两种情况)

1).先判断每个方向移动后,是否会咬到自己,如果是那个方向上的权重设为极小.(解决咬到自己)

2).如果仍一个方向移动后,会和自己接触(形成闭环),需要修正权重避开进入死胡同.(解决困死)

 

下面是代码:(现在解决了咬到自己,解决困死还没完成,食物在背后还没有完成)


  1  //  ***************************************************************
  2  //   LittleAI   version:  1.0   ? date: 08/28/2010
  3  //   -------------------------------------------------------------
  4  //   File:    LittleAI.h
  5  //   System:  Dual-Core T4300 2.10GHz ,DDR2 2GB ,Geforce GT 240M ,
  6  //            Windows XP SP3 ,MSVC++ 8.0
  7  //   Author:  风轻炫舞 HoneyCat
  8  //   Purpose: 贪吃蛇AI
  9  //   -------------------------------------------------------------
 10  //   Copyright (C) 2010 - All Rights Reserved
 11  //  ***************************************************************
 12  //
 13  //  ***************************************************************
 14  #ifndef __SNAKEAI_H__
 15  #define __SNAKEAI_H__
 16 #include  " Map.h "
 17 #include  " Snake.h "
 18 #include  " Food.h "
 19 
 20  #define DEFAULTWEIGHT 1
 21  #define MINWEIGHT -1
 22 
 23  class SnakeAI
 24 {
 25      struct Action
 26     {
 27          int _Weight;
 28         MoveDir _Dir;
 29     };
 30 
 31  public:
 32      void Ready(Map& map,Snake& snake,Food& food)
 33     {
 34         
 35     }
 36 
 37      void Go(Map& map,Snake& snake,Food& food)
 38     {
 39          if (snake.IsState(SS_Death))
 40              return;
 41 
 42         snake.ChangDir(Decision(map,snake,food));
 43     }
 44 
 45     MoveDir Decision(Map& map,Snake& snake,Food& food)
 46     {
 47         Action nextact[ 4];
 48         memset(nextact, 0x0, sizeof(nextact));
 49          int actnum= 4;
 50 
 51         CalcFeasibleAct(nextact,actnum,map,snake,food);
 52         NextActEffect(nextact,actnum,map,snake,food);
 53 
 54          return Arbitration(nextact,actnum,snake);
 55     }
 56 
 57  protected:
 58 
 59      void NextActEffect(Action* nextact, int& actnum,Map& map,Snake& snake,Food& food)
 60     {
 61          if (NoBiteSelf(nextact,actnum,map,snake,food))
 62             NoBesiegeSelf(nextact,actnum,map,snake,food);
 63     }
 64 
 65      void CalcFeasibleAct(Action* nextact, int& actnum,Map& map,Snake& snake,Food& food)
 66     {
 67         InitAction(nextact,actnum,snake);
 68         CalcWeight(nextact,actnum,snake,food);
 69     }
 70 
 71      void InitAction(Action* nextact, int& actnum,Snake& snake)
 72     {
 73         actnum= 4;
 74         nextact[snake.GetDir()]._Weight=DEFAULTWEIGHT;    nextact[snake.GetDir()]._Dir=snake.GetDir();
 75         nextact[snake.GetLeftDir()]._Weight= 0;    nextact[snake.GetLeftDir()]._Dir=snake.GetLeftDir();
 76         nextact[snake.GetRightDir()]._Weight= 0;    nextact[snake.GetRightDir()]._Dir=snake.GetRightDir();
 77         nextact[snake.GetBackDir()]._Weight=MINWEIGHT; nextact[snake.GetBackDir()]._Dir=snake.GetBackDir();
 78     }
 79 
 80      void CalcWeight(Action* nextact, int& actnum,Snake& snake,Food& food)
 81     {
 82          if (food.IsState(FS_Eaten))
 83         {
 84              return;
 85         }
 86         MapPoint curpos=snake.GetBody(snake.GetHead());
 87         MapPoint dest=food.GetPos();
 88 
 89          int len=abs(dest._X-curpos._X)+abs(dest._Y-curpos._Y);
 90 
 91          if ((dest._X-curpos._X)> 0)
 92         {
 93             nextact[MD_RIGHT]._Weight=len;
 94         }
 95          else  if ((dest._X-curpos._X)< 0)
 96         {
 97             nextact[MD_LEFT]._Weight=len;
 98         }
 99          else
100         {
101             nextact[MD_RIGHT]._Weight= 0;
102             nextact[MD_LEFT]._Weight= 0;
103         }
104 
105          if ((dest._Y-curpos._Y)> 0)
106         {
107             nextact[MD_UP]._Weight=len;
108         }
109          else  if ((dest._Y-curpos._Y)< 0)
110         {
111             nextact[MD_DOWN]._Weight=len;
112         }
113          else  if ((dest._Y-curpos._Y)== 0)
114         {
115             nextact[MD_UP]._Weight= 0;
116             nextact[MD_DOWN]._Weight= 0;
117         }
118     }
119     
120      bool NoBiteSelf(Action* nextact, int& actnum,Map& map,Snake& snake,Food& food)
121     {
122         MapPoint headpos=snake.GetBody(snake.GetHead());
123         MapPoint tailpos=snake.GetBody(snake.GetTail());
124         MapPoint dirpos;
125          bool touchself= false;
126          for ( int i= 0;i<actnum;++i)
127         {
128             NextHeadPos(dirpos,headpos,nextact[i]);
129              if (map.WhatInMap(dirpos._X,dirpos._Y)==OT_Snake)
130             {
131                  if (dirpos._X==tailpos._X&&dirpos._Y==tailpos._Y)
132                      continue;
133 
134                 nextact[i]._Weight=MINWEIGHT;
135                 touchself= true;
136             }
137         }
138          return touchself;
139     }
140 
141      void NextHeadPos(MapPoint& pos,MapPoint& curpos,Action& nextact)
142     {
143          switch(nextact._Dir)
144         {
145          case MD_DOWN:
146          case MD_UP:
147             pos._X=curpos._X;
148             pos._Y=curpos._Y+(nextact._Dir<< 1)- 1;
149              break;
150          case MD_LEFT:
151          case MD_RIGHT:
152             pos._X=curpos._X+((nextact._Dir-MD_LEFT)<< 1)- 1;
153             pos._Y=curpos._Y;
154              break;
155         }
156     };
157 
158      void NoBesiegeSelf(Action* nextact, int& actnum,Map& map,Snake& snake,Food& food)
159     {
160         
161     }
162 
163     MoveDir Arbitration(Action* nextact, int actnum,Snake& snake)
164     {
165         Action act;
166         act._Weight=MINWEIGHT;
167          for ( int i= 0;i<actnum;++i)
168         {
169              if (act._Weight<nextact[i]._Weight)
170             {
171                 act=nextact[i];
172             }
173         }
174         LogAct(act);
175          return act._Dir;
176     }
177 
178      void LogAct(Action& act)
179     {
180          switch (act._Dir)
181         {
182          case MD_UP:
183             printf( " Move Up/n ");
184              break;
185          case MD_DOWN:
186             printf( " Move Down/n ");
187              break;
188          case MD_LEFT:
189             printf( " Move Left/n ");
190              break;
191          case MD_RIGHT:
192             printf( " Move Right/n ");
193              break;
194         }
195     }
196 
197 };
198 
199  #endif __SNAKEAI_H__
200 
201 

你可能感兴趣的:(round)