Exemplo n.º 1
0
const FrameCountType GameState::whenGasReady(const ActionType & action) const
{
    if (_gas >= action.gasPrice())
    {
        return getCurrentFrame();
    }
    
    UnitCountType currentMineralWorkers     = _units.getNumMineralWorkers();
    UnitCountType currentGasWorkers         = _units.getNumGasWorkers();
    FrameCountType lastActionFinishFrame    = _currentFrame;
    FrameCountType addedTime                = 0;
    ResourceCountType addedGas              = 0;
    ResourceCountType difference            = action.gasPrice() - _gas;

    // loop through each action in progress, adding the minerals we would gather from each interval
    for (size_t i(0); i<_units.getNumActionsInProgress(); ++i)
    {
        // the vector is sorted in descending order
        size_t progressIndex = _units.getNumActionsInProgress() - i - 1;

        // the time elapsed and the current minerals per frame
        FrameCountType elapsed = _units.getFinishTimeByIndex(progressIndex) - lastActionFinishFrame;
        ResourceCountType gasPerFrame = (currentGasWorkers * Constants::GPWPF);

        // the amount of minerals that would be added this time step
        ResourceCountType tempAdd = elapsed * gasPerFrame;

        // if this amount isn't enough, update the amount added for this interval
        if (addedGas + tempAdd < difference)
        {
            addedGas += tempAdd;
            addedTime += elapsed;
        }
        else
        {
            // otherwise we can just break out and update at the end
            break;
        }

        // if it was a drone or extractor update the temp variables
        const ActionType & actionPerformed = _units.getActionInProgressByIndex(progressIndex);

        // finishing a building as terran gives you a mineral worker back
        if (actionPerformed.isBuilding() && !actionPerformed.isAddon() && (getRace() == Races::Terran))
        {
            currentMineralWorkers++;
        }

        if (actionPerformed.isWorker())
        {
            currentMineralWorkers++;
        }
        else if (actionPerformed.isRefinery())
        {
            BOSS_ASSERT(currentMineralWorkers > 3, "Not enough mineral workers");
            currentMineralWorkers -= 3; currentGasWorkers += 3;
        }

        // update the last action
        lastActionFinishFrame = _units.getFinishTimeByIndex(progressIndex);
    }

    // if we still haven't added enough minerals, add more time
    if (addedGas < difference)
    {
		BOSS_ASSERT(currentGasWorkers > 0, "Shouldn't have 0 gas workers");
		FrameCountType finalTimeToAdd;
		if (currentGasWorkers != 0)
		{
			finalTimeToAdd = (difference - addedGas) / (currentGasWorkers * Constants::GPWPF);
		}
		else
		{
			finalTimeToAdd = 1000000;
		}
        addedGas    += finalTimeToAdd * currentGasWorkers * Constants::GPWPF;
        addedTime   += finalTimeToAdd;

        // the last operation could have added one frame too little due to integer division so we need to check
        if (addedGas < difference)
        {
            addedTime += 1;
            addedGas += currentGasWorkers * Constants::GPWPF;
        }
    }
    
    BOSS_ASSERT(addedGas >= difference, "Gas prediction error");

    // for some reason if i don't return +1, i mine 1 less mineral in the interval
    return _currentFrame + addedTime;
}
Exemplo n.º 2
0
bool GameState::canAffordGas(const ActionType & action) const
{
    return _gas >= action.gasPrice();
}
Exemplo n.º 3
0
// do an action, action must be legal for this not to break
std::vector<ActionType> GameState::doAction(const ActionType & action)
{
    BOSS_ASSERT(action.getRace() == _race, "Race of action does not match race of the state");

    _actionsPerformed.push_back(ActionPerformed());
    _actionsPerformed[_actionsPerformed.size()-1].actionType = action;

    BOSS_ASSERT(isLegal(action), "Trying to perform an illegal action: %s %s", action.getName().c_str(), getActionsPerformedString().c_str());
    
    // set the actionPerformed
    _actionPerformed = action;
    _actionPerformedK = 1;

    FrameCountType workerReadyTime = whenWorkerReady(action);
    FrameCountType ffTime = whenCanPerform(action);

    BOSS_ASSERT(ffTime >= 0 && ffTime < 1000000, "FFTime is very strange: %d", ffTime);

    auto actionsFinished=fastForward(ffTime);

    _actionsPerformed[_actionsPerformed.size()-1].actionQueuedFrame = _currentFrame;
    _actionsPerformed[_actionsPerformed.size()-1].gasWhenQueued = _gas;
    _actionsPerformed[_actionsPerformed.size()-1].mineralsWhenQueued = _minerals;

    // how much time has elapsed since the last action was queued?
    FrameCountType elapsed(_currentFrame - _lastActionFrame);
    _lastActionFrame = _currentFrame;

    BOSS_ASSERT(canAffordMinerals(action),   "Minerals less than price: %ld < %d, ffTime=%d %s", _minerals, action.mineralPrice(), (int)elapsed, action.getName().c_str());
    BOSS_ASSERT(canAffordGas(action),       "Gas less than price: %ld < %d, ffTime=%d %s", _gas, action.gasPrice(), (int)elapsed, action.getName().c_str());

    // modify our resources
    _minerals   -= action.mineralPrice();
    _gas        -= action.gasPrice();

    // do race specific things here
    if (getRace() == Races::Protoss)
    {
        _units.addActionInProgress(action, _currentFrame + action.buildTime());    
    }
    else if (getRace() == Races::Terran)
    {
        if (action.isBuilding() && !action.isAddon())
        {
            if (getNumMineralWorkers() == 0)
            {
                std::cout << toString() << std::endl;
            }

            BOSS_ASSERT(getNumMineralWorkers() > 0, "Don't have any mineral workers to assign");
            _units.setBuildingWorker();
        }

        _units.addActionInProgress(action, _currentFrame + action.buildTime());
    }
    else if (getRace() == Races::Zerg)
    {
     	//  zerg must subtract a larva if the action was unit creation
    	if (action.isUnit() && !action.isBuilding()) 
        {
            if (action.isMorphed())
            {
                _units.morphUnit(action.whatBuildsActionType(), action, _currentFrame + action.buildTime());   
            }
            else
            {
                BOSS_ASSERT(getHatcheryData().numLarva() > 0, "We should have a larva to use");
                _units.getHatcheryData().useLarva();
                _units.addActionInProgress(action, _currentFrame + action.buildTime());
            }
     	}
     	else if (action.isBuilding())
     	{
            _units.morphUnit(action.whatBuildsActionType(), action, _currentFrame + action.buildTime());
     	}
        else
        {
            // if it's not a unit or a building it's a tech so we queue it normally
            _units.addActionInProgress(action, _currentFrame + action.buildTime());
        }
     }

	return actionsFinished;
}