]> git.pond.sub.org Git - empserver/blob - src/lib/as/as_cache.c
New path finder
[empserver] / src / lib / as / as_cache.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2010, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                           Ken Stevens, Steve McClure
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  *  ---
21  *
22  *  See files README, COPYING and CREDITS in the root of the source
23  *  tree for related information and legal notices.  It is expected
24  *  that future projects/authors will amend these files as needed.
25  *
26  *  ---
27  *
28  *  as_cache.c: Routines used to create/delete caches of A* paths.
29  *
30  *  Known contributors to this file:
31  *     Steve McClure, 1998
32  */
33
34 #include <config.h>
35
36 #include <stdlib.h>
37 #include <string.h>
38 #include "as.h"
39 #include "optlist.h"
40
41 /* The way this works is interesting. :) */
42 /* We keep a pointer to a list of pointers.  The index into this list
43  * is the y coordinate of the from sector.  This member points to a list
44  * of from sectors on that y coordinate.  So, we march that list checking
45  * the x value to find the from x,y we want. */
46 /* Once we find the from x,y, that node has the same type of pointer to
47  * a list of pointers.  The index into this list is the y coordinate of
48  * the to sector.  This member points to a list of to sectors on that y
49  * coordinate.  So, we march that list checking the x value to find the
50  * to x,y we want. */
51 /* These lists are dynamically created since the world is dynamically sized. */
52 /* See, I told you it was interesting. :) */
53
54 static struct as_frompath **fromhead = (struct as_frompath **)0;
55
56 /* Note that we only want to cache during updates.  Other times, it
57  * probably doesn't make much sense, but can be done. */
58
59 static int as_cachepath_on = 0; /* Default to off */
60
61 void
62 as_enable_cachepath(void)
63 {
64     as_cachepath_on = 1;
65 }
66
67 void
68 as_disable_cachepath(void)
69 {
70     as_cachepath_on = 0;
71 }
72
73 /* Note we want these to be as fast as possible */
74
75 void
76 as_add_cachepath(struct as_data *adp)
77 {
78     struct as_frompath *from;
79     struct as_topath *to = (struct as_topath *)0;
80     struct as_node *np;
81
82     /* Don't do anything if we aren't cacheing these */
83     if (as_cachepath_on == 0)
84         return;
85
86     /* Note we will only allocate this once.  Afterwards, we just keep
87      * zeroing it since it's rather small and we don't need to re-allocate
88      * each time. */
89     if (fromhead == NULL) {
90         fromhead = calloc(1, sizeof(struct as_frompath *) * WORLD_Y);
91         if (fromhead == NULL)
92             return;
93     }
94
95     np = adp->head->np;
96     for (from = fromhead[adp->from.y]; from; from = from->next)
97         if (from->x == adp->from.x)
98             break;
99     if (from) {
100         for (to = from->tolist[np->c.y]; to; to = to->next) {
101             if (to->x == np->c.x) {
102                 /* It is already here!  Don't bother adding it again */
103                 return;
104             }
105         }
106     } else {
107         /* We must make a new one of these */
108         from = malloc(sizeof(struct as_frompath));
109         if (from == NULL)
110             return;
111         /* And set some stuff */
112         from->x = adp->from.x;
113         /* Here we malloc a whole bunch of tolist pointers. */
114         from->tolist = calloc(1, sizeof(struct as_topath *) * WORLD_Y);
115         /* Now, add from to the global list */
116         from->next = fromhead[adp->from.y];
117         fromhead[adp->from.y] = from;
118     }
119     if (!to) {
120         /* We must make a new one */
121         to = malloc(sizeof(struct as_topath));
122         /* We can't, sorry */
123         if (to == NULL)
124             return;
125         /* Now set some stuff */
126         to->x = np->c.x;
127         /* Now add it to the list we are in */
128         to->next = from->tolist[np->c.y];
129         from->tolist[np->c.y] = to;
130     }
131     /* Now, make the path */
132     as_makepath(adp);
133     /* Now, take the path */
134     to->path = adp->path;
135     /* And clear the path in the adp */
136     adp->path = NULL;
137 }
138
139 void
140 as_clear_cachepath(void)
141 {
142     struct as_frompath *from, *from2;
143     struct as_topath *to, *to2;
144     int i, j;
145
146     /* Cache not used yet :) */
147     if (fromhead == NULL)
148         return;
149
150     for (j = 0; j < WORLD_Y; j++) {
151         for (from = fromhead[j]; from; from = from2) {
152             for (i = 0; i < WORLD_Y; i++) {
153                 for (to = from->tolist[i]; to; to = to2) {
154                     to2 = to->next;
155                     /* Free this path */
156                     as_free_path(to->path);
157                     /* Free this node */
158                     free(to);
159                 }
160             }
161             /* Now, free the list of lists */
162             free(from->tolist);
163             /* Save the next pointer */
164             from2 = from->next;
165             /* now, free this from node */
166             free(from);
167         }
168     }
169     /* Note we don't free the fromhead here, we just zero it.  That way,
170        we can use it next time without mallocing int */
171     memset(fromhead, 0, (sizeof(struct as_frompath *) * WORLD_Y));
172 }
173
174 struct as_path *
175 as_find_cachepath(coord fx, coord fy, coord tx, coord ty)
176 {
177     struct as_frompath *from;
178     struct as_topath *to;
179
180     /* Is the cache on?  if not, return NULL */
181     if (as_cachepath_on == 0)
182         return NULL;
183
184     /* Do we have any cached? */
185     if (fromhead == NULL)
186         return NULL;
187
188     /* Yes! */
189     for (from = fromhead[fy]; from; from = from->next) {
190         if (from->x == fx) {
191             for (to = from->tolist[ty]; to; to = to->next) {
192                 if (to->x == tx)
193                     return to->path;
194             }
195         }
196     }
197     return NULL;
198 }