ds3.0/bin/
ds3.0/extra/
ds3.0/extra/crat/
ds3.0/extra/creremote/
ds3.0/extra/mingw/
ds3.0/extra/wolfpaw/
ds3.0/fluffos-2.18-ds07/
ds3.0/fluffos-2.18-ds07/Win32/
ds3.0/fluffos-2.18-ds07/compat/
ds3.0/fluffos-2.18-ds07/compat/simuls/
ds3.0/fluffos-2.18-ds07/testsuite/
ds3.0/fluffos-2.18-ds07/testsuite/clone/
ds3.0/fluffos-2.18-ds07/testsuite/command/
ds3.0/fluffos-2.18-ds07/testsuite/data/
ds3.0/fluffos-2.18-ds07/testsuite/etc/
ds3.0/fluffos-2.18-ds07/testsuite/include/
ds3.0/fluffos-2.18-ds07/testsuite/inherit/
ds3.0/fluffos-2.18-ds07/testsuite/inherit/master/
ds3.0/fluffos-2.18-ds07/testsuite/log/
ds3.0/fluffos-2.18-ds07/testsuite/single/
ds3.0/fluffos-2.18-ds07/testsuite/single/tests/compiler/
ds3.0/fluffos-2.18-ds07/testsuite/single/tests/efuns/
ds3.0/fluffos-2.18-ds07/testsuite/single/tests/operators/
ds3.0/fluffos-2.18-ds07/testsuite/u/
ds3.0/fluffos-2.18-ds07/tmp/
ds3.0/lib/cmds/admins/
ds3.0/lib/cmds/common/
ds3.0/lib/cmds/creators/include/
ds3.0/lib/daemon/services/
ds3.0/lib/daemon/tmp/
ds3.0/lib/doc/
ds3.0/lib/doc/bguide/
ds3.0/lib/doc/efun/all/
ds3.0/lib/doc/efun/arrays/
ds3.0/lib/doc/efun/buffers/
ds3.0/lib/doc/efun/compile/
ds3.0/lib/doc/efun/floats/
ds3.0/lib/doc/efun/functions/
ds3.0/lib/doc/efun/mixed/
ds3.0/lib/doc/efun/numbers/
ds3.0/lib/doc/efun/parsing/
ds3.0/lib/doc/help/classes/
ds3.0/lib/doc/help/races/
ds3.0/lib/doc/lfun/
ds3.0/lib/doc/lfun/all/
ds3.0/lib/doc/lfun/lib/abilities/
ds3.0/lib/doc/lfun/lib/armor/
ds3.0/lib/doc/lfun/lib/bank/
ds3.0/lib/doc/lfun/lib/bot/
ds3.0/lib/doc/lfun/lib/clay/
ds3.0/lib/doc/lfun/lib/clean/
ds3.0/lib/doc/lfun/lib/clerk/
ds3.0/lib/doc/lfun/lib/client/
ds3.0/lib/doc/lfun/lib/combat/
ds3.0/lib/doc/lfun/lib/connect/
ds3.0/lib/doc/lfun/lib/container/
ds3.0/lib/doc/lfun/lib/corpse/
ds3.0/lib/doc/lfun/lib/creator/
ds3.0/lib/doc/lfun/lib/daemon/
ds3.0/lib/doc/lfun/lib/damage/
ds3.0/lib/doc/lfun/lib/deterioration/
ds3.0/lib/doc/lfun/lib/donate/
ds3.0/lib/doc/lfun/lib/door/
ds3.0/lib/doc/lfun/lib/equip/
ds3.0/lib/doc/lfun/lib/file/
ds3.0/lib/doc/lfun/lib/fish/
ds3.0/lib/doc/lfun/lib/fishing/
ds3.0/lib/doc/lfun/lib/flashlight/
ds3.0/lib/doc/lfun/lib/follow/
ds3.0/lib/doc/lfun/lib/ftp_client/
ds3.0/lib/doc/lfun/lib/ftp_data_connection/
ds3.0/lib/doc/lfun/lib/fuel/
ds3.0/lib/doc/lfun/lib/furnace/
ds3.0/lib/doc/lfun/lib/genetics/
ds3.0/lib/doc/lfun/lib/holder/
ds3.0/lib/doc/lfun/lib/id/
ds3.0/lib/doc/lfun/lib/interactive/
ds3.0/lib/doc/lfun/lib/lamp/
ds3.0/lib/doc/lfun/lib/leader/
ds3.0/lib/doc/lfun/lib/light/
ds3.0/lib/doc/lfun/lib/limb/
ds3.0/lib/doc/lfun/lib/living/
ds3.0/lib/doc/lfun/lib/load/
ds3.0/lib/doc/lfun/lib/look/
ds3.0/lib/doc/lfun/lib/manipulate/
ds3.0/lib/doc/lfun/lib/meal/
ds3.0/lib/doc/lfun/lib/messages/
ds3.0/lib/doc/lfun/lib/player/
ds3.0/lib/doc/lfun/lib/poison/
ds3.0/lib/doc/lfun/lib/position/
ds3.0/lib/doc/lfun/lib/post_office/
ds3.0/lib/doc/lfun/lib/potion/
ds3.0/lib/doc/lfun/lib/room/
ds3.0/lib/doc/lfun/lib/server/
ds3.0/lib/doc/lfun/lib/spell/
ds3.0/lib/doc/lfun/lib/torch/
ds3.0/lib/doc/lfun/lib/vendor/
ds3.0/lib/doc/lfun/lib/virt_sky/
ds3.0/lib/doc/lfun/lib/weapon/
ds3.0/lib/doc/lfun/lib/worn_storage/
ds3.0/lib/doc/lpc/constructs/
ds3.0/lib/doc/lpc/etc/
ds3.0/lib/doc/lpc/intermediate/
ds3.0/lib/doc/lpc/types/
ds3.0/lib/doc/misc/
ds3.0/lib/doc/old/
ds3.0/lib/doc/phints/
ds3.0/lib/domains/
ds3.0/lib/domains/Praxis/adm/
ds3.0/lib/domains/Praxis/attic/
ds3.0/lib/domains/Praxis/cemetery/mon/
ds3.0/lib/domains/Praxis/data/
ds3.0/lib/domains/Praxis/death/
ds3.0/lib/domains/Praxis/mountains/
ds3.0/lib/domains/Praxis/obj/armour/
ds3.0/lib/domains/Praxis/obj/magic/
ds3.0/lib/domains/Praxis/obj/weapon/
ds3.0/lib/domains/Praxis/orc_valley/
ds3.0/lib/domains/Ylsrim/
ds3.0/lib/domains/Ylsrim/adm/
ds3.0/lib/domains/Ylsrim/armor/
ds3.0/lib/domains/Ylsrim/broken/
ds3.0/lib/domains/Ylsrim/fish/
ds3.0/lib/domains/Ylsrim/meal/
ds3.0/lib/domains/Ylsrim/npc/
ds3.0/lib/domains/Ylsrim/obj/
ds3.0/lib/domains/Ylsrim/virtual/
ds3.0/lib/domains/Ylsrim/weapon/
ds3.0/lib/domains/campus/adm/
ds3.0/lib/domains/campus/chamber/
ds3.0/lib/domains/campus/etc/
ds3.0/lib/domains/campus/meals/
ds3.0/lib/domains/campus/txt/ai/charles/
ds3.0/lib/domains/campus/txt/ai/charles/bak2/
ds3.0/lib/domains/campus/txt/ai/charles/bak2/bak1/
ds3.0/lib/domains/campus/txt/ai/charly/
ds3.0/lib/domains/campus/txt/ai/charly/bak/
ds3.0/lib/domains/campus/txt/jenny/
ds3.0/lib/domains/cave/doors/
ds3.0/lib/domains/cave/etc/
ds3.0/lib/domains/cave/meals/
ds3.0/lib/domains/cave/weap/
ds3.0/lib/domains/default/chamber/
ds3.0/lib/domains/default/creator/
ds3.0/lib/domains/default/doors/
ds3.0/lib/domains/default/etc/
ds3.0/lib/domains/default/vehicle/
ds3.0/lib/domains/default/virtual/
ds3.0/lib/domains/town/save/
ds3.0/lib/domains/town/txt/shame/
ds3.0/lib/domains/town/virtual/
ds3.0/lib/domains/town/virtual/bottom/
ds3.0/lib/domains/town/virtual/space/
ds3.0/lib/estates/
ds3.0/lib/ftp/
ds3.0/lib/lib/comp/
ds3.0/lib/lib/daemons/
ds3.0/lib/lib/daemons/include/
ds3.0/lib/lib/lvs/
ds3.0/lib/lib/user/
ds3.0/lib/lib/virtual/
ds3.0/lib/log/
ds3.0/lib/log/adm/
ds3.0/lib/log/archive/
ds3.0/lib/log/chan/
ds3.0/lib/log/errors/
ds3.0/lib/log/law/adm/
ds3.0/lib/log/law/email/
ds3.0/lib/log/law/names/
ds3.0/lib/log/law/sites-misc/
ds3.0/lib/log/law/sites-register/
ds3.0/lib/log/law/sites-tempban/
ds3.0/lib/log/law/sites-watch/
ds3.0/lib/log/open/
ds3.0/lib/log/reports/
ds3.0/lib/log/router/
ds3.0/lib/log/secure/
ds3.0/lib/log/watch/
ds3.0/lib/obj/book_source/
ds3.0/lib/obj/include/
ds3.0/lib/powers/prayers/
ds3.0/lib/powers/spells/
ds3.0/lib/realms/template/
ds3.0/lib/realms/template/adm/
ds3.0/lib/realms/template/area/
ds3.0/lib/realms/template/area/armor/
ds3.0/lib/realms/template/area/npc/
ds3.0/lib/realms/template/area/obj/
ds3.0/lib/realms/template/area/room/
ds3.0/lib/realms/template/area/weap/
ds3.0/lib/realms/template/bak/
ds3.0/lib/realms/template/cmds/
ds3.0/lib/save/kills/o/
ds3.0/lib/secure/cfg/classes/
ds3.0/lib/secure/cmds/builders/
ds3.0/lib/secure/cmds/creators/include/
ds3.0/lib/secure/cmds/players/
ds3.0/lib/secure/cmds/players/include/
ds3.0/lib/secure/daemon/imc2server/
ds3.0/lib/secure/daemon/include/
ds3.0/lib/secure/lib/
ds3.0/lib/secure/lib/include/
ds3.0/lib/secure/lib/net/include/
ds3.0/lib/secure/lib/std/
ds3.0/lib/secure/log/adm/
ds3.0/lib/secure/log/bak/
ds3.0/lib/secure/log/intermud/
ds3.0/lib/secure/log/network/
ds3.0/lib/secure/modules/
ds3.0/lib/secure/npc/
ds3.0/lib/secure/obj/include/
ds3.0/lib/secure/room/
ds3.0/lib/secure/save/
ds3.0/lib/secure/save/backup/
ds3.0/lib/secure/save/boards/
ds3.0/lib/secure/save/players/g/
ds3.0/lib/secure/tmp/
ds3.0/lib/secure/upgrades/files/
ds3.0/lib/secure/verbs/creators/
ds3.0/lib/std/board/
ds3.0/lib/std/lib/
ds3.0/lib/verbs/admins/include/
ds3.0/lib/verbs/builders/
ds3.0/lib/verbs/common/
ds3.0/lib/verbs/common/include/
ds3.0/lib/verbs/creators/
ds3.0/lib/verbs/creators/include/
ds3.0/lib/verbs/rooms/
ds3.0/lib/verbs/rooms/include/
ds3.0/lib/www/client/
ds3.0/lib/www/errors/
ds3.0/lib/www/images/
ds3.0/win32/
/* Tricky */

