吴昊品游戏核心算法 Round 9 —— 黑白棋AI系列(第一弹)(BFS+位压缩存储)(POJ 1753)

 

在历史上,关于黑白棋(官方名称为奥赛罗),有许多个变种,比如这一弹中,我准备给出其中一种(和我在Round 7中介绍的熄灯问题)比较相似的(甚至可以说是几乎一摸一样)的游戏,其名字叫做翻转棋(Flip Game)。这款游戏的规则非常简单,在一个4*4的界面中,随意翻转一个子,其自身以及相邻的棋子都会跟着翻转并变换其颜色。了 解了规则之后,我们可以给出如下的AI,该AI可以翻转最短的次数,来找到目标位置(可以是全黑(All Black)或者是全白(All White))。在“熄灯问题”中,我们说过一种方法叫做BFS+Enum(也就是广度优先搜索配合枚举),这里注意的一点是,我们不能使用STL里面的 容器(包括bitset和queue),因为会产生溢出。这里,我们将数组改变成队列或者栈,在65535个长度以内都不会发生溢出的问题了。

 

Problem——源自POJ 1753,给出四行四列的16个字符,b代表黑子(black),w代表白子(white),我们的输出需要给出一个整形的数字,来表示最少几次就可以达到我们所需要的目标。如果完全无法达到的话,就输出Impossible。

队列实现:


  1 /*
  2 
  3     Highlights:
  4 
  5    (1)为了获得更多的装填量,利用数组模拟队列,而不使用STL中的各种容器
  6 
  7    (2)1<<x表示置x位为黑位,16个格子,正好用short int的短整型数表示16个点
  8 
  9    (3)巧妙运用XOR运算,将每一次变化后的状态存储
 10 
 11  */
 12 
 13  
 14 
 15  #include<iostream>
 16 
 17  #include<queue>
 18 
 19  using namespace std;
 20 
 21  
 22 
 23  int step[65535]; //利用数组,可以得到比容器更多的装载量(这里表示所有可能的装载量)
 24 
 25  bool flag[65535]; //防止重复搜索
 26 
 27  unsigned short qState[65535]; //搜索的状态,由于65536=2^16,所以可以用每一位的'0'和'1'状态标记是否被搜索
 28 
 29  
 30 
 31  int rear=0//队列尾指针
 32 
 33  int top=0//队列头指针
 34 
 35  
 36 
 37  //初始化,读入棋盘的初始状态并将其转化为16位数存储在头队列中
 38 
 39  //黑为'1'而白为'0'
 40 
 41  
 42 
 43  void init()
 44 
 45  {
 46 
 47    unsigned short temp=0;//无字符短整型变量,省空间
 48 
 49    char c;//每次读入一个字符
 50 
 51    for(int i=0;i<4;i++)
 52 
 53    {
 54 
 55      for(int j=0;j<4;j++)
 56 
 57      {
 58 
 59        cin>>c;
 60 
 61        if('b'==c)//注意这样写的妙处!如果写成c=='b'很容易和c='b'混淆
 62 
 63          temp=temp|(1<<(i*4+j));//将黑位置为高位       
 64 
 65      }       
 66 
 67    }    
 68 
 69    qState[rear++]=temp;//载入状态队列
 70 
 71    flag[temp]=true;//标记该位
 72 
 73  }
 74 
 75  
 76 
 77  //翻转一个棋子,并按照规则对周围棋子施加影响
 78 
 79  unsigned short move(unsigned short state,int i)
 80 
 81  {
 82 
 83    unsigned short temp=0;
 84 
 85    temp|=(1<<i);
 86 
 87    if((i+1)%4!=0//不在最右的右
 88 
 89      temp|=(1<<(i+1));
 90 
 91    if(i%4!=0//不在最左的左
 92 
 93      temp|=(1<<(i-1));
 94 
 95    if(i+4<16//
 96 
 97      temp|=(1<<(i+4));
 98 
 99    if(i-4>=0//
100 
101      temp|=(1<<(i-4));
102 
103    return (state^temp);//XOR异或运算        
104 
105  }
106 
107  
108 
109  //采用BFS将每一次
110 
111  bool BFS()
112 
113  {
114 
115    while(rear>top)//直到队列中无元素
116 
117    {
118 
119      //这个指令是在模拟qState.pop();
120 
121      unsigned short state=qState[top++];
122 
123      for(int i=0;i<16;i++)
124 
125      {
126 
127        unsigned short temp;
128 
129        temp=move(state,i);       
130 
131        if(0==state||65535==state)//上述说过的技巧
132 
133        {
134 
135          cout<<step[state]; 
136 
137          return true;                        
138 
139        }
140 
141        else if(!flag[temp])//防止重复搜索
142 
143        {
144 
145          //模拟进队列操作qState.push(temp);
146 
147          qState[rear++]=temp;
148 
149          flag[temp]=true;
150 
151          step[temp]=step[state]+1;    
152 
153        }
154 
155      }              
156 
157    }    
158 
159    return 0;
160 
161  }
162 
163  
164 
165  int main()
166 
167  {
168 
169    init();
170 
171    if(!BFS()) cout<<"Impossible";
172 
173    char c;
174 
175    cin>>c;
176 
177    return 0;   
178 
179  }

posted on 2013-02-27 21:36  吴昊系列  阅读(545)  评论(1编辑  收藏  举报

导航