吴昊品游戏核心算法 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 

posted on 2013-02-27 20:48  吴昊系列  阅读(958)  评论(0)    收藏  举报

导航