#include <astar.h>

/* ([ mappos: ({ parent, x, y, g_cost, h_cost, f_cost }), ... ]) */
static mapping data;

/* ([ id: ([ "pos": mappos, "fcost": f ]), ... ]) */
static mapping binaryHeap;

/* Number of items on the binary heap. */
static int numItems;
static int maxItems;

static int l1, l2;

void initHeap()
{
    l1 = l2 = 0;
    maxItems = numItems = 0;
    binaryHeap = ([ ]);
}

int getHeadHeap() { return binaryHeap[1]["pos"]; }

#undef LOG_FIND

int findHeap(int d)
{
    int *nodes;
    int u, v, f;
    int lc, rc;

    /* Sanity check. */
    if(!numItems) return 0; /* Heap is empty, return 0. */

    if(member_array(d, keys(data)) == -1) return 0; /* Not come across this item before. */

    if(numItems == 1)
    {

        if(d == binaryHeap[1]["pos"]) return 1;

        return 0;
    }

    nodes = allocate(numItems + 1);
    nodes[0] = 1;

    f = data[d][AS_FCOST];
    v = 1;

    while (v <= numItems)
    {
        nodes[v]++;

        if(d == binaryHeap[v]["pos"]) break;

        u = v;
        rc = (lc = u << 1) + 1;

        if(nodes[u] < 3)
        {

            if(rc <= numItems)
            {

                if(nodes[u] == 1 && f >= binaryHeap[lc]["fcost"]) v = lc;
                else
                    if(f >= binaryHeap[rc]["fcost"])
                    {
                        nodes[u] = 2;
                        v = rc;
                    }

                nodes[0]++;
            }
            else
                if(nodes[u] == 1 && lc <= numItems)
                {

                    if(f >= binaryHeap[lc]["fcost"]) v = lc;

                    nodes[0]++;
                }

        }

        if(nodes[u] == 4)
        {
            v = 0;
            break;
        }

        if(u == v)
        {
            v >>= 1;

            if(!v) break;

        }

    }

    if(v > numItems) v = 0;

#ifdef LOG_FIND
    if(l1 < 64 && !v)
    {
        int i, dx;

        l1++;

        log_file("HEAP", sprintf("Finding %d(%d). Checks made: %d ... Not Found!\n", d, f, nodes[0]));
        /* log_file("HEAP", sprintf("binaryHeap = %O\nnodes = %O\n", binaryHeap, nodes)); */

        i = 1;

        while(i <= numItems)
        {
            string *tmp = ({ });
            string str = "";

            dx = (80.0 / (float)i);

            for(int j = i; j < i << 1; j++)
            {

                if(j <= numItems) tmp += ({ "|" });
                else tmp += ({ "" });

            }

            log_file("HEAP", sprintf("%@|"+dx+"s\n", tmp));

            tmp = ({ });
            tmp = allocate(i);

            for(int j = i; j < i << 1; j++)
            {

                if(j <= numItems)
                    tmp[j - i] = sprintf("%|"+(dx >> 1)+"'_'d", binaryHeap[j]["fcost"]);
                else tmp[j - i] = "";

            }

            i <<= 1;

            log_file("HEAP", sprintf("%@|"+dx+"s\n", tmp));
        }

        log_file("HEAP", "\n");
    }

    if(l2 < 64 && v && numItems > 7)
    {
        int i, dx;

        l2++;

        log_file("HEAP", sprintf("Finding %d(%d). Checks made: %d ... Result = %d\n", d, f, nodes[0], v));
        /* log_file("HEAP", sprintf("binaryHeap = %O\nnodes = %O\n", binaryHeap, nodes)); */

        i = 1;

        while(i <= numItems)
        {
            string *tmp = ({ });
            string str = "";

            dx = (80.0 / (float)i);

            for(int j = i; j < i << 1; j++)
            {

                if(j <= numItems) tmp += ({ "|" });
                else tmp += ({ "" });

            }

            log_file("HEAP", sprintf("%@|"+dx+"s\n", tmp));

            tmp = ({ });
            tmp = allocate(i);

            for(int j = i; j < i << 1; j++)
            {

                if(j <= numItems)
                {

                    if(j == v)
                        tmp[j - i] = sprintf("%|"+(dx >> 1)+"'_'s", "["+binaryHeap[j]["fcost"]+"]");
                    else
                        tmp[j - i] = sprintf("%|"+(dx >> 1)+"'_'d", binaryHeap[j]["fcost"]);

                }
                else tmp[j - i] = "";

            }

            i <<= 1;

            log_file("HEAP", sprintf("%@|"+dx+"s\n", tmp));
        }

        log_file("HEAP", "\n");
    }
#endif

    return v;
}

