Exemplo n.º 1
0
/*
 * 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;
}
Exemplo n.º 2
0
/*
 * 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);
}