src/lib/as/as_cache.c

Go to the documentation of this file.
00001 /*
00002  *  Empire - A multi-player, client/server Internet based war game.
00003  *  Copyright (C) 1986-2007, Dave Pare, Jeff Bailey, Thomas Ruschak,
00004  *                           Ken Stevens, Steve McClure
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; either version 2 of the License, or
00009  *  (at your option) any later version.
00010  *
00011  *  This program is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *  GNU General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU General Public License
00017  *  along with this program; if not, write to the Free Software
00018  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  *
00020  *  ---
00021  *
00022  *  See files README, COPYING and CREDITS in the root of the source
00023  *  tree for related information and legal notices.  It is expected
00024  *  that future projects/authors will amend these files as needed.
00025  *
00026  *  ---
00027  *
00028  *  as_cache.c: Routines used to create/delete caches of A* paths.
00029  *
00030  *  Known contributors to this file:
00031  *     Steve McClure, 1998
00032  */
00033 
00034 #include <config.h>
00035 
00036 #include <stdlib.h>
00037 #include <string.h>
00038 #include "as.h"
00039 #include "optlist.h"
00040 
00041 /* The way this works is interesting. :) */
00042 /* We keep a pointer to a list of pointers.  The index into this list
00043  * is the y coordinate of the from sector.  This member points to a list
00044  * of from sectors on that y coordinate.  So, we march that list checking
00045  * the x value to find the from x,y we want. */
00046 /* Once we find the from x,y, that node has the same type of pointer to
00047  * a list of pointers.  The index into this list is the y coordinate of
00048  * the to sector.  This member points to a list of to sectors on that y
00049  * coordinate.  So, we march that list checking the x value to find the
00050  * to x,y we want. */
00051 /* These lists are dynamically created since the world is dynamically sized. */
00052 /* See, I told you it was interesting. :) */
00053 
00054 static struct as_frompath **fromhead = (struct as_frompath **)0;
00055 
00056 /* Note that we only want to cache during updates.  Other times, it
00057  * probably doesn't make much sense, but can be done. */
00058 
00059 static int as_cachepath_on = 0; /* Default to off */
00060 
00061 void
00062 as_enable_cachepath(void)
00063 {
00064     as_cachepath_on = 1;
00065 }
00066 
00067 void
00068 as_disable_cachepath(void)
00069 {
00070     as_cachepath_on = 0;
00071 }
00072 
00073 /* Note we want these to be as fast as possible */
00074 
00075 void
00076 as_add_cachepath(struct as_data *adp)
00077 {
00078     struct as_frompath *from;
00079     struct as_topath *to = (struct as_topath *)0;
00080     struct as_node *np;
00081 
00082     /* Don't do anything if we aren't cacheing these */
00083     if (as_cachepath_on == 0)
00084         return;
00085 
00086     /* Note we will only allocate this once.  Afterwards, we just keep
00087      * zeroing it since it's rather small and we don't need to re-allocate
00088      * each time. */
00089     if (fromhead == NULL) {
00090         fromhead = calloc(1, sizeof(struct as_frompath *) * WORLD_Y);
00091         if (fromhead == NULL)
00092             return;
00093     }
00094 
00095     np = adp->head->np;
00096     for (from = fromhead[adp->from.y]; from; from = from->next)
00097         if (from->x == adp->from.x)
00098             break;
00099     if (from) {
00100         for (to = from->tolist[np->c.y]; to; to = to->next) {
00101             if (to->x == np->c.x) {
00102                 /* It is already here!  Don't bother adding it again */
00103                 return;
00104             }
00105         }
00106     } else {
00107         /* We must make a new one of these */
00108         from = malloc(sizeof(struct as_frompath));
00109         if (from == NULL)
00110             return;
00111         /* And set some stuff */
00112         from->x = adp->from.x;
00113         /* Here we malloc a whole bunch of tolist pointers. */
00114         from->tolist = calloc(1, sizeof(struct as_topath *) * WORLD_Y);
00115         /* Now, add from to the global list */
00116         from->next = fromhead[adp->from.y];
00117         fromhead[adp->from.y] = from;
00118     }
00119     if (!to) {
00120         /* We must make a new one */
00121         to = malloc(sizeof(struct as_topath));
00122         /* We can't, sorry */
00123         if (to == NULL)
00124             return;
00125         /* Now set some stuff */
00126         to->x = np->c.x;
00127         /* Now add it to the list we are in */
00128         to->next = from->tolist[np->c.y];
00129         from->tolist[np->c.y] = to;
00130     }
00131     /* Now, make the path */
00132     as_makepath(adp);
00133     /* Now, take the path */
00134     to->path = adp->path;
00135     /* And clear the path in the adp */
00136     adp->path = NULL;
00137 }
00138 
00139 void
00140 as_clear_cachepath(void)
00141 {
00142     struct as_frompath *from, *from2;
00143     struct as_topath *to, *to2;
00144     int i, j;
00145 
00146     /* Cache not used yet :) */
00147     if (fromhead == NULL)
00148         return;
00149 
00150     for (j = 0; j < WORLD_Y; j++) {
00151         for (from = fromhead[j]; from; from = from2) {
00152             for (i = 0; i < WORLD_Y; i++) {
00153                 for (to = from->tolist[i]; to; to = to2) {
00154                     to2 = to->next;
00155                     /* Free this path */
00156                     as_free_path(to->path);
00157                     /* Free this node */
00158                     free(to);
00159                 }
00160             }
00161             /* Now, free the list of lists */
00162             free(from->tolist);
00163             /* Save the next pointer */
00164             from2 = from->next;
00165             /* now, free this from node */
00166             free(from);
00167         }
00168     }
00169     /* Note we don't free the fromhead here, we just zero it.  That way,
00170        we can use it next time without mallocing int */
00171     memset(fromhead, 0, (sizeof(struct as_frompath *) * WORLD_Y));
00172 }
00173 
00174 struct as_path *
00175 as_find_cachepath(coord fx, coord fy, coord tx, coord ty)
00176 {
00177     struct as_frompath *from;
00178     struct as_topath *to;
00179 
00180     /* Is the cache on?  if not, return NULL */
00181     if (as_cachepath_on == 0)
00182         return NULL;
00183 
00184     /* Do we have any cached? */
00185     if (fromhead == NULL)
00186         return NULL;
00187 
00188     /* Yes! */
00189     for (from = fromhead[fy]; from; from = from->next) {
00190         if (from->x == fx) {
00191             for (to = from->tolist[ty]; to; to = to->next) {
00192                 if (to->x == tx)
00193                     return to->path;
00194             }
00195         }
00196     }
00197     return NULL;
00198 }

Generated on Fri Mar 28 11:01:11 2008 for empserver by  doxygen 1.5.2