~ubuntu-branches/debian/squeeze/freeciv/squeeze

« back to all changes in this revision

Viewing changes to server/airgoto.c

  • Committer: Bazaar Package Importer
  • Author(s): Clint Adams, Karl Goetz, Clint Adams
  • Date: 2010-02-23 22:09:02 UTC
  • mfrom: (1.2.13 upstream)
  • Revision ID: james.westby@ubuntu.com-20100223220902-kiyrmr9i4152cka5
Tags: 2.2.0-1
[ Karl Goetz ]
* Remove civserver files in /etc/ggzd/ (Closes: 523772, 517787)
* Adding ${misc:Depends} to all binary packages (lintian warnings)

[ Clint Adams ]
* New upstream version.
  - Drop data_dsc_use_bindir.diff (binary pathnames have changed).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/********************************************************************** 
2
 
 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3
 
   This program is free software; you can redistribute it and/or modify
4
 
   it under the terms of the GNU General Public License as published by
5
 
   the Free Software Foundation; either version 2, or (at your option)
6
 
   any later version.
7
 
 
8
 
   This program is distributed in the hope that it will be useful,
9
 
   but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
 
   GNU General Public License for more details.
12
 
***********************************************************************/
13
 
 
14
 
#ifdef HAVE_CONFIG_H
15
 
#include <config.h>
16
 
#endif
17
 
 
18
 
#include "log.h"
19
 
#include "map.h"
20
 
#include "mem.h"
21
 
#include "movement.h"
22
 
#include "pqueue.h"
23
 
 
24
 
#include "gotohand.h"
25
 
 
26
 
#include "airgoto.h"
27
 
 
28
 
/* These are used for airplane GOTOs with waypoints */
29
 
#define MAXFUEL 100
30
 
/* Only used in the priority function for the queue */
31
 
#define MAX_FLIGHT 256
32
 
 
33
 
/* Type of refuel point */
34
 
enum refuel_type {
35
 
  FUEL_START = 0, FUEL_GOAL, FUEL_CITY, FUEL_AIRBASE
36
 
};
37
 
 
38
 
/* Is this refuel point listed in the queue? */
39
 
enum refuel_list_status {
40
 
  RLS_NOT_YET, RLS_YES, RLS_ALREADY_NOT
41
 
};
42
 
 
43
 
struct refuel {
44
 
  enum refuel_type type;
45
 
  enum refuel_list_status listed;
46
 
  struct tile *tile;
47
 
  int turns;
48
 
  int moves_left;
49
 
  struct refuel *coming_from;
50
 
};
51
 
 
52
 
#define ALLOC_STEP 20
53
 
static struct player_refuel_list {
54
 
  struct refuel *points;
55
 
  /* Size of the actual list */
56
 
  unsigned int list_size;
57
 
  /* Size of the allocated memory in points */
58
 
  unsigned int alloc_size;
59
 
  /* It is convenient to hold additional info here */
60
 
  struct player *pplayer;
61
 
  struct unit *punit;
62
 
  int max_moves;
63
 
  int moves_per_turn;
64
 
} refuels;
65
 
 
66
 
static void make_list_of_refuel_points(struct player *pplayer, 
67
 
                                       bool cities_only, 
68
 
                                       int moves_per_turn, int max_moves);
69
 
 
70
 
 
71
 
/*---------------- Refuel Points C/D and access --------------------------*/
72
 
/******************************************************************
73
 
 * Access function for struct refuel
74
 
 *****************************************************************/
75
 
struct tile *get_refuel_tile(struct refuel *point)
76
 
{
77
 
  return point->tile;
78
 
}
79
 
 
80
 
/******************************************************************
81
 
 * Access function for struct refuel
82
 
 *****************************************************************/
83
 
unsigned int get_turns_to_refuel(struct refuel *point)
84
 
{
85
 
  return point->turns;
86
 
}
87
 
 
88
 
/*------------------- End of Refuel Point C/D and Access ---------------*/
89
 
 
90
 
 
91
 
/*------------------- Refuel Point List Handling -----------------------*/
92
 
/******************************************************************
93
 
 * Add new refuel point to the (static) refuel point list.
94
 
 * If the last argument start is TRUE, the point will be written at
95
 
 * the head of the list.
96
 
 *****************************************************************/
97
 
static void add_refuel_point(struct tile *ptile, 
98
 
                             enum refuel_type type, int turns, 
99
 
                             int moves_left, bool start)
100
 
