/**************************************************************************
* # # # ## # # ### ## ## ### http://www.lyonesse.it *
* # # # # # ## # # # # # *
* # # # # # ## ## # # ## ## ## # # ## *
* # # # # # ## # # # # # # # # # # # *
* ### # ## # # ### ## ## ### # # #### ## Ver. 1.0 *
* *
* -Based on CircleMud & Smaug- Copyright (c) 2001-2002 by Mithrandir *
* *
* ********************************************************************** */
/* ************************************************************************
* File: graph.c Part of CircleMUD *
* Usage: various graph algorithms *
* *
* All rights reserved. See license.doc for complete information. *
* *
* Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University *
* CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991. *
************************************************************************ */
#include "conf.h"
#include "sysdep.h"
#include "structs.h"
#include "utils.h"
#include "comm.h"
#include "interpreter.h"
#include "handler.h"
#include "db.h"
typedef struct bfs_queue_struct BFS_QUEUE;
struct bfs_queue_struct
{
BFS_QUEUE *next;
ROOM_DATA *room;
int dir;
};
#define MARK(room) (SET_BIT(ROOM_FLAGS(room), ROOM_BFS_MARK))
#define UNMARK(room) (REMOVE_BIT(ROOM_FLAGS(room), ROOM_BFS_MARK))
#define IS_MARKED(room) (ROOM_FLAGGED(room, ROOM_BFS_MARK))
/* external variables */
extern int track_through_doors;
/* local globals */
static BFS_QUEUE *queuehead = NULL;
static BFS_QUEUE *queuetail = NULL;
/* local functions */
EXIT_DATA *valid_edge(ROOM_DATA *pRoom, int dir);
int find_first_step(ROOM_DATA *src, ROOM_DATA *target);
void bfs_enqueue(ROOM_DATA *room, int dir);
void bfs_dequeue(void);
void bfs_clear_queue(void);
/* ============================================================== */
EXIT_DATA *valid_edge(ROOM_DATA *pRoom, int dir)
{
EXIT_DATA *pexit;
if (IS_WILD(pRoom))
return (NULL);
pexit = get_exit(pRoom, dir);
if ( pexit == NULL || pexit->to_room == NULL || IS_WILD(pexit->to_room) )
return (NULL);
if (track_through_doors == FALSE && EXIT_FLAGGED(pexit, EX_CLOSED))
return (NULL);
if (ROOM_FLAGGED(pexit->to_room, ROOM_NOTRACK) || IS_MARKED(pexit->to_room))
return (NULL);
return (pexit);
}
void bfs_enqueue(ROOM_DATA *room, int dir)
{
BFS_QUEUE *curr;
CREATE(curr, BFS_QUEUE, 1);
curr->next = NULL;
curr->room = room;
curr->dir = dir;
if (queuetail)
{
queuetail->next = curr;
queuetail = curr;
}
else
queuehead = queuetail = curr;
}
void bfs_dequeue(void)
{
BFS_QUEUE *curr;
curr = queuehead;
if (!(queuehead = queuehead->next))
queuetail = NULL;
free(curr);
}
void bfs_clear_queue(void)
{
while (queuehead)
bfs_dequeue();
}
/*
* 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_DATA *src, ROOM_DATA *target)
{
ROOM_DATA *pRoom;
EXIT_DATA *pexit;
int curr_dir, iHash;
if (!src || !target)
{
log("SYSERR: Illegal value %d or %d passed to find_first_step. (%s)", src->number, target->number, __FILE__);
return (BFS_ERROR);
}
if (src == target)
return (BFS_ALREADY_THERE);
/* clear marks first, some OLC systems will save the mark. */
for (iHash = 0; iHash < ROOM_HASH; iHash++)
{
for (pRoom = World[iHash]; pRoom; pRoom = pRoom->next)
UNMARK(pRoom);
}
MARK(src);
/* first, enqueue the first steps, saving which direction we're going. */
//for ( pexit = pRoom->first_exit; pexit; pexit->next )
for (curr_dir = 0; curr_dir < NUM_OF_EX_DIRS; curr_dir++)
{
if ((pexit = valid_edge(src, curr_dir)) != NULL)
{
MARK(pexit->to_room);
bfs_enqueue(pexit->to_room, curr_dir);
}
}
/* now, do the classic BFS. */
while (queuehead)
{
if (queuehead->room == target)
{
curr_dir = queuehead->dir;
bfs_clear_queue();
return (curr_dir);
}
else
{
for (curr_dir = 0; curr_dir < NUM_OF_EX_DIRS; curr_dir++)
{
if ((pexit = valid_edge(queuehead->room, curr_dir)) != NULL)
{
MARK(pexit->to_room);
bfs_enqueue(pexit->to_room, queuehead->dir);
}
}
bfs_dequeue();
}
}
return (BFS_NO_PATH);
}