void resortHeapDown(int v)
{

    while(v <= numItems)
    {
        mapping parent, lchild, rchild;
        int u, lc, rc;

        u = v;

        rc = (lc = u << 1) + 1;

        parent = ([ ]) + binaryHeap[u];

        if(rc <= numItems)
        {
            lchild = ([ ]) + binaryHeap[lc];
            rchild = ([ ]) + binaryHeap[rc];

            if(parent["fcost"] > lchild["fcost"] &&
                    parent["fcost"] > rchild["fcost"])
            {

                if(lchild["fcost"] > rchild["fcost"]) v = rc;
                else v = lc;

            }
            else
                if(parent["fcost"] > lchild["fcost"]) v = lc;
                else
                    if(parent["fcost"] > rchild["fcost"]) v = rc;

        }
        else
            if(lc <= numItems)
            {

                if(parent["fcost"] > binaryHeap[lc]["fcost"]) v = lc;

            }

        if(u == v) break;

        binaryHeap[u] = ([ ]) + binaryHeap[v];
        binaryHeap[v] = ([ ]) + parent;
    }

}

void resortHeapUp(int m)
{
    mapping tmp;

    while(m > 1)
    {
        int m2 = m >> 1;

        if (binaryHeap[m]["fcost"] >= binaryHeap[m2]["fcost"]) break;

        tmp            = ([ ]) + binaryHeap[m];
        binaryHeap[m]  = ([ ]) + binaryHeap[m2];
        binaryHeap[m2] = ([ ]) + tmp;

        m = m2;
    }

}

