diggingInvaders: added per-creature dig times and differentiated between smooth and rough constructions.

develop
expwnent 2013-06-15 23:04:15 -04:00
parent 776d088eb9
commit f459bfc4f1
5 changed files with 191 additions and 54 deletions

@ -6,6 +6,7 @@
#include "modules/Materials.h"
#include "df/building.h"
#include "df/construction.h"
#include "df/coord.h"
#include "df/general_ref.h"
#include "df/general_ref_building_holderst.h"
@ -47,7 +48,7 @@ void getRidOfOldJob(df::unit* unit) {
//delete job;
}
int32_t assignJob(color_ostream& out, Edge firstImportantEdge, unordered_map<df::coord,df::coord,PointHash> parentMap, unordered_map<df::coord,cost_t,PointHash>& costMap, vector<int32_t>& invaders, unordered_set<df::coord,PointHash>& requiresZNeg, unordered_set<df::coord,PointHash>& requiresZPos, MapExtras::MapCache& cache) {
int32_t assignJob(color_ostream& out, Edge firstImportantEdge, unordered_map<df::coord,df::coord,PointHash> parentMap, unordered_map<df::coord,cost_t,PointHash>& costMap, vector<int32_t>& invaders, unordered_set<df::coord,PointHash>& requiresZNeg, unordered_set<df::coord,PointHash>& requiresZPos, MapExtras::MapCache& cache, DigAbilities& abilities ) {
df::unit* firstInvader = df::unit::find(invaders[0]);
if ( !firstInvader ) {
return -1;
@ -107,7 +108,7 @@ int32_t assignJob(color_ostream& out, Edge firstImportantEdge, unordered_map<df:
building->jobs.push_back(job);
Job::linkIntoWorld(job);
jobId = job->id;
job->completion_timer = jobDelay[DestroyBuilding];
job->completion_timer = abilities.jobDelay[CostDimension::DestroyBuilding];
} else {
df::tiletype* type1 = Maps::getTileType(pt1);
df::tiletype* type2 = Maps::getTileType(pt2);
@ -132,7 +133,12 @@ int32_t assignJob(color_ostream& out, Edge firstImportantEdge, unordered_map<df:
firstInvader->job.destroy_target = NULL;
Job::linkIntoWorld(job);
jobId = job->id;
job->completion_timer = jobDelay[DestroyConstruction];
df::construction* constr = df::construction::find(pt2);
bool smooth = constr != NULL && constr->item_type != df::enums::item_type::BOULDER;
if ( smooth )
job->completion_timer = abilities.jobDelay[CostDimension::DestroySmoothConstruction];
else
job->completion_timer = abilities.jobDelay[CostDimension::DestroyRoughConstruction];
} else {
bool walkable_low1 = shape1 == df::tiletype_shape::STAIR_DOWN || shape1 == df::tiletype_shape::STAIR_UPDOWN;
bool walkable_low2 = shape2 == df::tiletype_shape::STAIR_DOWN || shape2 == df::tiletype_shape::STAIR_UPDOWN;
@ -195,7 +201,7 @@ int32_t assignJob(color_ostream& out, Edge firstImportantEdge, unordered_map<df:
firstInvader->path.path.z.clear();
Job::linkIntoWorld(job);
jobId = job->id;
job->completion_timer = jobDelay[Dig];
job->completion_timer = abilities.jobDelay[CostDimension::Dig];
//TODO: test if he already has a pick
bool hasPick = false;

@ -9,5 +9,5 @@
using namespace std;
int32_t assignJob(color_ostream& out, Edge firstImportantEdge, unordered_map<df::coord,df::coord,PointHash> parentMap, unordered_map<df::coord,cost_t,PointHash>& costMap, vector<int32_t>& invaders, unordered_set<df::coord,PointHash>& requiresZNeg, unordered_set<df::coord,PointHash>& requiresZPos, MapExtras::MapCache& cache);
int32_t assignJob(color_ostream& out, Edge firstImportantEdge, unordered_map<df::coord,df::coord,PointHash> parentMap, unordered_map<df::coord,cost_t,PointHash>& costMap, vector<int32_t>& invaders, unordered_set<df::coord,PointHash>& requiresZNeg, unordered_set<df::coord,PointHash>& requiresZPos, MapExtras::MapCache& cache, DigAbilities& abilities);

@ -87,33 +87,61 @@ static bool activeDigging=false;
static unordered_set<string> diggingRaces;
static unordered_set<int32_t> invaderJobs;
static df::coord lastDebugEdgeCostPoint;
unordered_map<string, DigAbilities> digAbilities;
static cost_t costWeightDefault[] = {
//Distance
1,
//Destroy Building
2,
//Dig
10000,
//DestroyRoughConstruction
1000,
//DestroySmoothConstruction
100,
};
static int32_t jobDelayDefault[] = {
//Distance
-1,
//Destroy Building
1000,
//Dig
1000,
//DestroyRoughConstruction
1000,
//DestroySmoothConstruction
100,
};
DFhackCExport command_result plugin_init (color_ostream &out, std::vector <PluginCommand> &commands)
{
commands.push_back(PluginCommand(
"diggingInvaders", "Makes invaders dig to your dwarves.",
diggingInvadersCommand, false, /* true means that the command can't be used from non-interactive user interface */
"example usage:\n"
" diggingInvaders 0\n disables the plugin\n"
" diggingInvaders 1\n enables the plugin\n"
" diggingInvaders enable\n enables the plugin\n"
" diggingInvaders disable\n disables the plugin\n"
" diggingInvaders add GOBLIN\n registers the race GOBLIN as a digging invader. Case-sensitive.\n"
" diggingInvaders remove GOBLIN\n unregisters the race GOBLIN as a digging invader. Case-sensitive.\n"
" diggingInvaders setCost walk n\n sets the walk cost in the path algorithm\n"
" diggingInvaders setCost destroyBuilding n\n"
" diggingInvaders setCost dig n\n"
" diggingInvaders setCost destroyConstruction n\n"
" diggingInvaders setDelay destroyBuilding n\n adds to the job_completion_timer of destroy building jobs that are assigned to invaders\n"
" diggingInvaders setDelay dig n\n"
" diggingInvaders setDelay destroyConstruction n\n"
" diggingInvaders setCost GOBLIN walk n\n sets the walk cost in the path algorithm for the race GOBLIN\n"
" diggingInvaders setCost GOBLIN destroyBuilding n\n"
" diggingInvaders setCost GOBLIN dig n\n"
" diggingInvaders setCost GOBLIN destroyRoughConstruction n\n rough constructions are made from boulders\n"
" diggingInvaders setCost GOBLIN destroySmoothConstruction n\n smooth constructions are made from blocks or bars instead of boulders\n"
" diggingInvaders setDelay GOBLIN destroyBuilding n\n adds to the job_completion_timer of destroy building jobs that are assigned to invaders\n"
" diggingInvaders setDelay GOBLIN dig n\n"
" diggingInvaders setDelay GOBLIN destroyRoughConstruction n\n"
" diggingInvaders setDelay GOBLIN destroySmoothConstruction n\n"
" diggingInvaders now\n makes invaders try to dig now, if plugin is enabled\n"
" diggingInvaders clear\n clears all digging invader races\n"
" diggingInvaders edgesPerTick n\n makes the pathfinding algorithm work on at most n edges per tick. Set to 0 or lower to make it unlimited."
// " diggingInvaders\n Makes invaders try to dig now.\n"
));
*df::global::debug_showambush = true;
//*df::global::debug_showambush = true;
return CR_OK;
}
@ -135,6 +163,7 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan
case DFHack::SC_WORLD_UNLOADED:
// cleanup
lastInvasionJob = lastInvasionDigger = -1;
enabled = false;
activeDigging = false;
clearDijkstra();
invaderJobs.clear();
@ -193,14 +222,28 @@ command_result diggingInvadersCommand(color_ostream& out, std::vector<std::strin
string race = parameters[a+1];
if ( parameters[a] == "add" ) {
diggingRaces.insert(race);
DigAbilities& abilities = digAbilities[race];
memcpy(abilities.costWeight, costWeightDefault, costDim*sizeof(cost_t));
memcpy(abilities.jobDelay, jobDelayDefault, costDim*sizeof(int32_t));
} else {
diggingRaces.erase(race);
digAbilities.erase(race);
}
a++;
} else if ( parameters[a] == "setCost" || parameters[a] == "setDelay" ) {
if ( a+2 >= parameters.size() )
if ( a+3 >= parameters.size() )
return CR_WRONG_USAGE;
string costStr = parameters[a+1];
string raceString = parameters[a+1];
if ( digAbilities.find(raceString) == digAbilities.end() ) {
DigAbilities bob;
memset(&bob, 0xFF, sizeof(bob));
digAbilities[raceString] = bob;
}
DigAbilities& abilities = digAbilities[raceString];
string costStr = parameters[a+2];
int32_t costDim = -1;
if ( costStr == "walk" ) {
costDim = CostDimension::Walk;
@ -210,30 +253,47 @@ command_result diggingInvadersCommand(color_ostream& out, std::vector<std::strin
costDim = CostDimension::DestroyBuilding;
} else if ( costStr == "dig" ) {
costDim = CostDimension::Dig;
} else if ( costStr == "destroyConstruction" ) {
costDim = CostDimension::DestroyConstruction;
} else if ( costStr == "destroyRoughConstruction" ) {
costDim = CostDimension::DestroyRoughConstruction;
} else if ( costStr == "destroySmoothConstruction" ) {
costDim = CostDimension::DestroySmoothConstruction;
} else {
return CR_WRONG_USAGE;
}
cost_t value;
stringstream asdf(parameters[a+2]);
stringstream asdf(parameters[a+3]);
asdf >> value;
if ( parameters[a] == "setCost" && value <= 0 )
return CR_WRONG_USAGE;
if ( parameters[a] == "setCost" )
costWeight[costDim] = value;
else
jobDelay[costDim] = value;
a += 2;
//if ( parameters[a] == "setCost" && value <= 0 )
// return CR_WRONG_USAGE;
if ( parameters[a] == "setCost" ) {
abilities.costWeight[costDim] = value;
} else {
abilities.jobDelay[costDim] = value;
}
a += 3;
} else if ( parameters[a] == "edgeCost" ) {
if ( a+1 >= parameters.size() )
return CR_WRONG_USAGE;
string raceString = parameters[a+1];
if ( digAbilities.find(raceString) == digAbilities.end() ) {
out.print("Race %s does not have dig abilities assigned.\n", raceString.c_str());
return CR_WRONG_USAGE;
}
DigAbilities& abilities = digAbilities[raceString];
df::coord bob = Gui::getCursorPos();
out.print("(%d,%d,%d), (%d,%d,%d): cost = %lld\n", lastDebugEdgeCostPoint.x, lastDebugEdgeCostPoint.y, lastDebugEdgeCostPoint.z, bob.x, bob.y, bob.z, getEdgeCost(out, lastDebugEdgeCostPoint, bob));
out.print("(%d,%d,%d), (%d,%d,%d): cost = %lld\n", lastDebugEdgeCostPoint.x, lastDebugEdgeCostPoint.y, lastDebugEdgeCostPoint.z, bob.x, bob.y, bob.z, getEdgeCost(out, lastDebugEdgeCostPoint, bob, abilities));
lastDebugEdgeCostPoint = bob;
a++;
} else if ( parameters[a] == "now" ) {
activeDigging = true;
findAndAssignInvasionJob(out, (void*)0);
} else if ( parameters[a] == "clear" ) {
diggingRaces.clear();
digAbilities.clear();
} else if ( parameters[a] == "edgesPerTick" ) {
if ( a+1 >= parameters.size() )
return CR_WRONG_USAGE;
@ -335,8 +395,12 @@ void findAndAssignInvasionJob(color_ostream& out, void* tickTime) {
out.print("%s,%d: WTF? Couldn't find creature raw.\n", __FILE__, __LINE__);
continue;
}
/*
if ( diggingRaces.find(raw->creature_id) == diggingRaces.end() )
continue;
*/
if ( digAbilities.find(raw->creature_id) == digAbilities.end() )
continue;
if ( invaderPts.find(unit->pos) != invaderPts.end() )
continue;
//must be able to wield a pick: this is overly pessimistic
@ -380,6 +444,14 @@ void findAndAssignInvasionJob(color_ostream& out, void* tickTime) {
fringe.clear();
return;
}
df::creature_raw* creature_raw = df::creature_raw::find(firstInvader->race);
if ( creature_raw == NULL || digAbilities.find(creature_raw->creature_id) == digAbilities.end() ) {
//inappropriate digger: no dig abilities
fringe.clear();
return;
}
DigAbilities& abilities = digAbilities[creature_raw->creature_id];
//TODO: check that firstInvader is an appropriate digger
//out << firstInvader->id << endl;
//out << firstInvader->pos.x << ", " << firstInvader->pos.y << ", " << firstInvader->pos.z << endl;
@ -421,7 +493,7 @@ void findAndAssignInvasionJob(color_ostream& out, void* tickTime) {
cost_t myCost = costMap[pt];
clock_t edgeTime = clock();
vector<Edge>* myEdges = getEdgeSet(out, pt, cache, xMax, yMax, zMax);
vector<Edge>* myEdges = getEdgeSet(out, pt, cache, xMax, yMax, zMax, abilities);
totalEdgeTime += (clock() - edgeTime);
for ( auto a = myEdges->begin(); a != myEdges->end(); a++ ) {
Edge &e = *a;
@ -476,7 +548,7 @@ void findAndAssignInvasionJob(color_ostream& out, void* tickTime) {
while ( parentMap.find(pt) != parentMap.end() ) {
//out.print("(%d,%d,%d)\n", pt.x, pt.y, pt.z);
df::coord parent = parentMap[pt];
cost_t cost = getEdgeCost(out, parent, pt);
cost_t cost = getEdgeCost(out, parent, pt, abilities);
if ( cost < 0 ) {
//path invalidated
return;
@ -514,7 +586,7 @@ void findAndAssignInvasionJob(color_ostream& out, void* tickTime) {
}
*/
assignJob(out, firstImportantEdge, parentMap, costMap, invaders, requiresZNeg, requiresZPos, cache);
assignJob(out, firstImportantEdge, parentMap, costMap, invaders, requiresZNeg, requiresZPos, cache, abilities);
lastInvasionDigger = firstInvader->id;
lastInvasionJob = firstInvader->job.current_job ? firstInvader->job.current_job->id : -1;
invaderJobs.erase(lastInvasionJob);

@ -8,7 +8,9 @@
#include "df/building_bridgest.h"
#include "df/building_hatchst.h"
#include "df/building_type.h"
#include "df/construction.h"
#include "df/coord.h"
#include "df/item_type.h"
#include "df/map_block.h"
#include "df/tile_building_occ.h"
#include "df/tiletype.h"
@ -17,6 +19,7 @@
#include <iostream>
/*
cost_t costWeight[] = {
//Distance
1,
@ -38,6 +41,7 @@ int32_t jobDelay[] = {
//DestroyConstruction
1000
};
*/
using namespace std;
@ -46,11 +50,13 @@ limitations
ramps
cave-ins
*/
cost_t getEdgeCost(color_ostream& out, df::coord pt1, df::coord pt2) {
cost_t getEdgeCost(color_ostream& out, df::coord pt1, df::coord pt2, DigAbilities& abilities) {
int32_t dx = pt2.x - pt1.x;
int32_t dy = pt2.y - pt1.y;
int32_t dz = pt2.z - pt1.z;
cost_t cost = costWeight[CostDimension::Walk];
cost_t cost = abilities.costWeight[CostDimension::Walk];
if ( cost < 0 )
return -1;
if ( Maps::getTileBlock(pt1) == NULL || Maps::getTileBlock(pt2) == NULL )
return -1;
@ -83,14 +89,28 @@ cost_t getEdgeCost(color_ostream& out, df::coord pt1, df::coord pt2) {
df::building* building2 = Buildings::findAtTile(pt2);
if ( building2 ) {
cost += costWeight[CostDimension::DestroyBuilding];
if ( abilities.costWeight[CostDimension::DestroyBuilding] < 0 )
return -1;
cost += abilities.costWeight[CostDimension::DestroyBuilding];
if ( dx*dx + dy*dy > 1 )
return -1;
}
bool construction2 = ENUM_ATTR(tiletype, material, *type2) == df::enums::tiletype_material::CONSTRUCTION;
if ( construction2 )
cost += costWeight[CostDimension::DestroyConstruction];
if ( construction2 ) {
//smooth or not?
df::construction* constr = df::construction::find(pt2);
bool smooth = constr != NULL && constr->item_type != df::enums::item_type::BOULDER;
if ( smooth ) {
if ( abilities.costWeight[CostDimension::DestroySmoothConstruction] < 0 )
return -1;
cost += abilities.costWeight[CostDimension::DestroySmoothConstruction];
} else {
if ( abilities.costWeight[CostDimension::DestroyRoughConstruction] < 0 )
return -1;
cost += abilities.costWeight[CostDimension::DestroyRoughConstruction];
}
}
if ( dz == 0 ) {
if ( !building2 && !construction2 ) {
@ -102,7 +122,10 @@ cost_t getEdgeCost(color_ostream& out, df::coord pt1, df::coord pt2) {
//out << __FILE__ << ", line " << __LINE__ << ": WTF?" << endl;
return cost;
}
cost += costWeight[CostDimension::Dig];
if ( abilities.costWeight[CostDimension::Dig] < 0 ) {
return -1;
}
cost += abilities.costWeight[CostDimension::Dig];
}
} else {
if ( dx == 0 && dy == 0 ) {
@ -113,7 +136,10 @@ cost_t getEdgeCost(color_ostream& out, df::coord pt1, df::coord pt2) {
if ( !walkable_low2 ) {
if ( building2 || construction2 )
return -1;
cost += costWeight[CostDimension::Dig];
if ( abilities.costWeight[CostDimension::Dig] < 0 ) {
return -1;
}
cost += abilities.costWeight[CostDimension::Dig];
}
bool walkable_high1 = shape1 == df::tiletype_shape::STAIR_UP || shape1 == df::tiletype_shape::STAIR_UPDOWN;
@ -121,7 +147,10 @@ cost_t getEdgeCost(color_ostream& out, df::coord pt1, df::coord pt2) {
if ( shape1 != df::enums::tiletype_shape::WALL ) {
return -1;
}
cost += costWeight[CostDimension::Dig];
if ( abilities.costWeight[CostDimension::Dig] < 0 ) {
return -1;
}
cost += abilities.costWeight[CostDimension::Dig];
}
if ( building2 ) {
@ -174,7 +203,10 @@ cost_t getEdgeCost(color_ostream& out, df::coord pt1, df::coord pt2) {
if ( shape2 != df::enums::tiletype_shape::WALL )
return -1;
cost += costWeight[CostDimension::Dig];
if ( abilities.costWeight[CostDimension::Dig] < 0 ) {
return -1;
}
cost += abilities.costWeight[CostDimension::Dig];
}
bool walkable_low1 = shape1 == df::tiletype_shape::STAIR_DOWN || shape1 == df::tiletype_shape::STAIR_UPDOWN;
if ( !walkable_low1 ) {
@ -183,7 +215,10 @@ cost_t getEdgeCost(color_ostream& out, df::coord pt1, df::coord pt2) {
//TODO: consider ramps
if ( shape1 == df::tiletype_shape::RAMP )
return -1;
cost += costWeight[CostDimension::Dig];
if ( abilities.costWeight[CostDimension::Dig] < 0 ) {
return -1;
}
cost += abilities.costWeight[CostDimension::Dig];
}
df::building* building1 = Buildings::findAtTile(pt1);
@ -213,13 +248,17 @@ cost_t getEdgeCost(color_ostream& out, df::coord pt1, df::coord pt2) {
//you can deconstruct a hatch from the side
if ( building1 && forbidden /*&& building1->getType() == df::building_type::Hatch*/ ) {
/*
df::coord support[] = {df::coord(pt1.x-1, pt1.y, pt1.z), df::coord(pt1.x+1,pt1.y,pt1.z), df::coord(pt1.x,pt1.y-1,pt1.z), df::coord(pt1.x,pt1.y+1,pt1.z)};
if ( abilities.costWeight[CostDimension::DestroyBuilding] < 0 ) {
return -1;
}
cost_t minCost = -1;
for ( size_t a = 0; a < 4; a++ ) {
df::tiletype* supportType = Maps::getTileType(support[a]);
df::tiletype_shape shape = ENUM_ATTR(tiletype, shape, *supportType);
df::tiletype_shape_basic basic = ENUM_ATTR(tiletype_shape, basic_shape, shape);
cost_t cost2 = 2*costWeight[CostDimension::Walk] + costWeight[CostDimension::DestroyBuilding];
cost_t cost2 = 2*abilities.costWeight[CostDimension::Walk] + abilities.costWeight[CostDimension::DestroyBuilding];
if ( !Maps::canStepBetween(pt1, support[a]) ) {
switch(basic) {
case tiletype_shape_basic::Open:
@ -227,9 +266,15 @@ cost_t getEdgeCost(color_ostream& out, df::coord pt1, df::coord pt2) {
continue;
case tiletype_shape_basic::Wall:
if ( ENUM_ATTR(tiletype, material, *supportType) == df::enums::tiletype_material::CONSTRUCTION ) {
cost2 += costWeight[CostDimension::DestroyConstruction];
if ( abilities.costWeight[CostDimension::DestroyConstruction] < 0 ) {
continue;
}
cost2 += abilities.costWeight[CostDimension::DestroyConstruction];
} else {
cost2 += costWeight[CostDimension::Dig];
if ( abilities.costWeight[CostDimension::Dig] < 0 ) {
continue;
}
cost2 += abilities.costWeight[CostDimension::Dig];
}
case tiletype_shape_basic::Ramp:
//TODO: check for a hatch or a bridge: that makes it ok
@ -241,7 +286,10 @@ cost_t getEdgeCost(color_ostream& out, df::coord pt1, df::coord pt2) {
break;
}
if ( Buildings::findAtTile(support[a]) ) {
cost2 += costWeight[CostDimension::DestroyBuilding];
if ( abilities.costWeight[CostDimension::DestroyBuilding] < 0 ) {
continue;
}
cost2 += abilities.costWeight[CostDimension::DestroyBuilding];
}
}
if ( minCost == -1 || cost2 < minCost )
@ -251,6 +299,7 @@ cost_t getEdgeCost(color_ostream& out, df::coord pt1, df::coord pt2) {
return -1;
cost += minCost;
*/
//note: assignJob is not ready for this level of sophistication, so don't allow it
return -1;
}
@ -265,6 +314,7 @@ cost_t getEdgeCost(color_ostream& out, df::coord pt1, df::coord pt2) {
return cost;
}
/*
cost_t getEdgeCostOld(color_ostream& out, df::coord pt1, df::coord pt2) {
//first, list all the facts
int32_t dx = pt2.x - pt1.x;
@ -397,8 +447,9 @@ cost_t getEdgeCostOld(color_ostream& out, df::coord pt1, df::coord pt2) {
//moving diagonally
return -1;
}
*/
vector<Edge>* getEdgeSet(color_ostream &out, df::coord point, MapExtras::MapCache& cache, int32_t xMax, int32_t yMax, int32_t zMax) {
vector<Edge>* getEdgeSet(color_ostream &out, df::coord point, MapExtras::MapCache& cache, int32_t xMax, int32_t yMax, int32_t zMax, DigAbilities& abilities) {
//vector<Edge>* result = new vector<Edge>(26);
vector<Edge>* result = new vector<Edge>();
result->reserve(26);
@ -414,7 +465,7 @@ vector<Edge>* getEdgeSet(color_ostream &out, df::coord point, MapExtras::MapCach
continue;
if ( dx == 0 && dy == 0 && dz == 0 )
continue;
cost_t cost = getEdgeCost(out, point, neighbor);
cost_t cost = getEdgeCost(out, point, neighbor, abilities);
if ( cost == -1 )
continue;
Edge edge(point, neighbor, cost);

@ -9,6 +9,7 @@
#include "df/coord.h"
#include <unordered_map>
#include <vector>
//cost is [path cost, building destruction cost, dig cost, construct cost]. Minimize constructions, then minimize dig cost, then minimize path cost.
@ -16,15 +17,22 @@ enum CostDimension {
Walk,
DestroyBuilding,
Dig,
DestroyConstruction,
DestroyRoughConstruction,
DestroySmoothConstruction,
//Construct,
costDim
};
typedef int64_t cost_t;
extern cost_t costWeight[costDim];
extern int32_t jobDelay[costDim];
struct DigAbilities {
cost_t costWeight[costDim];
int32_t jobDelay[costDim];
};
//extern cost_t costWeight[costDim];
//extern int32_t jobDelay[costDim];
extern std::unordered_map<std::string, DigAbilities> digAbilities;
/*
const cost_t costWeight[] = {
//Distance
@ -85,6 +93,6 @@ struct PointHash {
}
};
cost_t getEdgeCost(color_ostream& out, df::coord pt1, df::coord pt2);
std::vector<Edge>* getEdgeSet(color_ostream &out, df::coord point, MapExtras::MapCache& cache, int32_t xMax, int32_t yMax, int32_t zMax);
cost_t getEdgeCost(color_ostream& out, df::coord pt1, df::coord pt2, DigAbilities& abilities);
std::vector<Edge>* getEdgeSet(color_ostream &out, df::coord point, MapExtras::MapCache& cache, int32_t xMax, int32_t yMax, int32_t zMax, DigAbilities& abilities);