[BACK]Return to Dijkstra.c CVS log [TXT][DIR] Up to [contributed] / brogue-ce / src / brogue

Annotation of brogue-ce/src/brogue/Dijkstra.c, Revision 1.1.1.1

1.1       rubenllo    1: /*
                      2:  *  Dijkstra.c
                      3:  *  Brogue
                      4:  *
                      5:  *  Copyright 2012. All rights reserved.
                      6:  *
                      7:  *  This file is part of Brogue.
                      8:  *
                      9:  *  This program is free software: you can redistribute it and/or modify
                     10:  *  it under the terms of the GNU Affero General Public License as
                     11:  *  published by the Free Software Foundation, either version 3 of the
                     12:  *  License, or (at your option) any later version.
                     13:  *
                     14:  *  This program is distributed in the hope that it will be useful,
                     15:  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
                     16:  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     17:  *  GNU Affero General Public License for more details.
                     18:  *
                     19:  *  You should have received a copy of the GNU Affero General Public License
                     20:  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
                     21:  */
                     22:
                     23: // This code was created by Joshua Day, to replace my clunkier and slower Dijkstra scanning algorithm in Movement.c.
                     24: // Thanks very much, Joshua.
                     25:
                     26: #include "Rogue.h"
                     27: #include "IncludeGlobals.h"
                     28:
                     29: struct pdsLink {
                     30:     short distance;
                     31:     short cost;
                     32:     pdsLink *left, *right;
                     33: };
                     34:
                     35: struct pdsMap {
                     36:     boolean eightWays;
                     37:
                     38:     pdsLink front;
                     39:     pdsLink links[DCOLS * DROWS];
                     40: };
                     41:
                     42: void pdsUpdate(pdsMap *map) {
                     43:     short dir, dirs;
                     44:     pdsLink *left = NULL, *right = NULL, *link = NULL;
                     45:
                     46:     dirs = map->eightWays ? 8 : 4;
                     47:
                     48:     pdsLink *head = map->front.right;
                     49:     map->front.right = NULL;
                     50:
                     51:     while (head != NULL) {
                     52:         for (dir = 0; dir < dirs; dir++) {
                     53:             link = head + (nbDirs[dir][0] + DCOLS * nbDirs[dir][1]);
                     54:             if (link < map->links || link >= map->links + DCOLS * DROWS) continue;
                     55:
                     56:             // verify passability
                     57:             if (link->cost < 0) continue;
                     58:             if (dir >= 4) {
                     59:                 pdsLink *way1, *way2;
                     60:                 way1 = head + nbDirs[dir][0];
                     61:                 way2 = head + DCOLS * nbDirs[dir][1];
                     62:                 if (way1->cost == PDS_OBSTRUCTION || way2->cost == PDS_OBSTRUCTION) continue;
                     63:             }
                     64:
                     65:             if (head->distance + link->cost < link->distance) {
                     66:                 link->distance = head->distance + link->cost;
                     67:
                     68:                 // reinsert the touched cell; it'll be close to the beginning of the list now, so
                     69:                 // this will be very fast.  start by removing it.
                     70:
                     71:                 if (link->right != NULL) link->right->left = link->left;
                     72:                 if (link->left != NULL) link->left->right = link->right;
                     73:
                     74:                 left = head;
                     75:                 right = head->right;
                     76:                 while (right != NULL && right->distance < link->distance) {
                     77:                     left = right;
                     78:                     right = right->right;
                     79:                 }
                     80:                 if (left != NULL) left->right = link;
                     81:                 link->right = right;
                     82:                 link->left = left;
                     83:                 if (right != NULL) right->left = link;
                     84:             }
                     85:         }
                     86:
                     87:         right = head->right;
                     88:
                     89:         head->left = NULL;
                     90:         head->right = NULL;
                     91:
                     92:         head = right;
                     93:     }
                     94: }
                     95:
                     96: void pdsClear(pdsMap *map, short maxDistance, boolean eightWays) {
                     97:     short i;
                     98:
                     99:     map->eightWays = eightWays;
                    100:
                    101:     map->front.right = NULL;
                    102:
                    103:     for (i=0; i < DCOLS*DROWS; i++) {
                    104:         map->links[i].distance = maxDistance;
                    105:         map->links[i].left = map->links[i].right = NULL;
                    106:     }
                    107: }
                    108:
                    109: short pdsGetDistance(pdsMap *map, short x, short y) {
                    110:     pdsUpdate(map);
                    111:     return PDS_CELL(map, x, y)->distance;
                    112: }
                    113:
                    114: void pdsSetDistance(pdsMap *map, short x, short y, short distance) {
                    115:     pdsLink *left, *right, *link;
                    116:
                    117:     if (x > 0 && y > 0 && x < DCOLS - 1 && y < DROWS - 1) {
                    118:         link = PDS_CELL(map, x, y);
                    119:         if (link->distance > distance) {
                    120:             link->distance = distance;
                    121:
                    122:             if (link->right != NULL) link->right->left = link->left;
                    123:             if (link->left != NULL) link->left->right = link->right;
                    124:
                    125:             left = &map->front;
                    126:             right = map->front.right;
                    127:
                    128:             while (right != NULL && right->distance < link->distance) {
                    129:                 left = right;
                    130:                 right = right->right;
                    131:             }
                    132:
                    133:             link->right = right;
                    134:             link->left = left;
                    135:             left->right = link;
                    136:             if (right != NULL) right->left = link;
                    137:         }
                    138:     }
                    139: }
                    140:
                    141: void pdsSetCosts(pdsMap *map, short **costMap) {
                    142:     short i, j;
                    143:
                    144:     for (i=0; i<DCOLS; i++) {
                    145:         for (j=0; j<DROWS; j++) {
                    146:             if (i != 0 && j != 0 && i < DCOLS - 1 && j < DROWS - 1) {
                    147:                 PDS_CELL(map, i, j)->cost = costMap[i][j];
                    148:             } else {
                    149:                 PDS_CELL(map, i, j)->cost = PDS_FORBIDDEN;
                    150:             }
                    151:         }
                    152:     }
                    153: }
                    154:
                    155: void pdsBatchInput(pdsMap *map, short **distanceMap, short **costMap, short maxDistance, boolean eightWays) {
                    156:     short i, j;
                    157:     pdsLink *left, *right;
                    158:
                    159:     map->eightWays = eightWays;
                    160:
                    161:     left = NULL;
                    162:     right = NULL;
                    163:
                    164:     map->front.right = NULL;
                    165:     for (i=0; i<DCOLS; i++) {
                    166:         for (j=0; j<DROWS; j++) {
                    167:             pdsLink *link = PDS_CELL(map, i, j);
                    168:
                    169:             if (distanceMap != NULL) {
                    170:                 link->distance = distanceMap[i][j];
                    171:             } else {
                    172:                 if (costMap != NULL) {
                    173:                     // totally hackish; refactor
                    174:                     link->distance = maxDistance;
                    175:                 }
                    176:             }
                    177:
                    178:             int cost;
                    179:
                    180:             if (i == 0 || j == 0 || i == DCOLS - 1 || j == DROWS - 1) {
                    181:                 cost = PDS_OBSTRUCTION;
                    182:             } else if (costMap == NULL) {
                    183:                 if (cellHasTerrainFlag(i, j, T_OBSTRUCTS_PASSABILITY) && cellHasTerrainFlag(i, j, T_OBSTRUCTS_DIAGONAL_MOVEMENT)) cost = PDS_OBSTRUCTION;
                    184:                 else cost = PDS_FORBIDDEN;
                    185:             } else {
                    186:                 cost = costMap[i][j];
                    187:             }
                    188:
                    189:             link->cost = cost;
                    190:
                    191:             if (cost > 0) {
                    192:                 if (link->distance < maxDistance) {
                    193:                     if (right == NULL || right->distance > link->distance) {
                    194:                         // left and right are used to traverse the list; if many cells have similar values,
                    195:                         // some time can be saved by not clearing them with each insertion.  this time,
                    196:                         // sadly, we have to start from the front.
                    197:
                    198:                         left = &map->front;
                    199:                         right = map->front.right;
                    200:                     }
                    201:
                    202:                     while (right != NULL && right->distance < link->distance) {
                    203:                         left = right;
                    204:                         right = right->right;
                    205:                     }
                    206:
                    207:                     link->right = right;
                    208:                     link->left = left;
                    209:                     left->right = link;
                    210:                     if (right != NULL) right->left = link;
                    211:
                    212:                     left = link;
                    213:                 } else {
                    214:                     link->right = NULL;
                    215:                     link->left = NULL;
                    216:                 }
                    217:             } else {
                    218:                 link->right = NULL;
                    219:                 link->left = NULL;
                    220:             }
                    221:         }
                    222:     }
                    223: }
                    224:
                    225: void pdsBatchOutput(pdsMap *map, short **distanceMap) {
                    226:     short i, j;
                    227:
                    228:     pdsUpdate(map);
                    229:     // transfer results to the distanceMap
                    230:     for (i=0; i<DCOLS; i++) {
                    231:         for (j=0; j<DROWS; j++) {
                    232:             distanceMap[i][j] = PDS_CELL(map, i, j)->distance;
                    233:         }
                    234:     }
                    235: }
                    236:
                    237: void pdsInvalidate(pdsMap *map, short maxDistance) {
                    238:     pdsBatchInput(map, NULL, NULL, maxDistance, map->eightWays);
                    239: }
                    240:
                    241: void dijkstraScan(short **distanceMap, short **costMap, boolean useDiagonals) {
                    242:     static pdsMap map;
                    243:
                    244:     pdsBatchInput(&map, distanceMap, costMap, 30000, useDiagonals);
                    245:     pdsBatchOutput(&map, distanceMap);
                    246: }
                    247:
                    248: void calculateDistances(short **distanceMap,
                    249:                         short destinationX, short destinationY,
                    250:                         unsigned long blockingTerrainFlags,
                    251:                         creature *traveler,
                    252:                         boolean canUseSecretDoors,
                    253:                         boolean eightWays) {
                    254:     creature *monst;
                    255:     static pdsMap map;
                    256:
                    257:     short i, j;
                    258:
                    259:     for (i=0; i<DCOLS; i++) {
                    260:         for (j=0; j<DROWS; j++) {
                    261:             char cost;
                    262:             monst = monsterAtLoc(i, j);
                    263:             if (monst
                    264:                 && (monst->info.flags & (MONST_IMMUNE_TO_WEAPONS | MONST_INVULNERABLE))
                    265:                 && (monst->info.flags & (MONST_IMMOBILE | MONST_GETS_TURN_ON_ACTIVATION))) {
                    266:
                    267:                 // Always avoid damage-immune stationary monsters.
                    268:                 cost = PDS_FORBIDDEN;
                    269:             } else if (canUseSecretDoors
                    270:                 && cellHasTMFlag(i, j, TM_IS_SECRET)
                    271:                 && cellHasTerrainFlag(i, j, T_OBSTRUCTS_PASSABILITY)
                    272:                 && !(discoveredTerrainFlagsAtLoc(i, j) & T_OBSTRUCTS_PASSABILITY)) {
                    273:
                    274:                 cost = 1;
                    275:             } else if (cellHasTerrainFlag(i, j, T_OBSTRUCTS_PASSABILITY)
                    276:                        || (traveler && traveler == &player && !(pmap[i][j].flags & (DISCOVERED | MAGIC_MAPPED)))) {
                    277:
                    278:                 cost = cellHasTerrainFlag(i, j, T_OBSTRUCTS_DIAGONAL_MOVEMENT) ? PDS_OBSTRUCTION : PDS_FORBIDDEN;
                    279:             } else if ((traveler && monsterAvoids(traveler, i, j)) || cellHasTerrainFlag(i, j, blockingTerrainFlags)) {
                    280:                 cost = PDS_FORBIDDEN;
                    281:             } else {
                    282:                 cost = 1;
                    283:             }
                    284:
                    285:             PDS_CELL(&map, i, j)->cost = cost;
                    286:         }
                    287:     }
                    288:
                    289:     pdsClear(&map, 30000, eightWays);
                    290:     pdsSetDistance(&map, destinationX, destinationY, 0);
                    291:     pdsBatchOutput(&map, distanceMap);
                    292: }
                    293:
                    294: short pathingDistance(short x1, short y1, short x2, short y2, unsigned long blockingTerrainFlags) {
                    295:     short retval, **distanceMap = allocGrid();
                    296:     calculateDistances(distanceMap, x2, y2, blockingTerrainFlags, NULL, true, true);
                    297:     retval = distanceMap[x1][y1];
                    298:     freeGrid(distanceMap);
                    299:     return retval;
                    300: }
                    301:

CVSweb