void Player_Random::getMoves(GameState & state, const MoveArray & moves, std::vector<Move> & moveVec) { for (size_t u(0); u<moves.numUnits(); u++) { moveVec.push_back(moves.getMove(u, rand() % moves.numMoves(u))); } }
void GameState::generateMoves(MoveArray & moves, const IDType & playerIndex) const { moves.clear(); // which is the enemy player IDType enemyPlayer = getEnemy(playerIndex); // we are interested in all simultaneous moves // so return all units which can move at the same time as the first TimeType firstUnitMoveTime = getUnit(playerIndex, 0).firstTimeFree(); for (IDType unitIndex(0); unitIndex < _numUnits[playerIndex]; ++unitIndex) { // unit reference const Unit & unit(getUnit(playerIndex,unitIndex)); // if this unit can't move at the same time as the first if (unit.firstTimeFree() != firstUnitMoveTime) { // stop checking break; } if (unit.previousMoveTime() == _currentTime && _currentTime != 0) { // CHANGED // printf("ERROR: Previous Move: %s\n", unit.previousMove().moveString().c_str()); int a = 6; } moves.addUnit(); // generate attack moves if (unit.canAttackNow()) { for (IDType u(0); u<_numUnits[enemyPlayer]; ++u) { const Unit & enemyUnit(getUnit(enemyPlayer, u)); if (unit.canAttackTarget(enemyUnit, _currentTime) && enemyUnit.isAlive()) { moves.add(Move(unitIndex, playerIndex, MoveTypes::ATTACK, u)); } } } else if (unit.canHealNow()) { for (IDType u(0); u<_numUnits[playerIndex]; ++u) { // units cannot heal themselves in broodwar if (u == unitIndex) { continue; } const Unit & ourUnit(getUnit(playerIndex, u)); if (unit.canHealTarget(ourUnit, _currentTime) && ourUnit.isAlive()) { moves.add(Move(unitIndex, playerIndex, MoveTypes::HEAL, u)); } } } // generate the wait move if it can't attack yet else { if (!unit.canHeal()) { moves.add(Move(unitIndex, playerIndex, MoveTypes::RELOAD, 0)); } } // generate movement moves if (unit.isMobile()) { for (IDType d(0); d<Search::Constants::Num_Directions; ++d) { Move move(unitIndex, playerIndex, MoveTypes::MOVE, d); Position dest; Position dir(Search::Constants::Move_Dir[move._moveIndex][0], Search::Constants::Move_Dir[move._moveIndex][1]); // if the unit can attack the destination will be set by default move distance if (unit.canAttackNow() || unit.canHeal()) { dest = Position(Search::Constants::Move_Distance*dir.x(), Search::Constants::Move_Distance*dir.y()) + unit.pos(); } // otherwise it will be a move until attack move else { dest = unit.getMoveUntilAttackDest(dir, _currentTime); } if (isWalkable(dest)) { moves.add(Move(unitIndex, playerIndex, MoveTypes::MOVE, d)); } } } // if no moves were generated for this unit, it must be issued a 'PASS' move if (moves.numMoves(unitIndex) == 0) { moves.add(Move(unitIndex, playerIndex, MoveTypes::PASS, 0)); } } if (!moves.validateMoves()) { fprintf(stderr, "Moves invalid, something is wrong\n"); } }
void GameState::generateMoves(MoveArray & moves, const IDType & playerIndex) const { moves.clear(); // which is the enemy player IDType enemyPlayer = getEnemy(playerIndex); // make sure this player can move right now const IDType canMove(whoCanMove()); if (canMove == enemyPlayer) { System::FatalError("GameState Error - Called generateMoves() for a player that cannot currently move"); } // we are interested in all simultaneous moves // so return all units which can move at the same time as the first TimeType firstUnitMoveTime = getUnit(playerIndex, 0).firstTimeFree(); for (IDType unitIndex(0); unitIndex < _numUnits[playerIndex]; ++unitIndex) { // unit reference const Unit & unit(getUnit(playerIndex,unitIndex)); // if this unit can't move at the same time as the first if (unit.firstTimeFree() != firstUnitMoveTime) { // stop checking break; } if (unit.previousActionTime() == _currentTime && _currentTime != 0) { System::FatalError("Previous Move Took 0 Time: " + unit.previousAction().moveString()); } moves.addUnit(); // generate attack moves if (unit.canAttackNow()) { for (IDType u(0); u<_numUnits[enemyPlayer]; ++u) { const Unit & enemyUnit(getUnit(enemyPlayer, u)); bool invisible = false; if (enemyUnit.type().hasPermanentCloak()) { invisible = true; for (IDType detectorIndex(0); detectorIndex < _numUnits[playerIndex]; ++detectorIndex) { // unit reference const Unit & detector(getUnit(playerIndex, detectorIndex)); if (detector.type().isDetector() && detector.canSeeTarget(enemyUnit, _currentTime)) { invisible = false; break; } } } if (!invisible && unit.canAttackTarget(enemyUnit, _currentTime) && enemyUnit.isAlive()) { moves.add(Action(unitIndex, playerIndex, ActionTypes::ATTACK, u)); //moves.add(Action(unitIndex, playerIndex, ActionTypes::ATTACK, unit.ID())); } } } else if (unit.canHealNow()) { for (IDType u(0); u<_numUnits[playerIndex]; ++u) { // units cannot heal themselves in broodwar if (u == unitIndex) { continue; } const Unit & ourUnit(getUnit(playerIndex, u)); if (unit.canHealTarget(ourUnit, _currentTime) && ourUnit.isAlive()) { moves.add(Action(unitIndex, playerIndex, ActionTypes::HEAL, u)); //moves.add(Action(unitIndex, playerIndex, ActionTypes::HEAL, unit.ID())); } } } // generate the wait move if it can't attack yet else { if (!unit.canHeal()) { moves.add(Action(unitIndex, playerIndex, ActionTypes::RELOAD, 0)); } } // generate movement moves if (unit.isMobile()) { // In order to not move when we could be shooting, we want to move for the minimum of: // 1) default move distance move time // 2) time until unit can attack, or if it can attack, the next cooldown double timeUntilAttack = unit.nextAttackActionTime() - getTime(); timeUntilAttack = timeUntilAttack == 0 ? unit.attackCooldown() : timeUntilAttack; // the default move duration double defaultMoveDuration = (double)Constants::Move_Distance / unit.speed(); // if we can currently attack double chosenTime = timeUntilAttack != 0 ? std::min(timeUntilAttack, defaultMoveDuration) : defaultMoveDuration; // the chosen movement distance PositionType moveDistance = (PositionType)(chosenTime * unit.speed()); // DEBUG: If chosen move distance is ever 0, something is wrong if (moveDistance == 0) { System::FatalError("Move Action with distance 0 generated. timeUntilAttack:"+ std::to_string(timeUntilAttack)+", speed:"+std::to_string(unit.speed())); } // we are only generating moves in the cardinal direction specified in common.h for (IDType d(0); d<Constants::Num_Directions; ++d) { // the direction of this movement Position dir(Constants::Move_Dir[d][0], Constants::Move_Dir[d][1]); if (moveDistance == 0) { printf("%lf %lf %lf\n", timeUntilAttack, defaultMoveDuration, chosenTime); } // the final destination position of the unit Position dest = unit.pos() + Position(moveDistance*dir.x(), moveDistance*dir.y()); // if that poisition on the map is walkable if (isWalkable(dest) || (unit.type().isFlyer() && isFlyable(dest))) { // add the move to the MoveArray moves.add(Action(unitIndex, playerIndex, ActionTypes::MOVE, d, dest)); } } } // if no moves were generated for this unit, it must be issued a 'PASS' move if (moves.numMoves(unitIndex) == 0) { moves.add(Action(unitIndex, playerIndex, ActionTypes::PASS, 0)); } } }
void Player_NOKDPS::getMoves(GameState & state, const MoveArray & moves, std::vector<UnitAction> & moveVec) { moveVec.clear(); IDType enemy(state.getEnemy(_playerID)); Array<int, Constants::Max_Units> hpRemaining; for (IDType u(0); u<state.numUnits(enemy); ++u) { hpRemaining[u] = state.getUnit(enemy,u).currentHP(); } for (IDType u(0); u<moves.numUnits(); ++u) { bool foundUnitAction (false); size_t actionMoveIndex (0); double actionHighestDPS (0); size_t closestMoveIndex (0); unsigned long long closestMoveDist (std::numeric_limits<unsigned long long>::max()); const Unit & ourUnit (state.getUnit(_playerID, u)); const Unit & closestUnit(ourUnit.canHeal() ? state.getClosestOurUnit(_playerID, u) : ourUnit.type().isDetector() ? state.getClosestEnemyUnit(_playerID, u, false):state.getClosestEnemyUnit(_playerID, u, true)); for (size_t m(0); m<moves.numMoves(u); ++m) { const UnitAction move (moves.getMove(u, m)); if ((move.type() == UnitActionTypes::ATTACK) && (hpRemaining[move._moveIndex] > 0)) { const Unit & target (state.getUnit(state.getEnemy(move.player()), move._moveIndex)); double dpsHPValue = (target.dpf() / hpRemaining[move._moveIndex]); if (dpsHPValue > actionHighestDPS) { actionHighestDPS = dpsHPValue; actionMoveIndex = m; foundUnitAction = true; } if (move._moveIndex >= state.numUnits(enemy)) { int e = enemy; int pl = _playerID; printf("wtf\n"); } } else if (move.type() == UnitActionTypes::HEAL) { const Unit & target (state.getUnit(move.player(), move._moveIndex)); double dpsHPValue = (target.dpf() / hpRemaining[move._moveIndex]); if (dpsHPValue > actionHighestDPS) { actionHighestDPS = dpsHPValue; actionMoveIndex = m; foundUnitAction = true; } } else if (move.type() == UnitActionTypes::RELOAD) { if (ourUnit.canAttackTarget(closestUnit, state.getTime())) { closestMoveIndex = m; break; } } else if (move.type() == UnitActionTypes::MOVE) { Position ourDest (ourUnit.x() + Constants::Move_Dir[move._moveIndex][0], ourUnit.y() + Constants::Move_Dir[move._moveIndex][1]); size_t dist (closestUnit.getDistanceSqToPosition(ourDest, state.getTime())); if (dist < closestMoveDist) { closestMoveDist = dist; closestMoveIndex = m; } } } size_t bestMoveIndex(foundUnitAction ? actionMoveIndex : closestMoveIndex); UnitAction theMove(moves.getMove(u, actionMoveIndex)); if (theMove.type() == UnitActionTypes::ATTACK) { hpRemaining[theMove.index()] -= state.getUnit(_playerID, theMove.unit()).damage(); } moveVec.push_back(moves.getMove(u, bestMoveIndex)); } }
const MoveTuple Player_AttackClosest::getMoveTuple(GameState & state, const MoveArray & moves) { MoveTuple tuple(0); for (IDType u(0); u<moves.numUnits(); ++u) { bool foundAction (false); size_t actionMoveIndex (0); size_t closestMoveIndex (0); unsigned long long actionDistance (std::numeric_limits<unsigned long long>::max()); unsigned long long closestMoveDist (std::numeric_limits<unsigned long long>::max()); const Unit & ourUnit (state.getUnit(_playerID, u)); const Unit & closestUnit (ourUnit.canHeal() ? state.getClosestOurUnit(_playerID, u) : state.getClosestEnemyUnit(_playerID, u)); for (size_t m(0); m<moves.numMoves(u); ++m) { const Move move (moves.getMove(u, m)); if (move.type() == MoveTypes::ATTACK) { const Unit & target (state.getUnit(state.getEnemy(move.player()), move._moveIndex)); size_t dist (ourUnit.distSq(target, state.getTime())); if (dist < actionDistance) { actionDistance = dist; actionMoveIndex = m; foundAction = true; } } if (move.type() == MoveTypes::HEAL) { const Unit & target (state.getUnit(move.player(), move._moveIndex)); size_t dist (ourUnit.distSq(target, state.getTime())); if (dist < actionDistance) { actionDistance = dist; actionMoveIndex = m; foundAction = true; } } else if (move.type() == MoveTypes::RELOAD) { if (ourUnit.canAttackTarget(closestUnit, state.getTime())) { closestMoveIndex = m; break; } } else if (move.type() == MoveTypes::MOVE) { Position ourDest (ourUnit.x() + Search::Constants::Move_Dir[move._moveIndex][0], ourUnit.y() + Search::Constants::Move_Dir[move._moveIndex][1]); size_t dist (closestUnit.distSq(ourDest, state.getTime())); if (dist < closestMoveDist) { closestMoveDist = dist; closestMoveIndex = m; } } } size_t bestMoveIndex(foundAction ? actionMoveIndex : closestMoveIndex); tuple += bestMoveIndex * moves.getProduct(u); } return tuple; }
void Player_KiterDPS::getMoves(GameState & state, const MoveArray & moves, std::vector<Move> & moveVec) { for (IDType u(0); u<moves.numUnits(); ++u) { bool foundAction (false); IDType actionMoveIndex (0); IDType furthestMoveIndex (0); size_t furthestMoveDist (0); IDType closestMoveIndex (0); double actionHighestDPS (0); unsigned long long closestMoveDist (std::numeric_limits<unsigned long long>::max()); const Unit & ourUnit (state.getUnit(_playerID, u)); const Unit & closestUnit (ourUnit.canHeal() ? state.getClosestOurUnit(_playerID, u) : state.getClosestEnemyUnit(_playerID, u)); for (IDType m(0); m<moves.numMoves(u); ++m) { const Move move (moves.getMove(u, m)); if (move.type() == MoveTypes::ATTACK) { const Unit & target (state.getUnit(state.getEnemy(move.player()), move._moveIndex)); double dpsHPValue (target.dpf() / target.currentHP()); if (dpsHPValue > actionHighestDPS) { actionHighestDPS = dpsHPValue; actionMoveIndex = m; foundAction = true; } } else if (move.type() == MoveTypes::HEAL) { const Unit & target (state.getUnit(move.player(), move._moveIndex)); double dpsHPValue (target.dpf() / target.currentHP()); if (dpsHPValue > actionHighestDPS) { actionHighestDPS = dpsHPValue; actionMoveIndex = m; foundAction = true; } } else if (move.type() == MoveTypes::MOVE) { Position ourDest (ourUnit.x() + Search::Constants::Move_Dir[move._moveIndex][0], ourUnit.y() + Search::Constants::Move_Dir[move._moveIndex][1]); size_t dist (closestUnit.distSq(ourDest, state.getTime())); if (dist > furthestMoveDist) { furthestMoveDist = dist; furthestMoveIndex = m; } if (dist < closestMoveDist) { closestMoveDist = dist; closestMoveIndex = m; } } } // the move we will be returning size_t bestMoveIndex(0); // if we have an attack move we will use that one if (foundAction) { bestMoveIndex = actionMoveIndex; } // otherwise use the closest move to the opponent else { // if we are in attack range of the unit, back up if (ourUnit.canAttackTarget(closestUnit, state.getTime())) { bestMoveIndex = furthestMoveIndex; } // otherwise get back into the fight else { bestMoveIndex = closestMoveIndex; } } moveVec.push_back(moves.getMove(u, bestMoveIndex)); } }
// TODO: UNTESTED const MoveTuple Player_Kiter::getMoveTuple(GameState & state, const MoveArray & moves) { // the tuple, we will generate this on the fly MoveTuple tuple(0); for (IDType u(0); u<moves.numUnits(); ++u) { bool foundAction (false); IDType actionMoveIndex (0); IDType furthestMoveIndex (0); size_t furthestMoveDist (0); IDType closestMoveIndex (0); int actionDistance (std::numeric_limits<int>::max()); unsigned long long closestMoveDist (std::numeric_limits<unsigned long long>::max()); const Unit & ourUnit (state.getUnit(_playerID, u)); const Unit & closestUnit (ourUnit.canHeal() ? state.getClosestOurUnit(_playerID, u) : state.getClosestEnemyUnit(_playerID, u)); for (IDType m(0); m<moves.numMoves(u); ++m) { const Move move (moves.getMove(u, m)); if (move.type() == MoveTypes::ATTACK) { const Unit & target (state.getUnit(state.getEnemy(move.player()), move._moveIndex)); PositionType dist (ourUnit.distSq(target, state.getTime())); if (dist < actionDistance) { actionDistance = dist; actionMoveIndex = m; foundAction = true; } } else if (move.type() == MoveTypes::HEAL) { const Unit & target (state.getUnit(move.player(), move._moveIndex)); PositionType dist (ourUnit.distSq(target, state.getTime())); if (dist < actionDistance) { actionDistance = dist; actionMoveIndex = m; foundAction = true; } } else if (move.type() == MoveTypes::MOVE) { Position ourDest (ourUnit.x() + Search::Constants::Move_Dir[move._moveIndex][0], ourUnit.y() + Search::Constants::Move_Dir[move._moveIndex][1]); size_t dist (closestUnit.distSq(ourDest, state.getTime())); if (dist > furthestMoveDist) { furthestMoveDist = dist; furthestMoveIndex = m; } if (dist < closestMoveDist) { closestMoveDist = dist; closestMoveIndex = m; } } } // the move we will be returning size_t bestMoveIndex(0); // if we have an attack move we will use that one if (foundAction) { bestMoveIndex = actionMoveIndex; } // otherwise use the closest move to the opponent else { // if we are in attack range of the unit, back up if (ourUnit.canAttackTarget(closestUnit, state.getTime())) { bestMoveIndex = furthestMoveIndex; } // otherwise get back into the fight else { bestMoveIndex = closestMoveIndex; } } // update the tuple calculation tuple += bestMoveIndex * moves.getProduct(u); } return tuple; }
const MoveTuple Player_NOK_AttackDPS::getMoveTuple(GameState & state, const MoveArray & moves) { MoveTuple tuple(0); IDType player(moves.getMove(0,0).player()); IDType enemy(state.getEnemy(player)); Array<int, Search::Constants::Max_Units> hpRemaining; if (state.numUnits(enemy) > Search::Constants::Max_Units) { hpRemaining.resize(state.numUnits(enemy)); } for (IDType u(0); u<state.numUnits(enemy); ++u) { hpRemaining[u] = state.getUnit(enemy,u).currentHP(); } for (IDType u(0); u<moves.numUnits(); ++u) { bool foundAction (false); size_t actionMoveIndex (0); double actionHighestDPS (0); size_t closestMoveIndex (0); unsigned long long closestMoveDist (std::numeric_limits<unsigned long long>::max()); const Unit & ourUnit (state.getUnit(_playerID, u)); const Unit & closestUnit (ourUnit.canHeal() ? state.getClosestOurUnit(_playerID, u) : state.getClosestEnemyUnit(_playerID, u)); for (size_t m(0); m<moves.numMoves(u); ++m) { const Move move (moves.getMove(u, m)); if ((move.type() == MoveTypes::ATTACK) && (hpRemaining[move._moveIndex] > 0)) { const Unit & target (state.getUnit(state.getEnemy(move.player()), move._moveIndex)); double dpsHPValue = (target.dpf() / hpRemaining[move._moveIndex]); if (dpsHPValue > actionHighestDPS) { actionHighestDPS = dpsHPValue; actionMoveIndex = m; foundAction = true; } } else if (move.type() == MoveTypes::HEAL) { const Unit & target (state.getUnit(move.player(), move._moveIndex)); double dpsHPValue = (target.dpf() / hpRemaining[move._moveIndex]); if (dpsHPValue > actionHighestDPS) { actionHighestDPS = dpsHPValue; actionMoveIndex = m; foundAction = true; } } else if (move.type() == MoveTypes::RELOAD) { if (ourUnit.canAttackTarget(closestUnit, state.getTime())) { closestMoveIndex = m; break; } } else if (move.type() == MoveTypes::MOVE) { Position ourDest (ourUnit.x() + Search::Constants::Move_Dir[move._moveIndex][0], ourUnit.y() + Search::Constants::Move_Dir[move._moveIndex][1]); size_t dist (closestUnit.distSq(ourDest, state.getTime())); if (dist < closestMoveDist) { closestMoveDist = dist; closestMoveIndex = m; } } } size_t bestMoveIndex(foundAction ? actionMoveIndex : closestMoveIndex); Move theMove(moves.getMove(u, actionMoveIndex)); if (theMove.type() == MoveTypes::ATTACK) { hpRemaining[theMove.index()] -= state.getUnit(player, theMove.unit()).damage(); } tuple += bestMoveIndex * moves.getProduct(u); } return tuple; }
void Player_AttackDPS::getMoves(GameState & state, const MoveArray & moves, std::vector<Move> & moveVec) { for (IDType u(0); u<moves.numUnits(); ++u) { bool foundAction (false); size_t actionMoveIndex (0); size_t closestMoveIndex (0); double actionHighestDPS (0); unsigned long long closestMoveDist (std::numeric_limits<unsigned long long>::max()); const Unit & ourUnit (state.getUnit(_playerID, u)); const Unit & closestUnit (ourUnit.canHeal() ? state.getClosestOurUnit(_playerID, u) : state.getClosestEnemyUnit(_playerID, u)); for (size_t m(0); m<moves.numMoves(u); ++m) { const Move move (moves.getMove(u, m)); if (move.type() == MoveTypes::ATTACK) { const Unit & target (state.getUnit(state.getEnemy(move.player()), move._moveIndex)); double dpsHPValue = (target.dpf() / target.currentHP()); if (dpsHPValue > actionHighestDPS) { actionHighestDPS = dpsHPValue; actionMoveIndex = m; foundAction = true; } } if (move.type() == MoveTypes::HEAL) { const Unit & target (state.getUnit(move.player(), move._moveIndex)); double dpsHPValue = (target.dpf() / target.currentHP()); if (dpsHPValue > actionHighestDPS) { actionHighestDPS = dpsHPValue; actionMoveIndex = m; foundAction = true; } } else if (move.type() == MoveTypes::RELOAD) { if (ourUnit.canAttackTarget(closestUnit, state.getTime())) { closestMoveIndex = m; break; } } else if (move.type() == MoveTypes::MOVE) { Position ourDest (ourUnit.x() + Search::Constants::Move_Dir[move._moveIndex][0], ourUnit.y() + Search::Constants::Move_Dir[move._moveIndex][1]); size_t dist (closestUnit.distSq(ourDest, state.getTime())); if (dist < closestMoveDist) { closestMoveDist = dist; closestMoveIndex = m; } } } size_t bestMoveIndex(foundAction ? actionMoveIndex : closestMoveIndex); moveVec.push_back(moves.getMove(u, bestMoveIndex)); } }
void Player_AttackClosest::getMoves(const GameState & state, const MoveArray & moves, std::vector<UnitAction> & moveVec) { moveVec.clear(); for (IDType u(0); u<moves.numUnits(); ++u) { bool foundUnitAction (false); size_t actionMoveIndex (0); size_t closestMoveIndex (0); unsigned long long actionDistance (std::numeric_limits<unsigned long long>::max()); unsigned long long closestMoveDist (std::numeric_limits<unsigned long long>::max()); const Unit & ourUnit (state.getUnit(_playerID, u)); const Unit & closestUnit (ourUnit.canHeal() ? state.getClosestOurUnit(_playerID, u) : state.getClosestEnemyUnit(_playerID, u)); for (size_t m(0); m<moves.numMoves(u); ++m) { const UnitAction move (moves.getMove(u, m)); if (move.type() == UnitActionTypes::ATTACK) { const Unit & target (state.getUnit(state.getEnemy(move.player()), move._moveIndex)); size_t dist (ourUnit.getDistanceSqToUnit(target, state.getTime())); if (dist < actionDistance) { actionDistance = dist; actionMoveIndex = m; foundUnitAction = true; } } if (move.type() == UnitActionTypes::HEAL) { const Unit & target (state.getUnit(move.player(), move._moveIndex)); size_t dist (ourUnit.getDistanceSqToUnit(target, state.getTime())); if (dist < actionDistance) { actionDistance = dist; actionMoveIndex = m; foundUnitAction = true; } } else if (move.type() == UnitActionTypes::RELOAD) { if (ourUnit.canAttackTarget(closestUnit, state.getTime())) { closestMoveIndex = m; break; } } else if (move.type() == UnitActionTypes::MOVE) { Position ourDest (ourUnit.x() + Constants::Move_Dir[move._moveIndex][0], ourUnit.y() + Constants::Move_Dir[move._moveIndex][1]); size_t dist (closestUnit.getDistanceSqToPosition(ourDest, state.getTime())); if (dist < closestMoveDist) { closestMoveDist = dist; closestMoveIndex = m; } } } size_t bestMoveIndex(foundUnitAction ? actionMoveIndex : closestMoveIndex); moveVec.push_back(moves.getMove(u, bestMoveIndex)); } }
void Player_Kiter_NOKDPS::getMoves(GameState & state, const MoveArray & moves, std::vector<Action> & moveVec) { moveVec.clear(); IDType enemy(state.getEnemy(_playerID)); Array<int, Constants::Max_Units> hpRemaining; for (IDType u(0); u<state.numUnits(enemy); ++u) { hpRemaining[u] = state.getUnit(enemy,u).currentHP(); } for (IDType u(0); u<moves.numUnits(); ++u) { bool foundAction (false); size_t actionMoveIndex (0); IDType furthestMoveIndex (0); size_t furthestMoveDist (0); double actionHighestDPS (0); size_t closestMoveIndex (0); unsigned long long closestMoveDist (std::numeric_limits<unsigned long long>::max()); const Unit & ourUnit (state.getUnit(_playerID, u)); const Unit & closestUnit (ourUnit.canHeal() ? state.getClosestOurUnit(_playerID, u) : state.getClosestEnemyUnit(_playerID, u)); for (size_t m(0); m<moves.numMoves(u); ++m) { const Action move (moves.getMove(u, m)); if ((move.type() == ActionTypes::ATTACK) && (hpRemaining[move.index()] > 0)) { const Unit & target (state.getUnit(state.getEnemy(move.player()), move.index())); double dpsHPValue = (target.dpf() / hpRemaining[move.index()]); if (dpsHPValue > actionHighestDPS) { actionHighestDPS = dpsHPValue; actionMoveIndex = m; foundAction = true; } if (move.index() >= state.numUnits(enemy)) { int e = enemy; int pl = _playerID; printf("wtf\n"); } } else if (move.type() == ActionTypes::HEAL) { const Unit & target (state.getUnit(move.player(), move.index())); double dpsHPValue = (target.dpf() / hpRemaining[move.index()]); if (dpsHPValue > actionHighestDPS) { actionHighestDPS = dpsHPValue; actionMoveIndex = m; foundAction = true; } } else if (move.type() == ActionTypes::RELOAD) { if (ourUnit.canAttackTarget(closestUnit, state.getTime())) { closestMoveIndex = m; break; } } else if (move.type() == ActionTypes::MOVE) { Position ourDest (ourUnit.x() + Constants::Move_Dir[move.index()][0], ourUnit.y() + Constants::Move_Dir[move.index()][1]); size_t dist (closestUnit.getDistanceSqToPosition(ourDest, state.getTime())); if (dist > furthestMoveDist) { furthestMoveDist = dist; furthestMoveIndex = m; } if (dist < closestMoveDist) { closestMoveDist = dist; closestMoveIndex = m; } } } size_t bestMoveIndex(0); // if we have an attack move we will use that one if (foundAction) { bestMoveIndex = actionMoveIndex; } // otherwise use the closest move to the opponent else { // if we are in attack range of the unit, back up if (ourUnit.canAttackTarget(closestUnit, state.getTime())) { bestMoveIndex = furthestMoveIndex; } // otherwise get back into the fight else { bestMoveIndex = closestMoveIndex; } } Action theMove(moves.getMove(u, actionMoveIndex)); if (theMove.type() == ActionTypes::ATTACK) { hpRemaining[theMove.index()] -= state.getUnit(_playerID, theMove.unit()).damage(); } moveVec.push_back(moves.getMove(u, bestMoveIndex)); } }