//--------------------------------------------- HAS PATH --------------------------------------------------- bool UnitInterface::hasPath(PositionOrUnit target) const { Broodwar->setLastError(); // Return error if the position is invalid if ( !target.getPosition() ) return Broodwar->setLastError(Errors::Invalid_Parameter); // Return true if this unit is an air unit if ( this->isFlying() ) return true; // Return error if either this or the target does not "exist" if ( (target.getUnit() && !target.getUnit()->exists()) || !exists() ) return Broodwar->setLastError(Errors::Unit_Not_Visible); // return result of Game::hasPath return Broodwar->hasPath(this->getPosition(), target.getPosition()); }
//--------------------------------------------- GET DISTANCE ----------------------------------------------- int UnitImpl::getDistance(PositionOrUnit target) const { // If this unit does not exist if ( !exists() ) return MAXINT; // Must be something valid if ( !target.getUnit() && !target.getPosition() ) return MAXINT; // if target is a unit but doesn't exist if ( target.getUnit() && !target.getUnit()->exists() ) return MAXINT; // If target is the same as the source if ( this == target.getUnit() ) return MAXINT; // Compute distance return computeDistance(this, target); }
//--------------------------------------------- GET DISTANCE ----------------------------------------------- int UnitInterface::getDistance(PositionOrUnit target) const { // If this unit does not exist if ( !exists() ) return std::numeric_limits<int>::max(); // Must be something valid if ( !target.getUnit() && !target.getPosition() ) return std::numeric_limits<int>::max(); // if target is a unit but doesn't exist if ( target.getUnit() && !target.getUnit()->exists() ) return std::numeric_limits<int>::max(); // If target is the same as the source if ( this == target.getUnit() ) return std::numeric_limits<int>::max(); /////// Compute distance // retrieve left/top/right/bottom values for calculations int left, right, top, bottom; if ( target.isPosition() ) { // Retrieve the target position if it is so Position targPos = target.getPosition(); left = targPos.x - 1; top = targPos.y - 1; right = targPos.x + 1; bottom = targPos.y + 1; } else { // Retrieve the target unit if it's not a position Unit pUnit = target.getUnit(); // return if target is invalid if ( !pUnit || pUnit == this ) return 0; left = pUnit->getLeft() - 1; top = pUnit->getTop() - 1; right = pUnit->getRight() + 1; bottom = pUnit->getBottom() + 1; } // compute x distance int xDist = this->getLeft() - right; if ( xDist < 0 ) { xDist = left - this->getRight(); if ( xDist < 0 ) xDist = 0; } // compute y distance int yDist = this->getTop() - bottom; if ( yDist < 0 ) { yDist = top - this->getBottom(); if ( yDist < 0 ) yDist = 0; } // compute actual distance return Positions::Origin.getApproxDistance(Position(xDist, yDist)); }
//--------------------------------------------- USE TECH --------------------------------------------------- bool UnitInterface::useTech(TechType tech, PositionOrUnit target) { if ( target.isUnit() && target.getUnit() == nullptr ) return this->issueCommand(UnitCommand::useTech(this,tech)); return this->issueCommand(UnitCommand::useTech(this,tech,target)); }
//--------------------------------------------- USE TECH --------------------------------------------------- bool Unitset::useTech(TechType tech, PositionOrUnit target) const { if ( target.isUnit() && target.getUnit() == nullptr ) return this->issueCommand(UnitCommand::useTech(nullptr,tech)); return this->issueCommand(UnitCommand::useTech(nullptr,tech,target)); }
void DesolatorModule::onFrame() { auto & ourUnits = us_->getUnits(); auto & theirUnits = them_->getUnits(); // Return if the game is a replay or is paused if ( Broodwar->isReplay() || Broodwar->isPaused() || !Broodwar->self() ) return; // Prevent spamming by only running our onFrame once every number of latency frames. // Latency frames are the number of frames before commands are processed. if ( Broodwar->getFrameCount() % Broodwar->getLatencyFrames() != 0 ) return; /************************/ /**** DESOLATOR CODE ****/ /************************/ if ( theirUnits.empty() ) { // cout << "Exploring" << endl; for (auto u : ourUnits) { unitStates_[u->getID()].setNoDraw(); } // Only move when idle. if(!ourUnits.begin()->isMoving()) { ourUnits.move(AI::explore()); } } else { //cout << "New action frame" << endl; // This updates the game state for each unit we have ( not the MDP state though ) for ( auto u : ourUnits ) updateUnitState(u); //cout << "Basic update completed" << endl; for ( auto u : ourUnits ) shareKnowledge(u); //cout << "Shares completed" << endl; // Now that the observations of the units are correct, we select the actions that we want the units to perform. for ( auto u : ourUnits ) { auto & GS = unitStates_[u->getID()]; //cout << "Executing unit " << u->getID() << endl; // Check when the units moved a tile bool moved = GS.updatePosition(u->getTilePosition()); // Hack to avoid units stopping while actually moving.. if ( !moved && GS.lastAction == Action::Move && GS.lastPerfectPosition == u->getPosition() ) GS.notMovingTurns++; else { GS.lastPerfectPosition = u->getPosition(); GS.notMovingTurns = 0; } //cout << "- unit movement updates done" << endl; // If our personal tick ended if ( u->isIdle() || moved || GS.lastAction == Action::None || ( GS.lastAction == Action::Attack && ! GS.isStartingAttack && ! u->isAttackFrame() ) ) { //cout << "- UNIT TICK" << endl; updateUnitMDPState(u); //cout << "- UNIT MDP updated state" << endl; Strategy strategy; Action action; int selectedAction = 0; //cout << "We use policy? " << usingPolicy_ << endl; // We check if we follow the policy or we go full random if (usingPolicy_) { AIToolbox::EpsilonPolicy p(policy_,1); selectedAction = p.sampleAction(GS.state); } else selectedAction = RandomInt::get(0,1); //selectedAction = 1; //cout << "Got action: " << selectedAction << endl; switch ( selectedAction ) { case 1: { // We flee strategy = Strategy::Flee; //cout << "Flee!" << endl; // Obtain where to flee auto position = AI::flee(u, ourUnits, theirUnits, unitStates_); action = moveUnitToPosition(u, position); break; } default: { // We attack strategy = Strategy::Fight; action = Action::Attack; //cout << "Fight" << endl; // Obtain who to attack or where to go PositionOrUnit target = AI::attack(u, ourUnits, theirUnits, unitStates_); if ( target.isPosition() ) { action = moveUnitToPosition(u, target.getPosition()); } // This check is to avoid breaking Starcraft when we spam attack command else { if ( u->getOrder() != Orders::AttackUnit || unitStates_[u->getID()].lastTarget != target.getUnit() ) { u->attack(target.getUnit()); GS.isStartingAttack = true; GS.lastTarget = target.getUnit(); GS.setDraw(target); //cout << "Attack" << endl; } } } } //cout << "UNIT action selected" << strategy << endl; // Update Action taken GS.lastStrategy = strategy; GS.lastAction = action; } // End, personal tick // End of hack, here we stop the units so I guess internally it resets so we can move it again. else if ( GS.notMovingTurns == 3 ) { //Broodwar->printf("Unit %d triggered an hack", u->getID()); log_ << "HACK TRIGGERED" << "\n"; log_ << "Action: " << GS.lastAction << " -- Strategy: " << GS.lastStrategy << "\n"; log_ << "Order: " << u->getOrder() << " -- Position: " << u->getPosition() << " -- Target Position: " << u->getTargetPosition() << "\n"; log_ << "Diff = " << u->getPosition() - u->getTargetPosition() << "\n"; log_ << "Unit Tile: " << convertToTile(u->getPosition()) << " -- Target Tile: " << convertToTile(u->getTargetPosition()) << "\n"; u->stop(); GS.setNoDraw(); } } // closure: unit iterator } // closure: We have enemies }