/*********************************/ /* 知識を用いた探索(8パズル) */ /* coded by Y.Suganuma */ /*********************************/ #include <stdio.h> #include <queue> #include <map> #include <string> using namespace std; class Node { public: int dep, est; string str; Node (string str1, int dep1, int est1) { str = str1; // 状態 dep = dep1; // 深さ est = est1; // 評価値 } }; class Depth { public: int dep, est; string prev; Depth (string prev1, int dep1, int est1) { prev = prev1; // 前の状態 dep = dep1; // 深さ est = est1; // 評価値 } }; bool operator< (Node n1, Node n2) { bool sw = true; if (n1.est == n2.est) sw = (n1.str < n2.str) ? true : false; else sw = (n1.est > n2.est) ? true : false; return sw; } /************************/ /* ノードの評価 */ /* dep : 深さ */ /* str : 状態 */ /* goal : 目標状態 */ /* return : 評価値 */ /************************/ int estimation(int dep, string str, string goal) { int i1, i2, i3, i4, k1, k2, pi = dep, sw; char cg[3][3], cn[3][3]; for (i1 = 0; i1 < 9; i1++) { k1 = i1 / 3; k2 = i1 - 3 * k1; cg[k1][k2] = goal.at(i1) - '0'; } for (i1 = 0; i1 < 9; i1++) { k1 = i1 / 3; k2 = i1 - 3 * k1; cn[k1][k2] = str.at(i1) - '0'; } for (i1 = 0; i1 < 3; i1++) { for (i2 = 0; i2 < 3; i2++) { sw = 1; for (i3 = 0; i3 < 3 && sw > 0; i3++) { for (i4 = 0; i4 < 3 && sw > 0; i4++) { if (cg[i3][i4] == cn[i1][i2]) { sw = 0; pi += (abs(i3-i1) + abs(i4-i2)); } } } } } if (cn[1][1] != '0') pi++; if (cn[0][1] != (cn[0][0]+1)%9) pi += 2; if (cn[0][2] != (cn[0][1]+1)%9) pi += 2; if (cn[1][2] != (cn[0][2]+1)%9) pi += 2; if (cn[2][2] != (cn[1][2]+1)%9) pi += 2; if (cn[2][1] != (cn[2][2]+1)%9) pi += 2; if (cn[2][0] != (cn[2][1]+1)%9) pi += 2; if (cn[1][0] != (cn[2][0]+1)%9) pi += 2; if (cn[0][0] != (cn[1][0]+1)%9) pi += 2; return pi; } /********************************/ /* コマの移動 */ /* str : 現在の状態 */ /* res : 移動後の状態 */ /* return : 移動後の状態数 */ /********************************/ int move(string str, string *res) { int k, n = 0; string str1; k = str.find("0"); switch(k) { case 0: str1 = str.replace(k, 1, str, k+3, 1); str1 = str1.replace(k+3, 1, 1, '0'); res[n] = str1; n++; str1 = str.replace(k, 1, str, k+1, 1); str1 = str1.replace(k+1, 1, 1, '0'); res[n] = str1; n++; break; case 1: str1 = str.replace(k, 1, str, k+3, 1); str1 = str1.replace(k+3, 1, 1, '0'); res[n] = str1; n++; str1 = str.replace(k, 1, str, k-1, 1); str1 = str1.replace(k-1, 1, 1, '0'); res[n] = str1; n++; str1 = str.replace(k, 1, str, k+1, 1); str1 = str1.replace(k+1, 1, 1, '0'); res[n] = str1; n++; break; case 2: str1 = str.replace(k, 1, str, k+3, 1); str1 = str1.replace(k+3, 1, 1, '0'); res[n] = str1; n++; str1 = str.replace(k, 1, str, k-1, 1); str1 = str1.replace(k-1, 1, 1, '0'); res[n] = str1; n++; break; case 3: str1 = str.replace(k, 1, str, k-3, 1); str1 = str1.replace(k-3, 1, 1, '0'); res[n] = str1; n++; str1 = str.replace(k, 1, str, k+3, 1); str1 = str1.replace(k+3, 1, 1, '0'); res[n] = str1; n++; str1 = str.replace(k, 1, str, k+1, 1); str1 = str1.replace(k+1, 1, 1, '0'); res[n] = str1; n++; break; case 4: str1 = str.replace(k, 1, str, k-3, 1); str1 = str1.replace(k-3, 1, 1, '0'); res[n] = str1; n++; str1 = str.replace(k, 1, str, k+3, 1); str1 = str1.replace(k+3, 1, 1, '0'); res[n] = str1; n++; str1 = str.replace(k, 1, str, k-1, 1); str1 = str1.replace(k-1, 1, 1, '0'); res[n] = str1; n++; str1 = str.replace(k, 1, str, k+1, 1); str1 = str1.replace(k+1, 1, 1, '0'); res[n] = str1; n++; break; case 5: str1 = str.replace(k, 1, str, k-3, 1); str1 = str1.replace(k-3, 1, 1, '0'); res[n] = str1; n++; str1 = str.replace(k, 1, str, k+3, 1); str1 = str1.replace(k+3, 1, 1, '0'); res[n] = str1; n++; str1 = str.replace(k, 1, str, k-1, 1); str1 = str1.replace(k-1, 1, 1, '0'); res[n] = str1; n++; break; case 6: str1 = str.replace(k, 1, str, k-3, 1); str1 = str1.replace(k-3, 1, 1, '0'); res[n] = str1; n++; str1 = str.replace(k, 1, str, k+1, 1); str1 = str1.replace(k+1, 1, 1, '0'); res[n] = str1; n++; break; case 7: str1 = str.replace(k, 1, str, k-3, 1); str1 = str1.replace(k-3, 1, 1, '0'); res[n] = str1; n++; str1 = str.replace(k, 1, str, k-1, 1); str1 = str1.replace(k-1, 1, 1, '0'); res[n] = str1; n++; str1 = str.replace(k, 1, str, k+1, 1); str1 = str1.replace(k+1, 1, 1, '0'); res[n] = str1; n++; break; case 8: str1 = str.replace(k, 1, str, k-3, 1); str1 = str1.replace(k-3, 1, 1, '0'); res[n] = str1; n++; str1 = str.replace(k, 1, str, k-1, 1); str1 = str1.replace(k-1, 1, 1, '0'); res[n] = str1; n++; break; } return n; } /********************************/ /* 知識を用いた探索(8パズル) */ /* start : 初期状態 */ /* goal : 目標状態 */ /********************************/ void intel(string start, string goal) { int i1, n, node1 = 1, node2 = 0, dep = 1, ct = 1, est; string str, res[4]; priority_queue<Node> p; map<string, Depth> m; map<string, Depth>::iterator it; bool sw; est = estimation(dep, start, goal); m.insert(pair<string, Depth>(start, Depth("",dep,est))); p.push(Node(start,dep,est)); while (!p.empty()) { str = p.top().str; dep = p.top().dep; node2++; // ゴール if (str == goal) { ct = dep; break; } // ゴールでない // コマを移動し,同じ状態のものがなければキューに追加 else { p.pop(); n = move(str, res); for (i1 = 0; i1 < n; i1++) { sw = true; est = estimation(dep+1, res[i1], goal); it = m.find(res[i1]); // 同じ状態か? if (it != m.end()) { if (est < ((*it).second).est) m.erase(it); else sw = false; } if (sw) { m.insert(pair<string, Depth>(res[i1], Depth(str,dep+1,est))); p.push(Node(res[i1], dep+1, est)); node1++; } } } } // 結果の出力 printf(" 展開とチェック: %d %d, 最短距離: %d\n", node1, node2, ct); while (str.length() > 0) { printf("\n %c %c %c\n", str.at(0), str.at(1), str.at(2)); printf(" %c %c %c\n", str.at(3), str.at(4), str.at(5)); printf(" %c %c %c\n", str.at(6), str.at(7), str.at(8)); it = m.find(str); str = ((*it).second).prev; } } int main() { string goal = "123804765"; printf("例1\n"); string start = "283164705"; intel(start, goal); printf("例2\n"); start = "216408753"; intel(start, goal); return 0; }