dfhack icon indicating copy to clipboard operation
dfhack copied to clipboard

Channel-Safely should detect inaccessible designations

Open cppcooper opened this issue 1 year ago • 11 comments

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. image image image

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);
        }
    }
...

cppcooper avatar Dec 03 '22 02:12 cppcooper