Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix gas saturation #34

Open
alkurbatov opened this issue May 15, 2020 · 5 comments
Open

Fix gas saturation #34

alkurbatov opened this issue May 15, 2020 · 5 comments
Labels

Comments

@alkurbatov
Copy link
Owner

We constantly have too many workers (e.g. 5 instead of 3) gathering the same refinery.

@ImpulseCloud
Copy link
Contributor

ImpulseCloud commented Mar 4, 2021

@alkurbatov It looks like there is currently no way I can iterate through the "Cache m_busy_workers".
I'd like to iterate through the m_busy_workers to find a vespene gatherer for a specific Refinery. (to avoid a call to GetUnits which iterates through the whole unit_pool)

void Hub::RemoveVespeneHarvester(const sc2::Unit& refinery_) {
    auto it = std::find_if(m_busy_workers.begin(), m_busy_workers.end(),
    [refinery_](const Worker& worker_)->const sc2::Unit* {
        const sc2::Unit* unit = gAPI->observer().GetUnit(worker_.Tag());
        if (unit && !unit->orders.empty() &&
            unit->orders.front().target_unit_tag == refinery_.tag &&
            unit->last_seen_game_loop == gAPI->observer().GetGameLoop()) {
            return unit;
        }
        return nullptr;
    });

    ...

Should a begin() and end() be added to Cache for iteration purposes? Or should Cache be able to take a lambda and return the first valid object?

@ImpulseCloud
Copy link
Contributor

ImpulseCloud commented Mar 4, 2021

My current fix relies on PR #50 , so I believe I have to wait til that's resolved to make a PR for this one.

But, here's the relevant new code:

const sc2::Unit* Hub::RemoveVespeneHarvester(const sc2::Unit& refinery_) {
    Units workers = gAPI->observer().GetUnits(sc2::IsUnit(m_current_worker_type));
    auto vespener = std::find_if(workers().begin(), workers().end(),
    [refinery_](const sc2::Unit* unit_)->const sc2::Unit* {
        if (!unit_->orders.empty() &&
            unit_->orders.front().target_unit_tag == refinery_.tag &&
            unit_->last_seen_game_loop == gAPI->observer().GetGameLoop()) {
            return unit_;
        }
        return nullptr;
    });

    if (!*vespener)
        return nullptr;

    return *vespener;
}

// this is in Miner.cpp
void SecureVespeneIncome() {
    auto refineries = gAPI->observer().GetUnits(IsRefinery());
    auto town_halls = gAPI->observer().GetUnits(sc2::IsTownHall());

    for (const auto& i : refineries()) {
        if (i->assigned_harvesters > 3) {  // gas ideal_harvesters is always 3
            const sc2::Unit* removed = gHub->RemoveVespeneHarvester(*i);
            DistrubuteMineralWorker(removed);
            continue;
        }

        if (i->assigned_harvesters == 3)  // gas already saturated
            continue;

        auto close_town_hall = town_halls.GetClosestUnit(i->pos);
        if (close_town_hall &&
            close_town_hall->assigned_harvesters > close_town_hall->ideal_harvesters) {
            gHub->AssignVespeneHarvester(*i); //reassign overflow mineral workers
            continue;
        }

        gHub->AssignVespeneHarvester(*i);
    }
}

@alkurbatov
Copy link
Owner Author

alkurbatov commented Mar 5, 2021

What do you think about keeping list of assigned gatherers in each geyser object?
Although I am not sure that such precise estimation is needed. The simplest option in the current design is to allow retrieval of a const reference to the busy workers list.

@ImpulseCloud
Copy link
Contributor

Yes, I do think keeping a list of assigned gatherers per geyser is good.

(also a list per mineral-patch will be needed eventually, in order to maintain 2 workers on close-mineral-patches, since sometimes they stray on auto-gather).

ImpulseCloud added a commit to ImpulseCloud/suvorov-Impulse that referenced this issue Mar 15, 2021
If gas oversaturated, remove from busy_workers and call DistributeWorker.
If gas under-saturated and any base is mineral-oversaturated, send one of those mineral workers to that gas.
@ImpulseCloud
Copy link
Contributor

Since you prefer lambdas, I changed RemoveVespeneHarvester to:

const sc2::Unit* Hub::RemoveVespeneHarvester(const sc2::Unit& refinery_) {
    const std::list<Worker>& workers = m_busy_workers();
    auto vespener = std::find_if(workers.begin(), workers.end(),
    [refinery_](const Worker& worker_) {
        const sc2::Unit* unit = gAPI->observer().GetUnit(worker_.Tag());
        return !unit->orders.empty() &&
            unit->orders.front().target_unit_tag == refinery_.tag &&
            unit->last_seen_game_loop == gAPI->observer().GetGameLoop();
    });

    if (vespener == workers.end())
        return nullptr;

    m_busy_workers.Swap(*vespener, m_free_workers);

    return gAPI->observer().GetUnit((*vespener).Tag());
}

If you want this function (and AssignVespeneHarvester) moved from Hub to Miner, I'll have to add a Hub::GetBusyWorkers that returns a const list reference.

ImpulseCloud added a commit to ImpulseCloud/suvorov-Impulse that referenced this issue Mar 19, 2021
Checks each refinery for oversaturation, and finds a worker on its way to refinery (not-inside-refinery) to STOP and force OnIdle next turn to be re-distributed to minerals.
ImpulseCloud added a commit to ImpulseCloud/suvorov-Impulse that referenced this issue Mar 21, 2021
Only check vespene workers every 10 frames, to prevent too many vespene workers from being added and oversaturated.
ImpulseCloud added a commit to ImpulseCloud/suvorov-Impulse that referenced this issue Mar 21, 2021
Only check vespene workers every 10 frames, to prevent too many vespene workers from being added and oversaturated.
ImpulseCloud added a commit to ImpulseCloud/suvorov-Impulse that referenced this issue Mar 28, 2021
Only check vespene workers every 7 frames, to prevent too many vespene workers from being added and oversaturated. Also, create functionality for other Plugin-derived classes to run every X turns.
ImpulseCloud added a commit to ImpulseCloud/suvorov-Impulse that referenced this issue Mar 28, 2021
Only check vespene workers every 7 frames, to prevent too many vespene workers from being added and oversaturated. Also, create functionality for other Plugin-derived classes to run every X turns.
ImpulseCloud added a commit to ImpulseCloud/suvorov-Impulse that referenced this issue Mar 28, 2021
Only check vespene workers every 7 frames, to prevent too many vespene workers from being added and oversaturated. Also, create functionality for other Plugin-derived classes to run every X turns.
ImpulseCloud added a commit to ImpulseCloud/suvorov-Impulse that referenced this issue Mar 30, 2021
Only check vespene workers every 7 gameloops, to prevent too many vespene workers from being added and oversaturated. Also, create functionality for other Plugin-derived classes to run every X gameloops.
ImpulseCloud added a commit to ImpulseCloud/suvorov-Impulse that referenced this issue Mar 30, 2021
Only check vespene workers every 7 steps, to prevent too many vespene workers from being added and oversaturated. Also, create functionality for other Plugin-derived classes to run every X steps.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants