游戏介绍:
这个游戏和推箱子类似,就是给你有限的操作数,每次操作只能把箱子左移或右移,然后箱子会掉落,最后把3个以上连续相连的相同的箱子消去,如果在规定的操作数内你能让所有的箱子全部消去则通过游戏。
游戏连接地址:http://www.gamereclaim.com/2008/10/hdos-databank-request-01/
游戏截图如下:
游戏总结:
刚开始的几关比较好过,到后面就越来越难,因为人的记忆空间有限(人脑的潜力还未被完全挖掘出来),所有很难考虑很多次操作的状态,后面受智佳(校队队友)提醒发现这个图只有7*6,操作数最大为4,果断可以用程序“爆”之,于是就可以YY的敲代码了,经过3个小时的辛勤劳动之后,果断得到了游戏的答案,中途调了一个Bug,但是发现在算第24关的答案的时候出错了,后面由于太晚了就先回宿舍了,后来回宿舍睡觉的时候发现是我在模拟箱子下落的过程对于某些情况是有错的,隔天早早到实验室果断改了一下代码(其实就是忘了更新原来位置箱子的状态,但最上层即一层有箱子时就会出错),最后我神奇的用程序通关了。(*^__^*) 嘻嘻……
暴力求解代码如下:
/* Author: ACb0y Date: 2010年12月3日13:19:14 Result: find the all ans of all levels. */ #include <iostream> #include <algorithm> #include <string> #include <vector> #include <queue> #include <set> using namespace std; //操作 struct operation { //在图中的那个格子进行操作 int x; int y; //操作的类型 int op_type; //构造函数 operation(int a, int b, int c) { x = a; y = b; op_type = c; } }; //每个状态 struct state { //图的状态 char g[8][7]; //从初始状态达到当前状态 ///需要的操作序列 vector<operation> v; }; //状态判重 set<string> s; //操作(1是右移,-1是左移) int dy[] = {1, -1}; //初始化图 char g[8][7]; //模拟单个箱子的掉落过程 void down_alone(int x, int y, char g[8][7]) { for (int i = x + 1; i <= 7; ++i) { if (g[i][y] == '0') { char t = g[x][y]; g[x][y] = g[i][y]; g[i][y] = t; x++; } else { break; } } } //模拟整列箱子的掉落一格的过程 void down(int x, int y, char g[8][7]) { for (int i = x - 1; i >= 1; --i) { g[i + 1][y] = g[i][y]; g[i][y] = '0'; } } //模拟消去三个以上连续的相同格子的过程 int Delete(char g[8][7]) { int i, j, k, l; int flag = 0; //横找 for (i = 1; i <= 7; ++i) { for (j = 1; j <= 6; ++j) { if (g[i][j] != '0' && j <= 4) { //查找连续相同的箱子,用len来保持连续相连 //的相同的格子的个数 int len = 0; for (k = j; k <= 6; ++k) { if (g[i][k] != g[i][j]) { break; } else { len++; } } //连续相同的格子有三个以上则模拟消去格子的过程 if (len >= 3) { //自己消失 for (k = j; k <= j + len - 1; ++k) { g[i][k] = 0; } //上层的所有格子掉落一层,(就是改了这里的代码) for (k = i - 1; k >= 0; --k) { for (l = j; l <= j + len - 1; ++l) { g[k + 1][l] = g[k][l]; //还有这里的代码也改了,箱子掉落之后 //原来的位置要为空。 g[k][l] = '0'; } } flag = 1; } } } } //竖找 for (i = 1; i <= 7; ++i) { for (j = 1; j <= 6; ++j) { if (g[i][j] != '0' && i <= 5) { int len = 0; for (k = i; k <= 7; ++k) { if (g[i][j] != g[k][j]) { break; } else { len++; } } if (len >= 3) { for (k = i; k <= i + len - 1; ++k) { g[k][j] = '0'; } for (k = i - 1; k >= 1; --k) { g[k + len][j] = g[k][j]; g[k][j] = '0'; } flag = 1; } } } } return flag; } //消去所有可以消去的格子 void delete_all(char g[8][7]) { while (Delete(g)); } //根据图的状态生产字符串,用来判重 string get_str(char g[8][7]) { string str = ""; for (int i = 1; i <= 7; ++i) { for (int j = 1; j <= 6; ++j) { str = str + g[i][j]; } } return str; } //判断是否找到一组解 int if_end(char g[8][7]) { int count = 0; for (int i = 1; i <= 7; ++i) { for (int j = 1; j <= 6; ++j) { if (g[i][j] != '0') { count++; } } } return count == 0 ? 1 : 0; } //广度优先遍历找最优解 void find_ans_bfs() { int i, j, k, l; state node; memcpy(node.g, g, sizeof(g)); //广度优先遍历使用的队列 queue<state> q; q.push(node); while (!q.empty()) { state current; current = q.front(); q.pop(); //扩展一层节点 for (i = 1; i <= 7; ++i) { for (j = 1; j <= 6; ++j) { if (current.g[i][j] != '0') { //扩展节点 for (k = 0; k < 2; ++k) { int newy = j + dy[k]; if (newy >= 1 && newy <= 6 && current.g[i][j] != current.g[i][newy]) { state temp = current; char t = temp.g[i][j]; temp.g[i][j] = temp.g[i][newy]; temp.g[i][newy] = t; //模拟格子移动的过程 down_alone(i, newy, temp.g); if (temp.g[i][j] == '0') { down(i, j, temp.g); } //消除可以消除的格子 delete_all(temp.g); //生产状态字符串 string str = get_str(temp.g); //集合判重 if (s.find(str) == s.end()) { s.insert(str); //保持操作结果 temp.v.push_back(operation(i, j, k)); //如果找到一组解,输出结果并返回。 if (if_end(temp.g)) { int len = temp.v.size(); for (l = 0; l < len; ++l) { cout << "位置(" << temp.v[l].x << "," << temp.v[l].y << ")"; if (temp.v[l].op_type == 0) { cout << "右移" << endl; } else { cout << "左移" << endl; } } return; } //入队列 q.push(temp); } } } } } } } } int main() { int i, j; freopen("in.txt", "r", stdin); for (i = 1; i <= 7; ++i) { for (j = 1; j <= 6; ++j) { cin >> g[i][j]; } } find_ans_bfs(); return 0; }
程序使用方法,首先你要建立一个输入文件in.txt,然后把关卡里初始的图的状态用一个7*6的矩阵表示。
如最上面的那个图的矩阵表示为:
程序运行结果如下:
(5, 2)右移之后的结果如下:
(6, 3)右移后的结果:
中间下面的三个蓝色箱子消掉了。
其余的9个箱子一起消掉。
过关了,(*^__^*) 嘻嘻……