{
101
 
  int pos;
102
 
 
103
 
  if (start) {
104
 
    pos = 0;
105
 
  } else {
106
 
    pos = refuels.list_size;
107
 
    refuels.list_size++;
108
 
  }
109
 
 
110
 
  if (pos +1 > refuels.alloc_size) {
111
 
    refuels.alloc_size += ALLOC_STEP;
112
 
    /* If refuels.alloc_size was zero (on the first call), 
113
 
     * then refuels.points is NULL and realloc will actually malloc */
114
 
    refuels.points = fc_realloc(refuels.points, 
115
 
                                refuels.alloc_size * sizeof(*refuels.points));
116
 
    /* This memory, because refuels is static, is never freed.
117
 
     * It is just reused. */  
118
 
  }
119
 
  
120
 
  /* Fill the new point in */
121
 
  refuels.points[pos].tile = ptile;
122
 
  refuels.points[pos].type = type;
123
 
  refuels.points[pos].listed = RLS_NOT_YET;
124
 
  refuels.points[pos].turns = turns;
125
 
  refuels.points[pos].moves_left = moves_left;
126
 
  refuels.points[pos].coming_from = NULL;
127
 
 
128
 
  return;
129
 
}
130
 
 
131
 
/******************************************************************
132
 
 * Wrapper to refuel point access.  Checks range too.
133
 
 ******************************************************************/
134
 
static struct refuel *get_refuel_by_index(int i)
135
 
{
136
 
  if (i < 0 || i >= refuels.list_size) {
137
 
    return NULL;
138
 
  }
139
 
 
140
 
  return &refuels.points[i];
141
 
}
142
 
 
143
 
/*************************************************************************
144
 
This list should probably be made by having a list of airbase and then
145
 
adding the players cities. It takes a little time to iterate over the map
146
 
as it is now, but as it is only used in the players turn that does not
147
 
matter.
148
 
Can probably do some caching...
149
 
*************************************************************************/
150
 
static void make_list_of_refuel_points(struct player *pplayer, 
151
 
                                       bool cities_only, 
152
 
                                       int moves_per_turn, 
153
 
                                       int max_moves)
154
 
{
155
 
  refuels.list_size = 1;
156
 
  refuels.pplayer = pplayer;
157
 
  refuels.moves_per_turn = moves_per_turn;
158
 
  refuels.max_moves = max_moves;
159
 
 
160
 
  whole_map_iterate(ptile) {
161
 
    if (is_allied_city_tile(ptile, pplayer)
162
 
        && !is_non_allied_unit_tile(ptile, pplayer) ) {
163
 
      add_refuel_point(ptile, FUEL_CITY, 
164
 
                       MAP_MAX_HEIGHT + MAP_MAX_WIDTH, 0, FALSE);
165
 
    } else if (tile_has_special(ptile, S_AIRBASE)
166
 
               && !is_non_allied_unit_tile(ptile, pplayer)
167
 
               && !cities_only) {
168
 
      add_refuel_point(ptile, FUEL_AIRBASE, 
169
 
                       MAP_MAX_HEIGHT + MAP_MAX_WIDTH, 0, FALSE);
170
 
    }
171
 
  } whole_map_iterate_end;
172
 
}
173
 
 
174
 
/*************************************************************************
175
 
 * Priority function for refuel points --- on the basis of their 
176
 
 * turn-distance from the starting point
177
 
 ************************************************************************/
178
 
static int queue_priority_function(const void *value)
179
 
{
180
 
  const struct refuel *point = (const struct refuel *) value;
181
 
 
182
 
  return -(MAX_FLIGHT * point->turns - point->moves_left);
183
 
}
184
 
 
185
 
/*----------------- End of Refuel Point List Handling -----------------*/
186
 
 
187
 
 
188
 
/*----------------- Refuel Point List Iterators -----------------------*/
189
 
 
190
 
/*************************************************************************
191
 
 * initialize air-map iterate
192
 
 * Args: (x,y) -- starting point
193
 
 * (dest_x, dest_y) -- proposed destination ( or repeat x,y if none)
194
 
 * cities_only -- will not consider airbases outside cities
195
 
 * moves_left -- moves left
196
 
 * moves_per_turn -- max moves per turn
197
 
 * max_fuel -- max fuel
198
 
 ************************************************************************/
199
 
struct pqueue *refuel_iterate_init(struct player *pplayer,
200
 
                                   struct tile *ptile,
201
 
                                   struct tile *dest_tile,
202
 
                                   bool cities_only, int moves_left, 
203
 
                                   int moves_per_turn, int max_fuel)
204
 
