dfhack
dfhack copied to clipboard
Channel-Safely should detect inaccessible designations
This is something I'm currently working on, however I'm struggling to grasp a sufficient algorithm. The images below depict designations (circled) which will never be accessible.
The first pair had channel designations between where that gap is, so it they could be reached if those gap designations had of been swapped for dig designations and channeled after the circled were completed. Doing so doesn't strike me as urgent though and I think it's more important to figure out how to determine they are inaccessible.
I currently have the following algorithm (not merged, or even pushed). As mentioned this isn't sufficient, and results in undesirable behaviour (such as insta-digging that gap)
uint8_t count_accessibility(const df::coord &map_pos) {
df::coord neighbours[8];
get_neighbours(map_pos, neighbours);
uint8_t accessibility = 0;
for (auto n: neighbours) {
if (Maps::canStepBetween(map_pos, n)) {
accessibility++;
}
}
return accessibility;
}
void ChannelManager::manage_group(const Group &group, bool set_marker_mode, bool marker_mode) {
...
// cavein prevention
bool cavein_possible = false;
uint8_t least_access = 10;
std::unordered_map<df::coord, uint8_t> cavein_candidates;
if (!marker_mode) {
for (const auto &pos: group) {
df::coord below(pos);
below.z--;
auto ttype = *Maps::getTileType(below);
if (DFHack::isOpenTerrain(ttype) || DFHack::isFloorTerrain(ttype)) {
cavein_possible = true;
auto access = count_accessibility(pos);
if (access == 0) {
if (config.insta_dig){
CSP::dignow_queue.emplace(pos);
}
} else {
cavein_candidates.emplace(pos, access);
least_access = min(least_access, access);
}
}
}
}
// managing designations
for (auto &pos: group) {
if (cavein_possible) {
// cavein is only possible if marker_mode is false
// todo: dig least accessible designations, first
if ((cavein_candidates.count(pos) && cavein_candidates[pos] == least_access) || CSP::dignow_queue.count(pos)) {
// we want to dig the cavein candidates first
manage_one(pos, true, false);
} else {
manage_one(pos, true, true);
}
} else {
manage_one(pos, true, marker_mode);
}
}
...