#include #include #include #include using namespace std; const char *kStart[] = { "baac", "baac", "dffe", "dghe", "i..j" }, *kGoal[] = { "....", "....", "....", ".aa.", ".aa." }; string buffer; int x, y, t, dx, dy, u0, v0, block_type[256]; struct Node { Node(Node *parent) : parent_(parent) { if( parent ) for(v0 = 0; v0 < 5; v0++) for(u0 = 0; u0 < 4; u0++) cell_[v0][u0] = parent->cell_[v0][u0]; } void Swap(int x0, int y0, int dx, int dy) { int tmp = cell_[y0][x0]; cell_[y0][x0] = cell_[y0 + dy][x0 + dx]; cell_[y0 + dy][x0 + dx] = tmp; } int Get(int u, int v) { return (v > -1 && v < 5 && u > -1 && u < 4) ? cell_[v][u] : 0; } int GetType(int u, int v) { return block_type[Get(u, v)]; } int Goal() { for(y = 0; y < 5; y++) for(x = 0; x < 4; x++) if( kGoal[y][x] - 46 && cell_[y][x] - kGoal[y][x] ) return 0; return 1; } void GetFingerprint() { buffer.clear(); for(v0 = 0; v0 < 5; v0++) for(u0 = 0; u0 < 4; u0++) buffer.push_back(block_type[cell_[v0][u0]]); } Node *parent_; int cell_[5][4]; }; Node *start, *neighbor; queue node_queue; set seen_nodes; const char *Cell(Node &node) { return node.Get(x, y) - 46 ? " " : "::"; } char Corner(Node &node) { dx = x - 1; return node.Get(dx, dy) - node.Get(x, dy) ? node.Get(dx, dy) - node.Get(dx, y) || node.Get(x, dy) - node.Get(x, y) ? 43 : 124 : node.Get(dx, y) - node.Get(x, y) ? 43 : node.Get(dx, dy) - node.Get(dx, y) ? 45 : *Cell(node); } char VerticalEdge(Node &node) { return node.Get(x - 1, y) - node.Get(x, y) ? 124 : *Cell(node); } int OutputSolution(Node &node) { t = node.parent_ ? 1 + OutputSolution(*node.parent_) : 0; printf("Move %d\n", t); for(y = 0; y < 6; y++) { dy = y - 1; for(x = 0; x < 4; x++) printf("%c%s", Corner(node), node.Get(x, dy) - node.Get(x, y) ? "--" : Cell(node)); printf("%c\n", Corner(node)); if( y < 5 ) { for(x = 0; x < 4; x++) printf("%c%s", VerticalEdge(node), Cell(node)); printf("%c\n", VerticalEdge(node)); } } return t; } void AddAndSwap(int x1, int y1, int dx1, int dy1, int x2, int y2, int dx2, int dy2) { neighbor = new Node(start); neighbor->Swap(x1, y1, dx1, dy1); neighbor->Swap(x2, y2, dx2, dy2); neighbor->GetFingerprint(); if( seen_nodes.insert(buffer).second ) node_queue.push(neighbor); else delete neighbor; } void AddAndSwap1(int x1, int y1, int dx1, int dy1) { AddAndSwap(x1, y1, dx1, dy1, 0, 0, 0, 0); } int main() { Node root(0); for(y = 0; y < 5; y++) for(x = 0; x < 4; x++) root.cell_[y][x] = kStart[y][x]; block_type[46] = 5; for(y = 0; y < 5; y++) for(x = 0; x < 4; x++) if( !block_type[t = root.Get(x, y)] ) block_type[t] = t - root.Get(x + 1, y) ? t - root.Get(x, y + 1) ? 1 : 2 : t - root.Get(x, y + 1) ? 3 : 4; root.GetFingerprint(); seen_nodes.insert(buffer); for(node_queue.push(&root); !node_queue.empty();) { start = node_queue.front(); node_queue.pop(); if( start->Goal() ) { OutputSolution(*start); break; } for(y = 0; y < 5; y++) for(x = 0; x < 4; x++) if( start->Get(x, y) == 46 ) { for(dx = -1; dx < 2; dx += 2) { t = start->GetType(x + dx, y); if( t == 1 ) AddAndSwap1(x, y, dx, 0); if( t == 3 && start->Get(x + dx, y) == start->Get(x + dx * 2, y) ) AddAndSwap1(x, y, dx * 2, 0); if( t == 5 ) { if( start->GetType(x + dx * 2, y) == 1 ) AddAndSwap1(x, y, dx * 2, 0); if( start->GetType(x + dx * 2, y) == 3 && start->Get(x + dx * 2, y) == start->Get(x + dx * 3, y) ) AddAndSwap(x, y, dx * 2, 0, x + dx, y, dx * 2, 0); } } for(dy = -1; dy < 2; dy += 2) { t = start->GetType(x, y + dy); if( t == 1 ) AddAndSwap1(x, y, 0, dy); if( t == 2 && start->Get(x, y + dy) == start->Get(x, y + dy * 2) ) AddAndSwap1(x, y, 0, dy * 2); if( t == 5 ) { if( start->GetType(x, y + dy * 2) == 1 ) AddAndSwap1(x, y, 0, dy * 2); if( start->GetType(x, y + dy * 2) == 2 && start->Get(x, y + dy * 2) == start->Get(x, y + dy * 3) ) AddAndSwap(x, y, 0, dy * 2, x, y + dy, 0, dy * 2); } } if( start->Get(x + 1, y) == 46 ) for(dy = -1; dy < 2; dy += 2) { if( start->GetType(x, y + dy) == 3 && start->Get(x, y + dy) == start->Get(x + 1, y + dy) ) AddAndSwap(x, y, 0, dy, x + 1, y, 0, dy); if( start->GetType(x, y + dy) == 4 && start->Get(x, y + dy) == start->Get(x + 1, y + dy) && start->Get(x, y + dy * 2) == start->Get(x + 1, y + dy * 2) && start->Get(x, y + dy) == start->Get(x, y + dy * 2) ) AddAndSwap(x, y, 0, dy * 2, x + 1, y, 0, dy * 2); if( start->GetType(x, y + dy) == 1 ) AddAndSwap1(x, y + dy, 1, -dy); if( start->GetType(x + 1, y + dy) == 1 ) AddAndSwap1(x + 1, y + dy, -1, -dy); } if( start->Get(x, y + 1) == 46 ) for(dx = -1; dx < 2; dx += 2) { if( start->GetType(x + dx, y) == 2 && start->Get(x + dx, y) == start->Get(x + dx, y + 1) ) AddAndSwap(x, y, dx, 0, x, y + 1, dx, 0); if( start->GetType(x + dx, y) == 4 && start->Get(x + dx, y) == start->Get(x + dx, y + 1) && start->Get(x + dx * 2, y) == start->Get(x + dx * 2, y + 1) && start->Get(x + dx, y) == start->Get(x + dx * 2, y) ) AddAndSwap(x, y, dx * 2, 0, x, y + 1, dx * 2, 0); if( start->GetType(x + dx, y) == 1 ) AddAndSwap1(x + dx, y, -dx, 1); if( start->GetType(x + dx, y + 1) == 1 ) AddAndSwap1(x + dx, y + 1, -dx, -1); } } } return 0; }