void remove_child(Agraph_t * graph, Agnode_t * node) { Agedge_t *edge; Agedge_t *nexte; /* Avoid cycles */ if MARKED (node) return; MARK(node); /* Skip nodes with more than one parent */ edge = agfstin(node); if (edge && (agnxtin(edge) != NULL)) { UNMARK(node); return; } /* recursively remove children */ for (edge = agfstout(node); edge; edge = nexte) { nexte = agnxtout(edge); if (aghead(edge) != node) { if (verbose) fprintf(stderr, "Processing descendant: %s\n", agnameof(aghead(edge))); remove_child(graph, aghead(edge)); agdeledge(edge); } } agdelnode(node); return; }
int find_first_step(sh_int src, sh_int target, int stay_zone) { int curr_dir; sh_int curr_room; int src_zone = ((src - (src % 100)) / 100); int target_zone = ((target - (target % 100)) / 100); if (src < 0 || src > top_of_world || target < 0 || target > top_of_world) { stderr_log("Illegal value passed to find_first_step (graph.c)"); return BFS_ERROR; } /* dez 19980805 if ((src_zone != target_zone && stay_zone == 1) || stay_zone == 2) { return BFS_NO_PATH; } */ if (src_zone != target_zone && stay_zone == 1) { return BFS_NO_PATH; } if (src == target) { return BFS_ALREADY_THERE; } /* clear marks first */ for (curr_room = 0; curr_room <= top_of_world; curr_room++) { UNMARK(curr_room); } MARK(src); /* first, enqueue the first steps, saving which direction we're going. */ for (curr_dir = 0; curr_dir < NUM_OF_DIRS; curr_dir++) { if (VALID_EDGE(src, curr_dir)) { MARK(TOROOM(src, curr_dir)); bfs_enqueue(TOROOM(src, curr_dir), curr_dir); } } /* now, do the classic BFS. */ while (queue_head) { if (queue_head->room == target) { curr_dir = queue_head->dir; bfs_clear_queue(); return curr_dir; } else { for (curr_dir = 0; curr_dir < NUM_OF_DIRS; curr_dir++) { if (VALID_EDGE(queue_head->room, curr_dir)) { MARK(TOROOM(queue_head->room, curr_dir)); bfs_enqueue(TOROOM(queue_head->room, curr_dir), queue_head->dir); } } bfs_dequeue(); } } return BFS_NO_PATH; }
/* ******************************************************************** This routines sorts a[0] ... a[n-1] using the fact that in their common prefix, after offset characters, there is a suffix whose rank is known. In this routine we call this suffix anchor (and we denote its position and rank with anchor_pos and anchor_rank respectively) but it is not necessarily an anchor (=does not necessarily starts at position multiple of Anchor_dist) since this function is called by pseudo_anchor_sort(). The routine works by scanning the suffixes before and after the anchor in order to find (and mark) those which are suffixes of a[0] ... a[n-1]. After that, the ordering of a[0] ... a[n-1] is derived with a sigle scan of the marked suffixes. ******************************************************************** */ static void general_anchor_sort(Int32 *a, Int32 n, Int32 anchor_pos, Int32 anchor_rank, Int32 offset) { int integer_cmp(const void *, const void *); Int32 sb, lo, hi; Int32 curr_lo, curr_hi, to_be_found, i,j; Int32 item; void *ris; assert(Sa[anchor_rank]==anchor_pos); /* ---------- get bucket of anchor ---------- */ sb = Get_small_bucket(anchor_pos); lo = BUCKET_FIRST(sb); hi = BUCKET_LAST(sb); assert(sb==Get_small_bucket(a[0]+offset)); // ------ sort pointers a[0] ... a[n-1] as plain integers qsort(a,n, sizeof(Int32), integer_cmp); // ------------------------------------------------------------------ // now we scan the bucket containing the anchor in search of suffixes // corresponding to the ones we have to sort. When we find one of // such suffixes we mark it. We go on untill n sfx's have been marked // ------------------------------------------------------------------ curr_hi = curr_lo = anchor_rank; // the anchor must correspond to a suffix to be sorted #if DEBUG item = anchor_pos-offset; assert(bsearch(&item,a,n,sizeof(Int32), integer_cmp)); #endif MARK(curr_lo); // scan suffixes preceeding and following the anchor for(to_be_found=n-1;to_be_found>0; ) { // invariant: the next positions to check are curr_lo-1 and curr_hi+1 assert(curr_lo > lo || curr_hi < hi); while (curr_lo > lo) { item = Sa[--curr_lo]-offset; ris = bsearch(&item,a,n,sizeof(Int32), integer_cmp); if(ris) {MARK(curr_lo); to_be_found--;} else break; } while (curr_hi < hi) { item = Sa[++curr_hi]-offset; ris = bsearch(&item,a,n,sizeof(Int32), integer_cmp); if(ris) {MARK(curr_hi); to_be_found--;} else break; } } // sort a[] using the marked suffixes for(j=0, i=curr_lo;i<=curr_hi;i++) if(ISMARKED(i)) { UNMARK(i); a[j++] = Sa[i] - offset; } assert(j==n); // make sure n items have been sorted }
void clean_room_queue( void ) { BFS_DATA *curr, *curr_next; for( curr = room_queue; curr; curr = curr_next ) { UNMARK( curr->room ); curr_next = curr->next; free( curr ); } room_queue = NULL; }
/* * find_first_step: given a source room and a target room, find the first * step on the shortest path from the source to the target. * * Intended usage: in mobile_activity, give a mob a dir to go if they're * tracking another mob or a PC. Or, a 'track' skill for PCs. */ int find_first_step(room_rnum src, room_rnum target) { int curr_dir; room_rnum curr_room; if (src == NOWHERE || target == NOWHERE || src > top_of_world || target > top_of_world) { extended_mudlog(NRM, SYSL_BUGS, TRUE, "Illegal value %d or %d passed to find_first_step. (%s)", src, target, __FILE__); return (BFS_ERROR); } if (src == target) return (BFS_ALREADY_THERE); /* clear marks first, some OLC systems will save the mark. */ for (curr_room = 0; curr_room <= top_of_world; curr_room++) UNMARK(curr_room); MARK(src); /* first, enqueue the first steps, saving which direction we're going. */ for (curr_dir = 0; curr_dir < NUM_OF_DIRS; curr_dir++) if (VALID_EDGE(src, curr_dir)) { MARK(TOROOM(src, curr_dir)); bfs_enqueue(TOROOM(src, curr_dir), curr_dir); } /* now, do the classic BFS. */ while (queue_head) { if (queue_head->room == target) { curr_dir = queue_head->dir; bfs_clear_queue(); return (curr_dir); } else { for (curr_dir = 0; curr_dir < NUM_OF_DIRS; curr_dir++) if (VALID_EDGE(queue_head->room, curr_dir)) { MARK(TOROOM(queue_head->room, curr_dir)); bfs_enqueue(TOROOM(queue_head->room, curr_dir), queue_head->dir); } bfs_dequeue(); } } return (BFS_NO_PATH); }
/* * find_first_step: given a source room and a target room, find the first * step on the shortest path from the source to the target. * * Intended usage: in mobile_activity, give a mob a dir to go if they're * tracking another mob or a PC. Or, a 'track' skill for PCs. */ int find_first_step(room_rnum src, room_rnum target, CHAR_DATA * ch) { int curr_dir, edge, through_doors; room_rnum curr_room, rnum_start = FIRST_ROOM, rnum_stop = top_of_world; if (src < FIRST_ROOM || src > top_of_world || target < FIRST_ROOM || target > top_of_world) { log("SYSERR: Illegal value %d or %d passed to find_first_step. (%s)", src, target, __FILE__); return (BFS_ERROR); } if (src == target) return (BFS_ALREADY_THERE); // clear marks first, some OLC systems will save the mark. if (IS_NPC(ch)) { // Запрещаем искать мобам в другой зоне ... if (world[src]->zone != world[target]->zone) return (BFS_ERROR); get_zone_rooms(world[src]->zone, &rnum_start, &rnum_stop); // Запрещаем мобам искать через двери ... through_doors = FALSE; edge = EDGE_ZONE; } else { // Игроки полноценно ищут в мире. through_doors = TRUE; edge = EDGE_WORLD; } for (curr_room = rnum_start; curr_room <= rnum_stop; curr_room++) UNMARK(curr_room); MARK(src); // переписано на вектор без реального очищения, чтобы не заниматься сотнями аллокаций памяти в секунду зря -- Krodo static std::vector<bfs_queue_struct> bfs_queue; static struct bfs_queue_struct temp_queue; // first, enqueue the first steps, saving which direction we're going. for (curr_dir = 0; curr_dir < NUM_OF_DIRS; curr_dir++) if (VALID_EDGE(src, curr_dir, edge, through_doors)) { MARK(TOROOM(src, curr_dir)); temp_queue.room = TOROOM(src, curr_dir); temp_queue.dir = curr_dir; bfs_queue.push_back(temp_queue); } // now, do the classic BFS. for (unsigned int i = 0; i < bfs_queue.size(); ++i) { if (bfs_queue[i].room == target) { curr_dir = bfs_queue[i].dir; bfs_queue.clear(); return curr_dir; } else { for (curr_dir = 0; curr_dir < NUM_OF_DIRS; curr_dir++) { if (VALID_EDGE(bfs_queue[i].room, curr_dir, edge, through_doors)) { MARK(TOROOM(bfs_queue[i].room, curr_dir)); temp_queue.room = TOROOM(bfs_queue[i].room, curr_dir); temp_queue.dir = bfs_queue[i].dir; bfs_queue.push_back(temp_queue); } } } } bfs_queue.clear(); sprintf(buf, "Mob (mob: %s vnum: %d) can't find path.", GET_NAME(ch), GET_MOB_VNUM(ch)); mudlog(buf, NRM, -1, ERRLOG, TRUE); return (BFS_NO_PATH); }
int main(int argc, char **argv) { int c; char *progname; ingraph_state ig; Agraph_t *graph; Agnode_t *node; Agedge_t *edge; Agedge_t *nexte; Agsym_t *attr; char **files; generic_list_t *attr_list; generic_list_t *node_list; unsigned long i, j; opterr = 0; progname = strrchr(argv[0], '/'); if (progname == NULL) { progname = argv[0]; } else { progname++; /* character after last '/' */ } attr_list = new_generic_list(16); node_list = new_generic_list(16); while ((c = getopt(argc, argv, "hvn:N:")) != -1) { switch (c) { case 'N': { attr_list = addattr(attr_list, optarg); break; } case 'n': { node_list = addnode(node_list, optarg); break; } case 'h': { help_message(progname); exit(EXIT_SUCCESS); break; } case 'v': { verbose = 1; break; } case '?': if (isprint(optopt)) { fprintf(stderr, "Unknown option `-%c'.\n", optopt); } else { fprintf(stderr, "Unknown option character `\\x%X'.\n", optopt); } exit(EXIT_FAILURE); break; default: help_message(progname); exit(EXIT_FAILURE); break; } } /* Any arguments left? */ if (optind < argc) { files = &argv[optind]; } else { files = NULL; } newIngraph(&ig, files, gread); while ((graph = nextGraph(&ig)) != NULL) { if (agisdirected(graph) == 0) { fprintf(stderr, "*** Error: Graph is undirected! Pruning works only with directed graphs!\n"); exit(EXIT_FAILURE); } /* attach node data for marking to all nodes */ aginit(graph, AGNODE, NDNAME, sizeof(ndata), 1); /* prune all nodes specified on the commandline */ for (i = 0; i < node_list->used; i++) { if (verbose == 1) fprintf(stderr, "Pruning node %s\n", (char *) node_list->data[i]); /* check whether a node of that name exists at all */ node = agnode(graph, (char *) node_list->data[i], 0); if (node == NULL) { fprintf(stderr, "*** Warning: No such node: %s -- gracefully skipping this one\n", (char *) node_list->data[i]); } else { MARK(node); /* Avoid cycles */ /* Iterate over all outgoing edges */ for (edge = agfstout(node); edge; edge = nexte) { nexte = agnxtout(edge); if (aghead(edge) != node) { /* non-loop edges */ if (verbose == 1) fprintf(stderr, "Processing descendant: %s\n", agnameof(aghead(edge))); remove_child(graph, aghead(edge)); agdelete(graph, edge); } } UNMARK(node); /* Unmark so that it can be removed in later passes */ /* Change attribute (e.g. border style) to show that node has been pruneed */ for (j = 0; j < attr_list->used; j++) { /* create attribute if it doesn't exist and set it */ attr = agattr(graph, AGNODE, ((strattr_t *) attr_list->data[j])->n, ""); if (attr == NULL) { fprintf(stderr, "Couldn't create attribute: %s\n", ((strattr_t *) attr_list->data[j])->n); exit(EXIT_FAILURE); } agxset(node, attr, ((strattr_t *) attr_list->data[j])->v); } } } agwrite(graph, stdout); agclose(graph); } free(attr_list); free(node_list); exit(EXIT_SUCCESS); }