/* * Solves the puzzle and prints results. * Returns 1 on success and 0 on nonexistence of a solution. */ static int solve(int *start, int *end) { Grid *root, *goal, *cur, *child, *iter, **result; Pqueue *pq; Set *visited; int goal_grid_code, child_code; int i, ch; int path_length; root = (Grid *) malloc(sizeof(Grid)); memcpy(root->g, start, sizeof(int) * 9); root->parent = NULL; root->hole = 1; root->depth = 0; goal = (Grid *) malloc(sizeof(Grid)); memcpy(goal->g, end, sizeof(int) * 9); goal_grid_code = grid_code(goal); get_correct_positions(goal); path_length = 0; i = 0; pq = pqueue_new(); visited = set_new(4); pqueue_insert(pq, root); set_insert(visited, grid_code(root)); while (!empty(pq)) { cur = pqueue_extract_min(pq); if (verbose) { fprintf(output, "%d.\n", ++i); fprintf(output, "Depth: %d\n", cur->depth); fprintf(output, "Grid:\n"); grid_print(output, cur); fprintf(output, "f: %2d\n", weight(cur)); fprintf(output, "\n"); } if (grid_code(cur) == goal_grid_code) break; ch = 0; #define ADD_CHILD() { \ child_code = grid_code(child); \ if (!set_contains(visited, child_code)) { \ set_insert(visited, child_code); \ pqueue_insert(pq, child); \ cur->child[ch++] = child; \ } else \ free(child); \ } /* Hole not on the left wall. */ if (cur->hole % 3 > 0) { child = make_child(cur); grid_move_hole(child, child->hole - 1); ADD_CHILD(); } /* Hole not on the right wall. */ if (cur->hole % 3 < 2) { child = make_child(cur); grid_move_hole(child, child->hole + 1); ADD_CHILD(); } /* Hole not on the top wall. */ if (cur->hole / 3 > 0) { child = make_child(cur); grid_move_hole(child, child->hole - 3); ADD_CHILD(); } /* Hole not on the bottom wall. */ if (cur->hole / 3 < 2) { child = make_child(cur); grid_move_hole(child, child->hole + 3); ADD_CHILD(); } #undef ADD_CHILD /* End of children character. */ cur->child[ch] = NULL; if (verbose) { fprintf(output, "Children:\n"); grid_children(output, cur); fprintf(output, "------------------------\n"); fprintf(output, "\n"); STEP(); } } if (grid_code(cur) != goal_grid_code) return 0; /* Collect result path. */ for (iter = cur; iter != NULL; iter = iter->parent) path_length ++; result = (Grid**) malloc(sizeof(Grid*) * path_length); i = path_length - 1; for (iter = cur; iter != NULL; iter = iter->parent) result[i--] = iter; if (verbose) fprintf(output, "Solution sequence:\n"); for (i = 0; i < path_length; i++) { grid_print(output, result[i]); STEP(); fprintf(output, "\n"); } /* Clean up. */ grid_dispose(root); set_dispose(visited); pqueue_dispose(pq); free(result); free(goal); return 1; }
/* * Single source shortest path algorithm (Dijkstra's algorithm). */ static int shortest_path(double *nodeArray, int num_nodes, double *edgeArray, int num_edges, int start_index, double dimdist[3], double radius, double *lastNodeList, int geoflag) { int i, cnt, num_nbhrs, curNodeIdx, curNhbrIdx, firstNodeOffset; double *node, *new_node, *nbhrs, *nbhrdists, new_dist; PQueue *PQ; /* Initialize distance to HUGE_VAL. */ for (i=0, node=&nodeArray[DIST]; i<num_nodes; i++, node+=NUM_ATTRS) *node = HUGE_VAL; /* Allocate priority queue and insert start_index as first node. */ PQ = make_pqueue(num_nodes); node = NODEN(nodeArray,start_index-1); node[DIST] = 0.0; if (lastNodeList != NULL) { lastNodeList[start_index-1] = 0; } pqueue_insert(PQ, (PQueueNode)node); firstNodeOffset = ((int)NODEN(nodeArray,0)); /* Dijkstra's algorithm. */ cnt = 0; while (!pqueue_empty_p(PQ)) { node = (double *) pqueue_extract_min(PQ); curNodeIdx = (int)(((int)(node) - firstNodeOffset) / (8*NUM_ATTRS)) + 1; node[DIST] = -node[DIST]; /* computed */ cnt++; /* Relax all the neighboring nodes. */ num_nbhrs = (int) node[NUM_NBHRS]; /* Get the geodesic distances to the neighbors. */ if (geoflag == 1) { nbhrs = EDGEN(edgeArray,(((int)node[NBHRS])-1)); nbhrdists = EDGEN(edgeArray,(((int)node[NBHRS])-1)) + 1; } else { nbhrs = &edgeArray[((int)node[NBHRS])-1]; } for (i=0; i<num_nbhrs; i++) { if (geoflag == 1) { curNhbrIdx = ((int)nbhrs[2*i]); new_node = NODEN(nodeArray,((int)nbhrs[2*i])-1); } else { curNhbrIdx = (((int)nbhrs[i])); new_node = NODEN(nodeArray,((int)nbhrs[i])-1); } if (new_node[DIST]>=0) { /* not computed yet */ /* node[DIST] has been negated a couple of lines above. * so, we need to negate it again to get the actual * (positive) distance. * -node[DIST] is the distance from our working node * to the start point. node_dist() is the distance * between our working node and its ith neighbor. */ /* 08.05.98 SJC * If geoflag == 1, use the geodesic edge distance. */ if (geoflag == 1) { new_dist = -node[DIST] + nbhrdists[2*i]; } else { new_dist = -node[DIST] + node_dist(node, new_node, dimdist); } if (new_dist<radius) { /* If this is the first time that we've gotten here, we * use this new distance and add the node into the * priority queue. */ if (new_node[DIST]==HUGE_VAL) { new_node[DIST] = new_dist; if (lastNodeList != NULL) { lastNodeList[curNhbrIdx - 1] = curNodeIdx; } pqueue_insert(PQ, (PQueueNode)new_node); } /* Otherwise, if the new distance is less than * the previously computed distance, then we pick * the new (shorter) distance and adjust its * position in the priority queue. */ else { if (new_dist<new_node[DIST]) { new_node[DIST] = new_dist; if (lastNodeList != NULL) { lastNodeList[curNhbrIdx - 1] = curNodeIdx; } pqueue_deckey(PQ, (PQueueNode)new_node); } } } } } } free_pqueue(PQ); return(cnt); }