{
205
 
  struct refuel *tmp;   
206
 
  struct pqueue *rp_queue = pq_create(MAP_MAX_WIDTH);
207
 
  short index;
208
 
 
209
 
  /* List of all refuel points of the player!  
210
 
   * TODO: Should cache the results */
211
 
  make_list_of_refuel_points(pplayer, cities_only, 
212
 
                             moves_per_turn, moves_per_turn * max_fuel);
213
 
  /* Add the starting point: we keep it for later backtracking */
214
 
  add_refuel_point(ptile, FUEL_START, 0, moves_left, TRUE);
215
 
 
216
 
  if (!same_pos(ptile, dest_tile)) {
217
 
    add_refuel_point(dest_tile, FUEL_GOAL, 
218
 
                     MAP_MAX_HEIGHT + MAP_MAX_WIDTH, 0, FALSE);
219
 
  }
220
 
 
221
 
  /* Process the starting point, no need to queue it
222
 
   * Note: starting position is in the head of refuels list */
223
 
  refuel_iterate_process(rp_queue, get_refuel_by_index(0));
224
 
 
225
 
  index = -1;
226
 
  (void) pq_peek(rp_queue, &index);
227
 
  tmp = get_refuel_by_index(index);
228
 
 
229
 
  if (tmp && same_pos(ptile, tmp->tile)) {
230
 
    /* We should get the starting point twice 
231
 
     * in case we start on less than full fuel */
232
 
    pq_remove(rp_queue, NULL);
233
 
    refuel_iterate_process(rp_queue, tmp);
234
 
  }
235
 
 
236
 
  return rp_queue;
237
 
}
238
 
 
239
 
/*************************************************************************
240
 
 * Get the next refuel point (wrt the turn-distance from the starting 
241
 
 * point).  Sort out the points that are already processed.
242
 
 ************************************************************************/
243
 
struct refuel *refuel_iterate_next(struct pqueue *rp_list)
244
 
{
245
 
  struct refuel *next_point;
246
 
 
247
 
  /* Get the next nearest point from the queue
248
 
   * (ignoring already processed ones) */
249
 
  do {
250
 
    short int index = -1;
251
 
 
252
 
    (void) pq_remove(rp_list, &index);
253
 
 
254
 
    next_point = get_refuel_by_index(index);
255
 
  } while(next_point != NULL && next_point->listed == RLS_ALREADY_NOT);
256
 
 
257
 
 
258
 
  if (next_point != NULL) {
259
 
    /* Mark as processed */
260
 
    next_point->listed = RLS_ALREADY_NOT;
261
 
  }
262
 
 
263
 
  return next_point;
264
 
}
265
 
 
266
 
/*************************************************************************
267
 
 * Process next refuel point: find all points we can reach from pfrom,
268
 
 * see if the new path is better than already existing one, add new 
269
 
 * reachable points to the priority queue.
270
 
 ************************************************************************/
271
 
void refuel_iterate_process(struct pqueue *rp_list, struct refuel *pfrom)
272
 
{
273
 
  int k;
274
 
  int max_moves 
275
 
    = (pfrom->type == FUEL_START ? pfrom->moves_left : refuels.max_moves);
276
 
 
277
 
  /* Iteration starts from 1, since 0 is occupied by the start point */
278
 
  for (k = 1; k < refuels.list_size; k++) {
279
 
    struct refuel *pto = get_refuel_by_index(k);
280
 
    int moves_left 
281
 
      = air_can_move_between(max_moves, 
282
 
                             pfrom->tile, pto->tile, 
283
 
                             refuels.pplayer);
284
 
    if (moves_left != -1) {
285
 
      int moves_used = max_moves - moves_left;
286
 
      /* Turns used on this flight (for units with fuel > 1) */
287
 
      int turns_used 
288
 
        = 1 + ((moves_used == 0 ? 0 : moves_used - 1) 
289
 
               / refuels.moves_per_turn);
290
 
      /* Total turns to get from the start to the pto refuelling point */
291
 
      int total_turns = pfrom->turns + turns_used;
292
 
 
293
 
      freelog(LOG_DEBUG, "Considering: (%i,%i)->(%i,%i), in (%d %d)",
294
 
              pfrom->tile->x, pfrom->tile->y, pto->tile->x, pto->tile->y, 
295
 
              total_turns, moves_left);
296
 
      freelog(LOG_DEBUG, "\t\t compared to (%d %d)", 
297
 
              pto->turns, pto->moves_left);
298
 
 
299
 
      if ( (pto->turns > total_turns) 
300
 
           || ((pto->turns == total_turns) 
301
 
               && (moves_left > pto->moves_left)) ) {
302
 
        /* Found a new refuelling point or at least a new route */
303
 
        if (pto->listed == RLS_ALREADY_NOT) {
304
 
          freelog(LOG_ERROR, "Found a shorter route to a node: (%i,%i)", 
305
 
                  pto->tile->x, pto->tile->y);
306
 
          assert(FALSE);
307
 
        }
308
 
        /* Update the info on pto */
309
 
        pto->coming_from = pfrom;
310
 
        pto->moves_left = moves_left;
311
 
        pto->turns = total_turns;
312
 
        
313
 
        /* Insert it into the queue.  No problem if it's already there */
314
 
        pq_insert(rp_list, k, queue_priority_function(pto));
315
 
        pto->listed = RLS_YES;
316
 
        
317
 
        freelog(LOG_DEBUG, "Recorded (%i,%i) from (%i,%i) in (%d %d)", 
318
 
                pto->tile->x, pto->tile->y, pfrom->tile->x, pfrom->tile->y, 
319
 
                total_turns, moves_left);
320
 
      }
321
 
    }
322
 
  }
323
 
}
324
 
 
325
 