void addHeap(int d)
{
    numItems++;

    if(numItems > maxItems) maxItems = numItems;

    binaryHeap[numItems] = ([ "pos": d, "fcost": data[d][AS_FCOST] ]);

    if(numItems > 1) resortHeapUp(numItems);

}

void removeHeadHeap()
{

    if(!numItems) return 0; /* Heap is empty, return 0. */

    /* Replace the head item with the tail item. */
    if(numItems > 1) binaryHeap[1] = ([ ]) + binaryHeap[numItems];

    /* Chop off the tail. */
    map_delete(binaryHeap, numItems);

    if(--numItems < 2) return;

    resortHeapDown(1);

    return;
}

int calc_h(int sx, int sy, int ex, int ey)
{
    int dx, dy;

    dx = sx - ex;
    dy = sy - ey;

    return (sqrt(dx * dx + dy * dy) * 0.975);

    /* Manhattan method. */
    /* return (abs(dx) + abs(dy)); */
}

string make_path(int start, int goal, int goalx, int goaly)
{
    mapping x_dir, y_dir;
    string *dirs;
    string path;
    int i, oldx, oldy, newx, newy;

    path = "";
    i = goal;
    oldx = goalx; oldy = goaly;
    x_dir = ([ -1: ({ 3, 4, 5 }), 0: ({ 2, 9, 6 }), 1: ({ 1, 0, 7 }) ]);
    y_dir = ([ -1: ({ 3, 2, 1 }), 0: ({ 4, 9, 0 }), 1: ({ 5, 6, 7 }) ]);
    dirs  = ({ "e", "ne", "n", "nw", "w", "sw", "s", "se", "*" });

    while(i != start)
    {
        int *xd, *yd;

        i    = data[i][AS_PARENT];
        newx = data[i][AS_X];
        newy = data[i][AS_Y];

        xd   = x_dir[oldx - newx];
        yd   = y_dir[oldy - newy];
        path = dirs[(xd & yd)[0]] + path;

        oldx = newx;
        oldy = newy;
    }

    return path;
}

