Digging Invaders: kind of works, but WAAAAAY too slow.

develop
expwnent 2012-12-17 20:12:11 -05:00
parent 957a4da474
commit 937769874d
1 changed files with 94 additions and 78 deletions

@ -14,10 +14,13 @@
#include "df/building.h" #include "df/building.h"
#include "df/coord.h" #include "df/coord.h"
#include "df/inorganic_raw.h"
#include "df/map_block.h" #include "df/map_block.h"
#include "df/strain_type.h"
#include "df/ui.h" #include "df/ui.h"
#include "df/unit.h" #include "df/unit.h"
#include "df/tiletype.h" #include "df/tiletype.h"
#include "df/tiletype_material.h"
#include "df/tiletype_shape.h" #include "df/tiletype_shape.h"
#include "df/tiletype_shape_basic.h" #include "df/tiletype_shape_basic.h"
#include "df/world.h" #include "df/world.h"
@ -25,6 +28,7 @@
#include <algorithm> #include <algorithm>
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <iostream>
#include <map> #include <map>
#include <set> #include <set>
#include <vector> #include <vector>
@ -33,13 +37,10 @@ using namespace std;
using namespace DFHack; using namespace DFHack;
using namespace df::enums; using namespace df::enums;
/////////////////////// int32_t digSpeed = 100;
color_ostream* glob_out; int32_t destroySpeed = 100;
int32_t deconstructSpeed = 100;
#if 0 int32_t constructSpeed = 100;
#define DEBUG_PRINT(str) \
out.print("%s, line %d" STR, __FILE__, __LINE__);
#endif
command_result diggingInvadersFunc(color_ostream &out, std::vector <std::string> & parameters); command_result diggingInvadersFunc(color_ostream &out, std::vector <std::string> & parameters);
@ -62,42 +63,6 @@ DFhackCExport command_result plugin_shutdown ( color_ostream &out )
return CR_OK; return CR_OK;
} }
// Called to notify the plugin about important state changes.
// Invoked with DF suspended, and always before the matching plugin_onupdate.
// More event codes may be added in the future.
/*
DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event)
{
switch (event) {
case SC_GAME_LOADED:
// initialize from the world just loaded
break;
case SC_GAME_UNLOADED:
// cleanup
break;
default:
break;
}
return CR_OK;
}
*/
// Whatever you put here will be done in each game step. Don't abuse it.
// It's optional, so you can just comment it out like this if you don't need it.
/*
DFhackCExport command_result plugin_onupdate ( color_ostream &out )
{
// whetever. You don't need to suspend DF execution here.
return CR_OK;
}
*/
/*class CompareEdge {
bool operator()(edge e1, edge e2) {
}
};*/
//cost is [path cost, building destruction cost, dig cost, construct cost]. Minimize constructions, then minimize dig cost, then minimize path cost. //cost is [path cost, building destruction cost, dig cost, construct cost]. Minimize constructions, then minimize dig cost, then minimize path cost.
const size_t costDim = 4; const size_t costDim = 4;
@ -189,7 +154,7 @@ public:
} }
}; };
vector<Edge>* getEdgeSet(color_ostream &out, df::coord point, 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);
df::coord getRoot(df::coord point, map<df::coord, df::coord>& rootMap); df::coord getRoot(df::coord point, map<df::coord, df::coord>& rootMap);
class PointComp { class PointComp {
@ -218,10 +183,16 @@ public:
}; };
bool important(df::coord pos, map<df::coord, set<Edge> >& edges, df::coord prev, set<df::coord>& importantPoints, set<Edge>& importantEdges); bool important(df::coord pos, map<df::coord, set<Edge> >& edges, df::coord prev, set<df::coord>& importantPoints, set<Edge>& importantEdges);
void doDiggingInvaders(color_ostream& out, void* ptr);
command_result diggingInvadersFunc(color_ostream& out, std::vector<std::string>& parameters) { command_result diggingInvadersFunc(color_ostream& out, std::vector<std::string>& parameters) {
if (!parameters.empty()) if (!parameters.empty())
return CR_WRONG_USAGE; return CR_WRONG_USAGE;
doDiggingInvaders(out, NULL);
return CR_OK;
}
void doDiggingInvaders(color_ostream& out, void* ptr) {
CoreSuspender suspend; CoreSuspender suspend;
map<df::coord, set<Edge> > edgeSet; map<df::coord, set<Edge> > edgeSet;
@ -235,6 +206,7 @@ command_result diggingInvadersFunc(color_ostream& out, std::vector<std::string>&
Maps::getSize(xMax,yMax,zMax); Maps::getSize(xMax,yMax,zMax);
xMax *= 16; xMax *= 16;
yMax *= 16; yMax *= 16;
MapExtras::MapCache cache;
//TODO: look for invaders with buildingdestroyer:3 //TODO: look for invaders with buildingdestroyer:3
@ -257,7 +229,7 @@ command_result diggingInvadersFunc(color_ostream& out, std::vector<std::string>&
continue; continue;
} }
vector<Edge>* neighbors = getEdgeSet(out, unit->pos, xMax, yMax, zMax); vector<Edge>* neighbors = getEdgeSet(out, unit->pos, cache, xMax, yMax, zMax);
set<Edge>& rootEdges = edgeSet[unit->pos]; set<Edge>& rootEdges = edgeSet[unit->pos];
for ( auto i = neighbors->begin(); i != neighbors->end(); i++ ) { for ( auto i = neighbors->begin(); i != neighbors->end(); i++ ) {
Edge edge = *i; Edge edge = *i;
@ -272,7 +244,7 @@ command_result diggingInvadersFunc(color_ostream& out, std::vector<std::string>&
while(!fringe.empty()) { while(!fringe.empty()) {
df::coord pt = *(fringe.begin()); df::coord pt = *(fringe.begin());
fringe.erase(fringe.begin()); fringe.erase(fringe.begin());
out.print("line %d: fringe size = %d, localPtsFound = %d / %d, closedSetSize = %d\n", __LINE__, fringe.size(), localPtsFound, localPts.size(), closedSet.size()); //out.print("line %d: fringe size = %d, localPtsFound = %d / %d, closedSetSize = %d\n", __LINE__, fringe.size(), localPtsFound, localPts.size(), closedSet.size());
if ( closedSet.find(pt) != closedSet.end() ) { if ( closedSet.find(pt) != closedSet.end() ) {
out.print("Double closure! Bad!\n"); out.print("Double closure! Bad!\n");
break; break;
@ -289,7 +261,7 @@ command_result diggingInvadersFunc(color_ostream& out, std::vector<std::string>&
if ( edgeSet.find(pt) == edgeSet.end() ) { if ( edgeSet.find(pt) == edgeSet.end() ) {
set<Edge>& temp = edgeSet[pt]; set<Edge>& temp = edgeSet[pt];
vector<Edge>* edges = getEdgeSet(out, pt, xMax, yMax, zMax); vector<Edge>* edges = getEdgeSet(out, pt, cache, xMax, yMax, zMax);
for ( auto a = edges->begin(); a != edges->end(); a++ ) { for ( auto a = edges->begin(); a != edges->end(); a++ ) {
Edge e = *a; Edge e = *a;
temp.insert(e); temp.insert(e);
@ -315,7 +287,6 @@ command_result diggingInvadersFunc(color_ostream& out, std::vector<std::string>&
//find important edges //find important edges
list<Edge> importantEdges; list<Edge> importantEdges;
map<df::coord, int32_t> importance;
for ( auto i = localPts.begin(); i != localPts.end(); i++ ) { for ( auto i = localPts.begin(); i != localPts.end(); i++ ) {
df::coord pt = *i; df::coord pt = *i;
if ( costMap.find(pt) == costMap.end() ) if ( costMap.find(pt) == costMap.end() )
@ -325,7 +296,7 @@ command_result diggingInvadersFunc(color_ostream& out, std::vector<std::string>&
if ( costMap[pt].cost[1] == 0 && costMap[pt].cost[2] == 0 ) if ( costMap[pt].cost[1] == 0 && costMap[pt].cost[2] == 0 )
continue; continue;
while ( parentMap.find(pt) != parentMap.end() ) { while ( parentMap.find(pt) != parentMap.end() ) {
out.print("(%d,%d,%d)\n", pt.x, pt.y, pt.z); //out.print("(%d,%d,%d)\n", pt.x, pt.y, pt.z);
df::coord parent = parentMap[pt]; df::coord parent = parentMap[pt];
if ( !Maps::canWalkBetween(pt, parent) ) { if ( !Maps::canWalkBetween(pt, parent) ) {
importantEdges.push_front(Edge(pt,parent,0)); importantEdges.push_front(Edge(pt,parent,0));
@ -335,6 +306,8 @@ command_result diggingInvadersFunc(color_ostream& out, std::vector<std::string>&
break; break;
} }
bool didSomething = false;
df::coord where;
for ( auto i = importantEdges.begin(); i != importantEdges.end(); i++ ) { for ( auto i = importantEdges.begin(); i != importantEdges.end(); i++ ) {
Edge e = *i; Edge e = *i;
df::coord pt1 = e.p1; df::coord pt1 = e.p1;
@ -345,9 +318,10 @@ command_result diggingInvadersFunc(color_ostream& out, std::vector<std::string>&
} }
df::building* building = Buildings::findAtTile(pt2); df::building* building = Buildings::findAtTile(pt2);
if ( building != NULL ) { if ( building != NULL ) {
out.print("%d\n", __LINE__);
building->flags.bits.almost_deleted = true; building->flags.bits.almost_deleted = true;
out.print("%d\n", __LINE__); didSomething = true;
where = pt2;
break;
} else { } else {
df::map_block* block1 = Maps::getTileBlock(pt1); df::map_block* block1 = Maps::getTileBlock(pt1);
df::map_block* block2 = Maps::getTileBlock(pt2); df::map_block* block2 = Maps::getTileBlock(pt2);
@ -358,34 +332,33 @@ command_result diggingInvadersFunc(color_ostream& out, std::vector<std::string>&
if ( pt1.z != pt2.z && shape1 != df::enums::tiletype_shape::STAIR_DOWN && shape1 != df::enums::tiletype_shape::STAIR_UPDOWN ) { if ( pt1.z != pt2.z && shape1 != df::enums::tiletype_shape::STAIR_DOWN && shape1 != df::enums::tiletype_shape::STAIR_UPDOWN ) {
block1->tiletype[pt2.x&0x0F][pt2.y&0x0F] = df::enums::tiletype::ConstructedStairUD; block1->tiletype[pt2.x&0x0F][pt2.y&0x0F] = df::enums::tiletype::ConstructedStairUD;
where = pt2;
didSomething = true;
break;
} }
if ( ENUM_ATTR(tiletype_shape, basic_shape, shape2) == df::enums::tiletype_shape_basic::Wall ) { if ( ENUM_ATTR(tiletype_shape, basic_shape, shape2) == df::enums::tiletype_shape_basic::Wall ) {
block2->tiletype[pt2.x&0x0F][pt2.y&0x0F] = df::enums::tiletype::ConstructedStairUD; block2->tiletype[pt2.x&0x0F][pt2.y&0x0F] = df::enums::tiletype::ConstructedStairUD;
didSomething = true;
where = pt2;
break;
} }
} }
/*if ( e.p1.z == e.p2.z ) {
}*/
importance[e.p1]++;
importance[e.p2]++;
} }
#if 0 if ( !didSomething )
//dig important points return;
for ( auto a = importance.begin(); a != importance.end(); a++ ) {
df::coord pos = (*a).first; Cost cost = costMap[where];
int32_t cost = (*a).second; int32_t cost_tick = 0;
if ( cost < 1 ) for ( size_t a = 0; a < costDim; a++ ) {
continue; cost_tick += cost.cost[a];
out.print("Requires action: (%d,%d,%d): %d\n", pos.x,pos.y,pos.z, cost);
df::map_block* block = Maps::getTileBlock(pos);
block->tiletype[pos.x&0x0F][pos.y&0x0F] = df::enums::tiletype::ConstructedStairUD;
} }
#endif
EventManager::EventHandler handle(doDiggingInvaders);
return CR_OK; Plugin* me = Core::getInstance().getPluginManager()->getPluginByName("diggingInvaders");
EventManager::registerTick(handle, cost_tick, me);
df::global::world->reindex_pathfinding = true;
} }
bool important(df::coord pos, map<df::coord, set<Edge> >& edges, df::coord prev, set<df::coord>& importantPoints, set<Edge>& importantEdges) { bool important(df::coord pos, map<df::coord, set<Edge> >& edges, df::coord prev, set<df::coord>& importantPoints, set<Edge>& importantEdges) {
@ -407,7 +380,45 @@ bool important(df::coord pos, map<df::coord, set<Edge> >& edges, df::coord prev,
return result; return result;
} }
vector<Edge>* getEdgeSet(color_ostream &out, df::coord point, int32_t xMax, int32_t yMax, int32_t zMax) { int32_t getDestroyCost(df::building* building) {
return 1000 / destroySpeed;
#if 0
if ( building->mat_type != 0 ) {
cerr << "Error " << __FILE__ << ", " << __LINE__ << endl;
exit(1);
}
df::inorganic_raw* mat = df::global::world->raws.inorganics[building->mat_index];
int32_t str = mat->material.strength.fracture[df::enums::strain_type::IMPACT];
return str / destroySpeed;
#endif
}
int32_t getDigCost(MapExtras::MapCache& cache, df::coord point) {
//TODO: check for constructions
return 10000 / digSpeed;
#if 0
df::tiletype* type = Maps::getTileType(point);
df::enums::tiletype_material::tiletype_material ttmat = ENUM_ATTR(tiletype, material, *type);
if ( ttmat == df::enums::tiletype_material::CONSTRUCTION ) {
//construction stuff
return 1;
} else if ( ttmat == df::enums::tiletype_material::SOIL ) {
}
return 1;
#endif
}
int32_t getDeconstructCost(df::coord point) {
return 10000 / deconstructSpeed;
}
int32_t getConstructCost(df::coord point) {
return 100000 / constructSpeed;
}
vector<Edge>* getEdgeSet(color_ostream &out, df::coord point, MapExtras::MapCache& cache, int32_t xMax, int32_t yMax, int32_t zMax) {
vector<Edge>* result = new vector<Edge>; vector<Edge>* result = new vector<Edge>;
for ( int32_t dx = -1; dx <= 1; dx++ ) { for ( int32_t dx = -1; dx <= 1; dx++ ) {
@ -443,14 +454,14 @@ vector<Edge>* getEdgeSet(color_ostream &out, df::coord point, int32_t xMax, int3
df::building* building1 = Buildings::findAtTile(point); df::building* building1 = Buildings::findAtTile(point);
df::building* building2 = Buildings::findAtTile(neighbor); df::building* building2 = Buildings::findAtTile(neighbor);
if ( building2 != NULL && building2 != building1 ) { if ( building2 != NULL && building2 != building1 ) {
cost.cost[1] += 1; cost.cost[1] += getDestroyCost(building2);
if ( dz != 0 ) if ( dz != 0 )
continue; continue;
} }
} }
if ( shape2 == df::enums::tiletype_shape::EMPTY ) { if ( shape2 == df::enums::tiletype_shape::EMPTY ) {
cost.cost[3] += 1; cost.cost[3] += getConstructCost(neighbor);
} else { } else {
if ( point.z == neighbor.z ) { if ( point.z == neighbor.z ) {
if ( ENUM_ATTR(tiletype_shape, walkable, shape2) ) { if ( ENUM_ATTR(tiletype_shape, walkable, shape2) ) {
@ -460,7 +471,7 @@ vector<Edge>* getEdgeSet(color_ostream &out, df::coord point, int32_t xMax, int3
//TODO: check //TODO: check
df::building* building = Buildings::findAtTile(neighbor); df::building* building = Buildings::findAtTile(neighbor);
if ( building != NULL ) if ( building != NULL )
cost.cost[1]+=1; cost.cost[1]+=getDestroyCost(building);
else { else {
building = Buildings::findAtTile(point); building = Buildings::findAtTile(point);
if ( building == NULL ) { if ( building == NULL ) {
@ -473,7 +484,7 @@ vector<Edge>* getEdgeSet(color_ostream &out, df::coord point, int32_t xMax, int3
} }
//this is fine: only charge once for digging through a wall //this is fine: only charge once for digging through a wall
} else { } else {
cost.cost[2] += 1; cost.cost[2] += getDigCost(cache, neighbor);
} }
} else { } else {
bool ascending = neighbor.z > point.z; bool ascending = neighbor.z > point.z;
@ -487,7 +498,12 @@ vector<Edge>* getEdgeSet(color_ostream &out, df::coord point, int32_t xMax, int3
if ( ENUM_ATTR(tiletype_shape, basic_shape, shape2) == df::enums::tiletype_shape_basic::Stair ) { if ( ENUM_ATTR(tiletype_shape, basic_shape, shape2) == df::enums::tiletype_shape_basic::Stair ) {
if ( (ascending && ENUM_ATTR(tiletype_shape, passable_low, shape2)) || (!ascending && ENUM_ATTR(tiletype_shape, walkable_up, shape2)) ) { if ( (ascending && ENUM_ATTR(tiletype_shape, passable_low, shape2)) || (!ascending && ENUM_ATTR(tiletype_shape, walkable_up, shape2)) ) {
//must be a forbidden hatch: TODO: check //must be a forbidden hatch: TODO: check
cost.cost[1] += 1; df::building* building = Buildings::findAtTile(dz < 0 ? point : neighbor);
if ( building != NULL ) {
cost.cost[1] += getDestroyCost(building);
} else {
out.print("%s, line %d: Weirdness (%d,%d,%d), (%d,%d,%d).\n", __FILE__, __LINE__, point.x,point.y,point.z, neighbor.x,neighbor.y,neighbor.z);
}
} else { } else {
//too complicated //too complicated
continue; continue;
@ -495,9 +511,9 @@ vector<Edge>* getEdgeSet(color_ostream &out, df::coord point, int32_t xMax, int3
} else { } else {
//bad! //bad!
if ( ENUM_ATTR(tiletype_shape, basic_shape, shape2) == df::enums::tiletype_shape_basic::Wall ) { if ( ENUM_ATTR(tiletype_shape, basic_shape, shape2) == df::enums::tiletype_shape_basic::Wall ) {
cost.cost[2] += 1; cost.cost[2] += getDigCost(cache, neighbor);
} else if ( ENUM_ATTR(tiletype_shape, basic_shape, shape2) == df::enums::tiletype_shape_basic::Open ) { } else if ( ENUM_ATTR(tiletype_shape, basic_shape, shape2) == df::enums::tiletype_shape_basic::Open ) {
cost.cost[3] += 1; cost.cost[3] += getConstructCost(neighbor);
} else { } else {
continue; continue;
} }