/*************************************************************************
326
 
 * Clean up
327
 
 ************************************************************************/
328
 
void refuel_iterate_end(struct pqueue *rp_list)
329
 
{
330
 
  /* No need to free memory allocated for the refuels list 
331
 
   * -- it will be reused */
332
 
 
333
 
  /* Just destroy the queue */
334
 
  pq_destroy(rp_list);
335
 
}
336
 
 
337
 
/*----------------- End of Refuel Point List Iterators -------------------*/
338
 
 
339
 
 
340
 
/*----------------- Air Goto Standard Functions --------------------------*/
341
 
 
342
 
/************************************************************************
343
 
 * We need to find a route that our airplane can use without crashing. The
344
 
 * first waypoint of this route is returned inside the arguments dest_x and
345
 
 * dest_y. This can be the point where we start, fx when a plane with few 
346
 
 * moves left need to stay in a city to refuel.
347
 
 *
348
 
 * This is achieved by a simple use of refuel_iterate and then backtracking.
349
 
 *
350
 
 * The path chosen will be such that upon arrival the unit will have maximal 
351
 
 * moves left (among the paths that get to dest in minimal number of moves).
352
 
 *
353
 
 * Possible changes:
354
 
 * We might also make sure that fx a fighter will have enough fuel to fly back
355
 
 * to a base after reaching it's destination. This could be done by making a
356
 
 * list of goal from which the last jump on the route could be done
357
 
 * satisfactory. We should also make sure that bombers given an order to
358
 
 * attack a unit will not make the attack on it's last fuel point etc. etc.
359
 
 ***********************************************************************/
360
 
bool find_air_first_destination(struct unit *punit, struct tile **dest_tile)
361
 
362
 
  unsigned int fullmoves = unit_move_rate(punit) / SINGLE_MOVE;
363
 
  unsigned int fullfuel = unit_type(punit)->fuel;
364
 
  unsigned int moves_and_fuel_left 
365
 
    = punit->moves_left / SINGLE_MOVE + fullmoves * (punit->fuel - 1);
366
 
  struct pqueue *my_list 
367
 
    = refuel_iterate_init(unit_owner(punit), punit->tile, 
368
 
                          *dest_tile, FALSE, 
369
 
                          moves_and_fuel_left, fullmoves, fullfuel);
370
 
  struct refuel *next_point;
371
 
  bool reached_goal = FALSE;
372
 
 
373
 
  while((next_point = refuel_iterate_next(my_list)) != NULL) {
374
 
    freelog(LOG_DEBUG, "Next point (%d, %d), priority %d", 
375
 
            next_point->tile->x, next_point->tile->y,
376
 
            queue_priority_function(next_point));
377
 
    if (next_point -> type == FUEL_GOAL) {
378
 
      /* Found a route! */
379
 
      reached_goal = TRUE;
380
 
      break;
381
 
    }
382
 
    refuel_iterate_process(my_list, next_point);
383
 
  }
384
 
 
385
 
  if (reached_goal) {
386
 
    struct refuel *backtrack = next_point;
387
 
    while (backtrack->coming_from->type != FUEL_START) {
388
 
      backtrack = backtrack->coming_from;
389
 
      freelog(LOG_DEBUG, "(%i,%i) ->",
390
 
              backtrack->tile->x, backtrack->tile->y);
391
 
    }
392
 
    freelog(LOG_DEBUG, "Found a route!");
393
 
    *dest_tile = backtrack->tile;
394
 
  } else {
395
 
    freelog(LOG_DEBUG, "Didn't find a route...");
396
 
  }
397
 
  refuel_iterate_end(my_list);
398
 
 
399
 
  return reached_goal;
400
 
}
401
 
 
402
 
 
403
 
/*----------------- End of Air Goto Standard Functions ------------------*/