mixed *find_path(string map, int startx, int starty, int goalx, int goaly, mapping costs)
{
    string *split_map;
    int *closed;
    int map_width, start, goal;
    int currpos;
    int newx, newy, newpos;
    int oldf, g, h;
    int id;

    /* Process the map into an easier-to-use format. */
    split_map = explode(map, "\n");
    map_width = 0;

    /* Find the length of the longest line in the "map" */
    for(int i = sizeof(split_map); i-- ;)
        if(map_width < strlen(split_map[i]))
            map_width = strlen(split_map[i]);

    /* Make all the lines that length by padding with escape characters.
     *      (Note: I use escapes because they are an unlikely character to be
     *           chosen for walking over, and unused characters are 'walls') */
    for(int i = sizeof(split_map); i-- ;)
        split_map[i] += sprintf("%" + (map_width - strlen(split_map[i])) + "'\27's", "");

    /* Sanity checks */
    if(goalx < 0  || goalx >= map_width || goaly < 0 || goaly >= sizeof(split_map))
        return ({ });

    if(member_array(split_map[starty][startx], keys(costs)) == -1 ||
            member_array(split_map[goaly][goalx], keys(costs)) == -1)
        return ({ });

    /* Setup initial state. */
    start = startx + starty * map_width;
    goal = goalx + goaly * map_width;

    data   = ([ ]);
    closed = ({ });

    g = 0;
    h = calc_h(startx, starty, goalx, goaly);
    write("Distance estimate: " + h + "\n");

    data[start] = ({ -1, startx, starty, g, h, g + h });

    /* Initialise the binary heap. */
    initHeap();
    addHeap(start);

    while(numItems && member_array(goal, closed) == -1)
    {
        currpos = getHeadHeap();
        closed += ({ currpos });
        removeHeadHeap();

        for(int ineighbour = 0; ineighbour < 8; ineighbour += 2)
        {
            newx = (currpos % map_width) + ({  1,  1,  0, -1, -1, -1,  0,  1 })[ineighbour];
            newy = (currpos / map_width) + ({  0, -1, -1, -1,  0,  1,  1,  1 })[ineighbour];

            /* Out of bounds, ignore it. */
            if(newx < 0 || newx >= map_width ||
                    newy < 0 || newy >= sizeof(split_map))
                continue;

            /* Solid wall, ignore it. */
            if(member_array(split_map[newy][newx], keys(costs)) == -1) continue;

            newpos = newy * map_width + newx;
            /* Already checked, ignore it. */
            if(member_array(newpos, closed) != -1) continue;

            g = data[currpos][AS_GCOST] + costs[split_map[newy][newx]];

            if(!(id = findHeap(newpos)))
            {
                h = calc_h(newx, newy, goalx, goaly);

                data[newpos] = allocate(AS_DATA_SZ);
                data[newpos][AS_PARENT] = currpos;
                data[newpos][AS_X]      = newx;
                data[newpos][AS_Y]      = newy;
                data[newpos][AS_GCOST]  = g;
                data[newpos][AS_HCOST]  = h;
                data[newpos][AS_FCOST]  = g + h;

                addHeap(newpos);
            }
            else
            {

                if(g < data[newpos][AS_GCOST])
                {
                    oldf = data[newpos][AS_FCOST];

                    h = calc_h(newx, newy, goalx, goaly);

                    data[newpos][AS_PARENT] = currpos;
                    data[newpos][AS_X]      = newx;
                    data[newpos][AS_Y]      = newy;
                    data[newpos][AS_GCOST]  = g;
                    data[newpos][AS_HCOST]  = h;
                    data[newpos][AS_FCOST]  = g + h;

                    if(g + h != oldf)
                    {
                        binaryHeap[id]["fcost"] = g + h;

                        if(g + h < oldf) resortHeapUp(id);
                        else
                            if(g + h > oldf) resortHeapDown(id);

                    }

                }

            }

        }

    }

    write("Maximum binary heap size: " + maxItems + "\n");

    if(member_array(goal, closed) == -1) return ({ });

    return ({ make_path(start, goal, goalx, goaly), data });
}