Mercurial > hg > batmud > maputils
view mappath.c @ 945:81184d58133c aprilli2011
Sync.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Fri, 14 May 2010 11:18:20 +0000 |
parents | 304a50a9d51f |
children | 667ce752bfe3 |
line wrap: on
line source
/* * Calculate "optimal" walkpath through ASCII map * Programmed by Matti 'ccr' Hämäläinen (Ggr Pupunen) * (C) Copyright 2007 Tecnic Software productions (TNSP) */ #include "maputils.h" #include "th_args.h" #include "th_string.h" #include <string.h> char *srcFilename = NULL, *destFilename = NULL; typedef float pathmap_t; int optRace = -1, optX0 = -1, optY0 = -1, optX1 = -1, optY1 = -1; float optTurnFactor = 5.0f; #define MAXCOSTS (30) #define MAXPIECES (256) typedef struct { char *name; float defcost; char *pieces[MAXCOSTS]; pathmap_t epcost[MAXCOSTS]; } costinfo_t; #define T_IMP "!^VCc?%" #define T_ROAD "-/|\\=+" static const costinfo_t costTable[] = { { "duck", 105.0f, { T_IMP , "~SrRl" , T_ROAD, ".y" , "fF" , "hH" }, { -1 , 1.00 , 0.20 , 0.50 , 3.00 , 2.0 }}, /* Special costs for city maps */ { "CITY", 0.1f, { "#~" }, { -1 }}, }; static const int ncostTable = (sizeof(costTable) / sizeof(costinfo_t)); /* Arguments */ optarg_t optList[] = { { 0, '?', "help", "Show this help", OPT_NONE }, { 1, 'v', "verbose", "Be more verbose", OPT_NONE }, { 2, 'q', "quiet", "Be quiet", OPT_NONE }, { 3, 's', "start", "Start coords x:y", OPT_ARGREQ }, { 4, 'e', "end", "End coords x:y", OPT_ARGREQ }, { 5, 'o', "output", "Output filename", OPT_ARGREQ }, { 6, 'r', "race", "Race", OPT_ARGREQ }, { 7, 'f', "factor", "Turn factorial", OPT_ARGREQ }, }; const int optListN = (sizeof(optList) / sizeof(optarg_t)); void argShowHelp(void) { int i; th_args_help(stderr, optList, optListN, th_prog_name, "[options] <input mapfile> -r <race> -s <x>:<y> -e <x>:<y>"); fprintf(stderr, "Available races:\n"); for (i = 0; i < ncostTable; i++) { fprintf(stderr, "%s", costTable[i].name); if (i != (ncostTable - 1)) fprintf(stderr, ","); if (i % 5 == 0) fprintf(stderr, "\n"); else fprintf(stderr, " "); } } BOOL argParseCoord(char *arg, int *x, int *y, char *msg) { BOOL res = TRUE; char *s = th_strdup(arg); char *d = strchr(s, ':'); if (*d) { *d = 0; d++; if (th_isdigit(*s) && th_isdigit(*d)) { *x = atoi(s); *y = atoi(d); } else res = FALSE; } else res = FALSE; th_free(s); if (res) { THMSG(2, "Using %s coordinates %d:%d\n", msg, optX0, optY0); } else { THERR("Invalid %s coordinate argument '%s'!\n", msg, arg); } return res; } BOOL argHandleOpt(const int optN, char *optArg, char *currArg) { int i; switch (optN) { case 0: argShowHelp(); exit(0); break; case 1: th_verbosityLevel++; break; case 2: th_verbosityLevel = -1; break; case 3: if (!argParseCoord(optArg, &optX0, &optY0, "start")) return FALSE; break; case 4: if (!argParseCoord(optArg, &optX1, &optY1, "end")) return FALSE; break; case 5: destFilename = optArg; THMSG(2, "Output file set to '%s'.\n", destFilename); break; case 6: optRace = -1; for (i = 0; i < ncostTable && optRace < 0; i++) { if (strcmp(optArg, costTable[i].name) == 0) optRace = i; } if (optRace < 0) { THERR("Invalid/unsupported race name '%s'.\n", optArg); return FALSE; } else THMSG(2, "Race set to '%s' (%d).\n", optArg, optRace); break; case 7: optTurnFactor = atof(optArg); THMSG(2, "Turn factor = %1.3f.\n", optTurnFactor); break; default: THERR("Unknown option '%s'.\n", currArg); return FALSE; } return TRUE; } BOOL argHandleFile(char *currArg) { if (!srcFilename) srcFilename = currArg; else { THERR("Too many input map files specified!\n"); return FALSE; } return TRUE; } BOOL checkCoords(int w, int h, int x, int y) { return (x >= 0 && x < w && y >= 0 && y < h); } BOOL checkMap(pathmap_t *pathMap, int w, int h, int x, int y, pathmap_t val) { BOOL res = checkCoords(w, h, x, y); if (res) { pathmap_t tmp = pathMap[(y * w) + x]; res = ((tmp > 0) && (tmp < val)); } return res; } int getType(const costinfo_t *race, char c) { int i; for (i = 0; i < MAXCOSTS; i++) if (race->pieces[i]) { if (strchr(race->pieces[i], c)) return i; } else return -1; return -1; } /* Main program */ int main(int argc, char *argv[]) { FILE *outFile; mapblock_t *map, *map2; pathmap_t *pathMap, *d; const costinfo_t *race; pathmap_t costs[MAXPIECES]; BOOL costSet[MAXPIECES], pathOK, found; int i, x, y, px, py, sx, sy, count; unsigned char *c; size_t pathSize; #define QSET(ZX,ZY,ZV) pathMap[((ZY) * map->w) + (ZX)] = (ZV) #define QCHK(ZX,ZY) checkMap(pathMap, map->w, map->h, (ZX), (ZY), 99999) /* Initialize */ th_init("mappath", "ASCII map path generator", "0.1", NULL, NULL); th_verbosityLevel = 1; /* Parse arguments */ if (!th_args_process(argc, argv, optList, optListN, argHandleOpt, argHandleFile, TRUE)) exit(1); if (srcFilename == NULL) { THERR("No mapfile given. (try --help)\n"); exit(0); } /* Check settings */ if (optRace < 0) { THERR("You must set a race! (try --help for a list)\n"); exit(3); } if (optX0 < 0 || optX1 < 0 || optY0 < 0 || optY1 < 0) { THERR("Starting and ending coordinates must be set.\n"); exit(4); } /* Create cost table */ THMSG(1, "Building pathcost table\n"); race = &costTable[optRace]; for (i = 0; i < MAXPIECES; i++) { costSet[i] = FALSE; costs[i] = race->defcost; } for (i = 0; i < MAXCOSTS; i++) if (race->pieces[i]) { c = (unsigned char *) race->pieces[i]; while (*c) { if (costSet[*c]) { THERR("Cost for piece '%c' duplicated in #%d '%s' of race '%s'.\n", (char) *c, i, race->pieces[i], race->name); } //fprintf(stderr, "'%c' -> %1.3f\n", *c, race->epcost[i]); costs[*c] = race->epcost[i]; costSet[*c] = TRUE; c++; } } /* Read input file */ THMSG(1, "Reading map file '%s'\n", srcFilename); if ((map = parseFile(srcFilename, FALSE)) == NULL) { THERR("Error reading map file '%s'!\n", srcFilename); exit(1); } if ((map2 = allocBlock(map->w, map->h)) == NULL) { THERR("Could not allocate map2!\n"); exit(4); } memcpy(map2->d, map->d, map->w * map->h * sizeof(char)); pathSize = (map->w) * (map->h) * sizeof(pathmap_t); if ((pathMap = th_malloc(pathSize)) == NULL) { THERR("Could not allocate pathmap!\n"); exit(2); } /* Initialize and mark impassable blocks */ memset(pathMap, 0, pathSize); d = pathMap; c = (unsigned char *) map->d; for (y = 0; y < map->h; y++) for (x = 0; x < map->w; x++) { if (costs[*c] < 0) *d = 9999999.0; c++; d++; } /* Create pathmap */ THMSG(1, "Analyzing %dx%d area ...\n", map->w, map->h); QSET(optX0, optY0, 1); QSET(optX1, optY1, 0); pathOK = TRUE; while (pathOK) { pathOK = FALSE; c = (unsigned char *) map->d; d = pathMap; for (y = 0; y < map->h; y++) for (x = 0; x < map->w; x++) { if (*d == 0.0f) { int dx, dy, nx, ny, mx, my; pathmap_t mval = 9999999.0f, nval; found = FALSE; for (dy = -1; dy <= 1; dy++) for (dx = -1; dx <= 1; dx++) { nx = x + dx; ny = y + dy; if (!(dx == 0 && dy == 0) && checkMap(pathMap, map->w, map->h, nx, ny, mval)) { mval = nval; mx = nx; my = ny; found = TRUE; } } if (found) { pathmap_t v; if (x == optX1 && y == optY1) goto pathResolved; v = mval + costs[*c]; if (getType(race, *c) != getType(race, map->d[(my * map->w) + mx])) v += 15.0f; QSET(x, y, v); pathOK = TRUE; } } c++; d++; } } THMSG(1, "Bailout!\n"); pathResolved: QSET(optX1, optY1, 989898.0f); #if 0 d = pathMap; c = (unsigned char *) map->d; for (y = 0; y < map->h; y++) { for (x = 0; x < map->w; x++) { printf("%10.2f[%c] ", *d, *c); c++; d++; } printf("\n"); } #endif THMSG(1, "Resolving %d:%d -> %d:%d ...\n", optX0, optY0, optX1, optY1); sx = x = optX1; sy = y = optY1; px = py = 0; count = 0; do { int dx, dy, nx = 0, ny = 0; pathmap_t val, oval = pathMap[(y * map->w) + x]; val = 9999999.0f; found = FALSE; for (dy = -1; dy <= 1; dy++) for (dx = -1; dx <= 1; dx++) if (!(dx == 0 && dy == 0)) { int zx = x+dx, zy = y+dy; if (checkCoords(map->w, map->h, zx, zy)) { pathmap_t nval = pathMap[(zy * map->w) + zx]; if (nval <= val && nval > 0) { val = nval; nx = dx; ny = dy; found = TRUE; } } } if (found) { //printf("%d,%d -> %d,%d [%1.3f -> %1.3f]\n", x, y, nx, ny, oval, val); if (px != nx || py != ny) { px = nx; py = ny; sx = x; sy = y; } x += nx; y += ny; map2->d[(y * map->w) + x] = '&'; } else { printf("return: %d,%d -> %d,%d\n", x, y, sx, sy); x = sx; y = sy; } count++; } while ((x != optX0 || y != optY0) && count < 5000); /* Open output file */ if (destFilename == NULL) outFile = stdout; else if ((outFile = fopen(destFilename, "wb")) == NULL) { THERR("Error opening output file '%s'!\n", destFilename); exit(1); } printBlock(outFile, map2); fclose(outFile); THMSG(1, "Done.\n"); exit(0); return 0; }