比这篇新的文章: Gmail 发信
比这篇旧的文章: char_identification.h

华容道最短路径求解程序

语言: C++, 标签: 华容道 求解程序 2008/10/01发布 2个月前更新 更新记录
作者: 半瓶墨水, 点击1464次, 评论(8), 收藏者(1), , 打分:

背景
主题: 字体:
001 //解华容道的程序,解题时间在100ms以内
002 //by 半瓶墨水( http://www.2maomao.com/blog/ )
003 // 相关文章在这里:http://www.2maomao.com/blog/youxi-hrd-online-resolver/
004 // 可以到这里体验: http://fayaa.com/youxi/hrd/add/
005
006 #pragma warning(disable:4530)
007 #include <stdio.h>
008 #include <set>
009 #include <deque>
010 using namespace std;
011 typedef __int64 INT64;
012 typedef unsigned char BYTE;
013 //!assume int is 32-bit
014
015 //block item type
016 enum BIT {EMPTY=0, DOT, VBAR, HBAR, BOX};
017
018 class Board;
019 //----------------------------------------
020 //Global variables
021 set<INT64> g_mbd;
022 deque<Board*> g_bfs; //Broad-First-Search to ensure shortest path
023 unsigned int g_index = 0;
024
025 //CI is short for Cell Index
026 #define VALID_CI(x) (x >= 0 && x < 10)
027 #define IS_BOX(x) (items[x-1]>>5 == BOX)
028 #define BUILD_BYTE(type, x, y) ((type) << 5 | (x) << 3 | (y))
029
030 class Board {
031 public:
032     Board(){}
033     Board(int *layout) {
034         memset(this, 0, sizeof(*this));
035         //0xFF mean's boundary
036         for (int i=0; i<6; i++) {
037             matrix[0][i] = (BYTE)0xFF;
038             matrix[6][i] = (BYTE)0xFF;
039         }
040         for (int i=0; i<7; i++) {
041             matrix[i][0] = (BYTE)0xFF;
042             matrix[i][5] = (BYTE)0xFF;
043         }
044         //init the matrix and items
045         BYTE type = 0;
046         BYTE x = 0;
047         BYTE y = 0;
048         for (int i=0; i<10; i++) {
049             type = layout[i*3];
050             x = layout[i*3+1];
051             y = layout[i*3+2];
052             items[i] = BUILD_BYTE(type, x, y);
053             switch (type) {
054                 case DOT:  matrix[y+1][x+1] = i+1; break;
055                 case VBAR: matrix[y+1][x+1] = i+1; matrix[y+2][x+1] = i+1; break;
056                 case HBAR: matrix[y+1][x+1] = i+1; matrix[y+1][x+2] = i+1; break;
057                 case BOX:  matrix[y+1][x+1] = i+1; matrix[y+1][x+2] = i+1;
058                            matrix[y+2][x+1] = i+1; matrix[y+2][x+2] = i+1; break;
059             }
060         }
061         //find out the empty block
062         int count = 0;
063         for (int i=0; i<7; i++)
064             for (int k=0; k<6; k++)
065                 if (matrix[i][k] == 0)
066                     empty[count++] = k << 4 | i;
067     }
068
069     inline INT64 GetValue() {
070         INT64 val = 0;
071         int index = 0;
072         BYTE bt = 0;
073         for (int i=1; i<6; i++) {
074             for (int k=1; k<5; k++) {
075                 index = matrix[i][k] - 1;
076                 bt = VALID_CI(index) ? items[index] >> 5 : 0;
077                 val = val << 3 | bt;
078             }
079         }
080         return val;
081     }
082     inline INT64 GetRValue() {
083         INT64 val = 0;
084         int index = 0;
085         BYTE bt = 0;
086         for (int i=1; i<6; i++) {
087             for (int k=4; k>0; k--) {
088                 index = matrix[i][k] - 1;
089                 bt = VALID_CI(index) ? items[index] >> 5 : 0;
090                 val = val << 3 | bt;
091             }
092         }
093         return val;
094     }
095     void PrintOut() {
096         printf("\n-----------------------------------\n");
097         printf("count=%d, parent=%d, empty=(%d,%d),(%d, %d)\n",
098             g_bfs.size(), parent, empty[0]>>4, empty[0]&0xF, empty[1]>>4, empty[1]&0xF);
099         printf("   0 1 2 3 4 5\n");
100         for (int i=0; i<7; i++) {
101             printf("%d|", i);
102             for (int k=0; k<6; k++) {
103                 int index = matrix[i][k] - 1;
104                 if (VALID_CI(index))
105                     printf("%2x", index);
106                 else
107                     printf("  ");
108             }
109             printf("\n");
110         }
111     }
112     //spawn new Board by moving the cells around empty cells
113     //  return false if not found
114     //  return true if we got the solution
115     //      the last board in the deque is the solution
116     bool Spawn() {
117         //collect the cells around empty cells
118         BYTE around[8] = {0};
119         int count = 0;
120         //DO NOT change the order of ulrd, it's been depended
121         int ulrd[4][2] = {{0,-1}, {-1,0}, {1,0}, {0,1}};
122         for (int i=0; i<2; i++) {
123             int x = empty[i] >> 4;
124             int y = empty[i] & 0xF;
125             for (int k=0; k<4; k++) {
126                 int nx = x + ulrd[k][0];
127                 int ny = y + ulrd[k][1];
128                 int index = matrix[ny][nx] - 1;
129                 if (VALID_CI(index)) {
130                     Board *pnewb = new Board();
131                     *pnewb = (*this);
132                     pnewb->level += 1; //it's next level
133                     pnewb->parent = g_index;
134                     if (pnewb->TryAndMove(index, -ulrd[k][0], -ulrd[k][1])) {
135                         INT64 value = 0;
136                         //in Hua-Rong-Dao's rule, move a cell continously
137                         //  multi-times, only count as ONE step, so,
138                         //  let's give it another chance to move
139                         int moveBack = k ^ 3; //3==0b11, the reverse direction of last move
140                         Board *pnewb2 = new Board();
141                         *pnewb2 = (*pnewb);
142                         //pnewb2->parent = g_bfs.size() - 1;
143                         int d = 0;
144                         for (; d<4; d++) {
145                             if (d == moveBack) continue;
146                             //copy data and add parent
147                             if (pnewb2->TryAndMove(index, -ulrd[d][0], -ulrd[d][1])) {
148                                 value = pnewb2->GetValue();
149                                 if (g_mbd.find(value) == g_mbd.end()) {
150                                     //add new board to bfs and set the board value to map
151                                     g_bfs.push_back(pnewb2);
152                                     g_mbd.insert(value);
153                                     g_mbd.insert(pnewb2->GetRValue());
154                                     //Do we win?
155                                     if (pnewb2->Win())
156                                         return true;
157                                 }
158                                 break;//ONLY one direction is good due to the rule
159                             }
160                         }
161                         if (d == 4) delete pnewb2;
162                         //-------------------------------------
163                        
164                         value = pnewb->GetValue();
165                         if (g_mbd.find(value) == g_mbd.end()) {
166                             //add new board to bfs and set the board value to map
167                             g_bfs.push_back(pnewb);
168                             g_mbd.insert(value);
169                             g_mbd.insert(pnewb->GetRValue());
170                             //Do we win?
171                             if (pnewb->Win())
172                                 return true;
173
174                             continue;
175                         }
176                     }
177                     delete pnewb;
178                 }
179             }
180         }
181         return false;
182     }
183
184     bool Win() {
185         //return true if the following cell's type is BOX
186         // 2,4, 3,4, 2,5, 3,5
187         return IS_BOX(matrix[4][2]) && IS_BOX(matrix[4][3]) &&
188                IS_BOX(matrix[5][2]);// && IS_BOX(matrix[5][3]);
189     }
190
191     bool TryAndMove(int index, int dx, int dy) {
192         BYTE item = items[index];
193         BYTE type = item >> 5;
194         int x = item >> 3 & 0x03; //0x03==0b11
195         int y = item & 0x07; //0x07==0b111
196         bool bRet = false;
197         //ci is short for cell index
198         int ci1, ci2, ci3, ci4;
199         ci1 = ci2 = ci3 = ci4 = 0;
200         switch (type) {
201             case DOT:
202                 ci1 = matrix[y+dy+1][x+dx+1];
203                 bRet = !ci1 || ci1==index+1;
204                 if (bRet) {
205                     matrix[y+1][x+1] = 0;
206                     matrix[y+dy+1][x+dx+1] = index + 1;
207                     items[index] = BUILD_BYTE(type, x+dx, y+dy);
208                     SetEmpty(x+1, y+1);
209                 }
210                 break;
211             case VBAR:
212                 ci1 = matrix[y+dy+1][x+dx+1];
213                 ci2 = matrix[y+dy+2][x+dx+1];
214                 bRet = (!ci1 || ci1==index+1) && (!ci2 || ci2==index+1);
215                 if (bRet) {
216                     matrix[y+1][x+1] = 0;
217                     matrix[y+2][x+1] = 0;
218                     matrix[y+dy+1][x+dx+1] = index + 1;
219                     matrix[y+dy+2][x+dx+1] = index + 1;
220                     items[index] = BUILD_BYTE(type, x+dx, y+dy);
221                     if (matrix[y+1][x+1] == 0) SetEmpty(x+1, y+1);
222                     if (matrix[y+2][x+1] == 0) SetEmpty(x+1, y+2);
223                 }
224                 break;
225             case HBAR:
226                 ci1 = matrix[y+dy+1][x+dx+1]; ci2 = matrix[y+dy+1][x+dx+2];
227                 bRet = (!ci1 || ci1==index+1) && (!ci2 || ci2==index+1);
228                 if (bRet) {
229                     matrix[y+1][x+1] = 0; matrix[y+1][x+2] = 0;
230                     matrix[y+dy+1][x+dx+1] = index + 1;
231                     matrix[y+dy+1][x+dx+2] = index + 1;
232                     items[index] = BUILD_BYTE(type, x+dx, y+dy);
233                     if (matrix[y+1][x+1] == 0) SetEmpty(x+1, y+1);
234                     if (matrix[y+1][x+2] == 0) SetEmpty(x+2, y+1);
235                 }
236                 break;
237             case BOX:
238                 ci1 = matrix[y+dy+1][x+dx+1]; ci2 = matrix[y+dy+1][x+dx+2];
239                 ci3 = matrix[y+dy+2][x+dx+1]; ci4 = matrix[y+dy+2][x+dx+2];
240                 bRet = (!ci1 || ci1==index+1) && (!ci2 || ci2==index+1) &&
241                        (!ci3 || ci3==index+1) && (!ci4 || ci4==index+1);
242                 if (bRet) {
243                     matrix[y+1][x+1] = 0; matrix[y+1][x+2] = 0;
244                     matrix[y+2][x+1] = 0; matrix[y+2][x+2] = 0;
245                     matrix[y+dy+1][x+dx+1] = index+1; matrix[y+dy+1][x+dx+2] = index+1;
246                     matrix[y+dy+2][x+dx+1] = index+1; matrix[y+dy+2][x+dx+2] = index+1;
247                     items[index] = BUILD_BYTE(type, x+dx, y+dy);
248                     if (matrix[y+1][x+1] == 0) SetEmpty(x+1, y+1);
249                     if (matrix[y+1][x+2] == 0) SetEmpty(x+2, y+1);
250                     if (matrix[y+2][x+1] == 0) SetEmpty(x+1, y+2);
251                     if (matrix[y+2][x+2] == 0) SetEmpty(x+2, y+2);
252                 }
253                 break;
254         }
255         return bRet;
256     }
257
258     void SetEmpty(int ex, int ey) {
259         int x = empty[0] >> 4;
260         int y = empty[0] & 0xF;
261         BYTE *pB = &empty[1];
262         if (matrix[y][x] != 0)
263             pB = &empty[0];
264         (*pB) = (ex<<4) + ey;
265     }
266
267     //Member variables====^_^====^_^====^_^====^_^====^_^====^_^====
268     int level;
269     int parent; //parent node position in the deque
270     BYTE matrix[7][6]; //[1+5+1][1+4+1] of byte, each byte is the (index+1) in items
271     BYTE empty[2];  //2 empty slot's position in matrix, x = p >> 4, y = p & 0xF
272     BYTE items[10]; //BIT:3,x:2,y:3), x,y is zero-based
273 };
274
275 //----------------------------------------
276 //return the board index in g_bfs if succeed
277 bool SolveTheBoard(const Board &bd) {
278     Board *pnewb = new Board();
279     *pnewb = bd;
280     g_bfs.push_back(pnewb);
281     g_mbd.insert(pnewb->GetValue());
282     g_mbd.insert(pnewb->GetRValue());
283     while (g_index < g_bfs.size()) {
284         bool bRet = g_bfs[g_index]->Spawn();
285         if (bRet) return bRet;
286         g_index++;
287     }
288     return false;
289 }
290
291 void PrintSolution() {
292     deque<Board*> sbs;
293     Board *pBd = g_bfs[g_bfs.size() - 1];
294     sbs.push_front(pBd);
295     printf("Steps = %d\n", pBd->level);
296     while (pBd->parent != 0) {
297         pBd = g_bfs[pBd->parent];
298         sbs.push_front(pBd);
299     }
300     for (unsigned int i=0; i<sbs.size(); i++)
301         sbs[i]->PrintOut();
302 }
303
304 #include<windows.h>
305 void main() {
306     //HengDaoLiMa
307     int layout[] = {2,0,0, 4,1,0, 2,3,0, 2,0,2, 3,1,2, 2,3,2, 1,1,3, 1,2,3, 1,0,4, 1,3,4 };
308     //BiYiHengKong
309     //int layout[] = {3,0,0, 4,2,0, 3,0,1, 3,0,2, 3,2,2, 1,0,3, 1,2,3, 2,3,3, 1,0,4, 1,2,4 };
310     Board bd(layout);
311     DWORD tc1 = GetTickCount();
312     bool bRet = SolveTheBoard(bd);
313     DWORD tc2 = GetTickCount();
314     printf("Total: %d ms\n", tc2-tc1);
315     if (bRet) {
316         PrintSolution();
317         printf(":)  bfs=%d, mbd=%d,  Solved!\n", g_bfs.size(), g_mbd.size());
318     } else {
319         printf(":)  bfs=%d, mbd=%d,  NO SOLUTION FOUND!\n", g_bfs.size(), g_mbd.size());
320     }
321
322     //delete all items
323     for (unsigned int i=0; i<g_bfs.size(); i++)
324         delete g_bfs[i];
325 }


所有评论,共8条:( 我也来说两句)

1
3751 9个月前 回复
0
0
看看http://wmlin.ycool.com/post.2152998.html。最难的华容道题目我的python程序需要5秒。是基于Leo Jay的版本修改的^_^。
2
半瓶墨水 9个月前 回复
0
0
呵呵,我要做网页上的自动解题程序(近两天上线),所以5秒还是太多了,必须控制在100ms以内。
3
3751 9个月前 回复
0
1
其实我2年前就发现了,华容道的可行局面太少了,完全可以用数据库将解法存起来^_^
你贴的c++程序还有很大的改进空间啊。
4
半瓶墨水 9个月前 回复
1
1
嗯,时间有限,做东西我都是做到够用就行了
暂时没有再改进的需求,而且可行局面是以万为单位的,遍历起来找个快点儿的机器也得个把钟头,出啥问题调试太费劲
呵呵你有兴趣的可以尝试一下,至少可以找出开局难度列表
5
半瓶墨水 9个月前 回复
0
0
华容道自动求解程序的网页版已经做好了,在这里:
http://www.fayaa.com/youxi/hrd/add/
6
Leo Jay 6个月前 回复
0
0
貌似你的程序不能解第44局?  
7
半瓶墨水 6个月前 回复
0
0
@Leo Jay 呵呵没错,第44局不是标准布局(大于10个方块)
8
半瓶墨水 3个月前 回复
0
0
@Leo Jay: 已经能解第44局了

发表评论

注册登录后再发表评论