const bool AlphaBeta::pruneMove(GameState & state, const IDType & playerToMove, const MoveArray & moves, const MoveTuple & tuple) const { IDType enemy(getEnemy(playerToMove)); // damage assigned to each enemy unit so far int hpRemaining[Search::Constants::Max_Units]; for (IDType u(0); u<state.numUnits(enemy); ++u) { hpRemaining[u] = state.getUnit(enemy,u).currentHP(); } // for each unit in the tuple for (size_t u(0); u<moves.numUnits(); u++) { // get its move const Move & m(moves.getTupleMove(tuple, u)); if (m.type() == MoveTypes::ATTACK) { // if the target unit has already been killed then return prune if (hpRemaining[m.index()] <= 0) { return true; } hpRemaining[m.index()] -= state.getUnit(playerToMove, u).damage(); } } return false; }
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 AlphaBeta::doTupleMoves(GameState & state, MoveArray & moves, const MoveTuple & tuple) { // for each simultaneous move in this tuple for (size_t u(0); u<moves.numUnitsInTuple(); ++u) { Move m = moves.getTupleMove(tuple, u); state.makeMove(m, state); } }
// causes playerToMove() to make the moves in the tuple void LargeGame::makeMoves(const MoveTuple & tuple, MoveArray & arr) { // for each simultaneous move in this tuple for (size_t u(0); u<arr.numUnitsInTuple(); ++u) { Move m = arr.getTupleMove(tuple, u); //printf(" Move (%d, %d) (%s, %s)\n", (int)tuple, (int)u, state.getUnit(m.player(), m.unit()).name().c_str(), m.moveString().c_str()); state.makeMove(m, state); } }
bool AlphaBetaSearch::getNextMoveVec(IDType playerToMove, MoveArray & moves, const size_t & moveNumber, const TTLookupValue & TTval, const size_t & depth, std::vector<Action> & moveVec) const { if (_params.maxChildren() && (moveNumber >= _params.maxChildren())) { return false; } // if this move is beyond the first, check to see if we are only using a single move if (moveNumber == 1) { // if we are player modeling, we should have only generated the first move if (_params.playerModel(playerToMove) != PlayerModels::None) { // so return false return false; } // if there is a transposition table entry for this state if (TTval.found()) { // if there was a valid move found with higher depth, just do that one const AlphaBetaMove & abMove = getAlphaBetaMove(TTval, playerToMove); if ((TTval.entry()->getDepth() >= depth) && abMove.isValid()) { // so return false return false; } } } const Array<std::vector<Action>, Constants::Max_Ordered_Moves> & orderedMoves(_orderedMoves[depth]); moveVec.clear(); // if this move should be from the ordered list, return it from the list if (moveNumber < orderedMoves.size()) { moveVec.assign(orderedMoves[moveNumber].begin(), orderedMoves[moveNumber].end()); return true; } // otherwise return the next move vector starting from the beginning else { if (moves.hasMoreMoves()) { moves.getNextMoveVec(moveVec); return true; } else { return false; } } }
void UnitScriptData::calculateMoves(const IDType & player, MoveArray & moves, GameState & state, std::vector<Action> & moveVec) { // generate all script moves for this player at this state and store them in allScriptMoves for (size_t scriptIndex(0); scriptIndex<_scriptVec[player].size(); ++scriptIndex) { // get the associated player pointer const PlayerPtr & pp = getPlayerPtr(player, scriptIndex); // get the actual script we are working with const IDType actualScript = getScript(player, scriptIndex); // generate the moves inside the appropriate vector getMoves(player, actualScript).clear(); pp->getMoves(state, moves, getMoves(player, actualScript)); } // for each unit the player has to move, populate the move vector with the appropriate script move for (size_t unitIndex(0); unitIndex < moves.numUnits(); ++unitIndex) { // the unit from the state const Unit & unit = state.getUnit(player, unitIndex); // the move it would choose to do based on its associated script preference Action unitMove = getMove(player, unitIndex, getUnitScript(unit)); // put the unit into the move vector moveVec.push_back(unitMove); } }
void GameState::printMoveTuple(const IDType & player, const MoveTuple & t) const { printf("\n"); MoveArray moves; generateMoves(moves, player); for (size_t u(0); u<moves.numUnitsInTuple(); ++u) { Move m = moves.getTupleMove(t, u); std::cout << "Player " << (int)m.player() << " " << getUnit(m.player(), m.unit()).name() << " (id=" << (int)m.unit() << ")" << " " << m.moveString() ; if (m.type() == MoveTypes::ATTACK) { std::cout << " target " << getUnit(getEnemy(m.player()), m.index()).name() << " (id=" << (int)m.index() << ")"; } std::cout << "\n"; } }
bool UCTSearch::getNextMove(IDType playerToMove, MoveArray & moves, const size_t & moveNumber, std::vector<UnitAction> & actionVec) { if (moveNumber > _params.maxChildren()) { return false; } // if this move is beyond the first, check to see if we are only using a single move if (moveNumber == 1) { // if we are player modeling, we should have only generated the first move if (_params.playerModel(playerToMove) != PlayerModels::None) { // so return false return false; } } actionVec.clear(); // if this move should be from the ordered list, return it from the list if (moveNumber < _orderedMoves.size()) { actionVec.assign(_orderedMoves[moveNumber].begin(), _orderedMoves[moveNumber].end()); return true; } // otherwise return the next move vector starting from the beginning else { if (moves.hasMoreMoves()) { moves.getNextMoveVec(actionVec); return true; } else { return false; } } }
const MoveTuple AlphaBeta::getNumMoveTuples(MoveArray & moves, const TTLookupValue & TTval, const IDType & playerToMove, const size_t & depth) const { // if we are doing opponent modeling, there is just one move to do if (_params.usePlayerModel(playerToMove)) { return 1; } // if there is a transposition table entry for this state if (TTval.found()) { // if there was a valid move found with higher depth, just do that one const AlphaBetaMove & abMove = getAlphaBetaMove(TTval, playerToMove); if ((TTval.entry()->getDepth() >= depth) && abMove.isValid() && (abMove.moveTuple() < moves.numMoveTuples())) { return 1; } } // otherwise, it's the number of possible moves + number of ordered moves return moves.numMoveTuples(); }
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)); } }
// get desired move tuple for this player's strategy const MoveTuple Player_Random::getMoveTuple(GameState & state, const MoveArray & moves) { //boost::random::uniform_int_distribution<> dist(0, moves.numMoveTuples() - 1); return rand() % moves.numMoveTuples(); }
void AlphaBeta::generateOrderedMoves(GameState & state, MoveArray & moves, const TTLookupValue & TTval, const IDType & playerToMove, const size_t & depth) { // get the array where we will store the moves and clear it Array<MoveTuple, Search::Constants::Max_Ordered_Moves> & orderedMoves(_orderedMoves[depth]); orderedMoves.clear(); // if we are using opponent modeling, get the move and then return, we don't want to put any more moves in if (_params.usePlayerModel(playerToMove)) { MoveTuple playerModelMove = _params.getPlayer(playerToMove)->getMoveTuple(state, moves); orderedMoves.add(playerModelMove); return; } // if there is a transposition table entry for this state if (TTval.found()) { // get the abMove we stored for this player const AlphaBetaMove & abMove = getAlphaBetaMove(TTval, playerToMove); // here we get an incorrect move from the transposition table if (abMove.moveTuple() >= moves.numMoveTuples()) { HashType h0 = state.calculateHash(0); HashType h1 = state.calculateHash(1); MoveArray moves2; state.generateMoves(moves2, playerToMove); // figure out why //fprintf(stderr, "Something very wrong, this tuple (%d) doesn't exist, only (%d) moves\n", (int)abMove.moveTuple(), (int)moves.numMoveTuples()); } _results.ttFoundCheck++; // Two checks: // 1) Is the move 'valid' ie: was it actually set inside the TT // 2) Is it a valid tuple number for this move set? This guards against double // hash collision errors. Even if it is a collision, this is just a move // ordering, so no errors should occur. if (abMove.isValid() && (abMove.moveTuple() < moves.numMoveTuples())) { orderedMoves.add(abMove.moveTuple()); _results.ttMoveOrders++; return; } else { _results.ttFoundButNoMove++; } } // if we are using script modeling, insert the script moves we want if (_params.useScriptMoveFirst()) { for (size_t s(0); s<_allScripts.size(); s++) { MoveTuple scriptMove = _allScripts[s]->getMoveTuple(state, moves); orderedMoves.addUnique(scriptMove); } } }
int CDECL main(int argc, char **argv) { Bitboard::init(); Attacks::init(); Scoring::init(); if (!initGlobals(argv[0], false)) { cleanupGlobals(); exit(-1); } atexit(cleanupGlobals); Board board; ECO eco; int arg = 1; if (argc <=1) { show_usage(); return -1; } else { ifstream pgn_file( argv[arg], ios::in | ios::binary); int c; ColorType side; string result, white, black; if (!pgn_file.good()) { cerr << "could not open file " << argv[arg] << endl; exit(-1); } else { vector<ChessIO::Header> hdrs; while (!pgn_file.eof()) { long first; MoveArray moves; board.reset(); side = White; while (pgn_file.good() && (c = pgn_file.get()) != EOF) { if (c=='[') { int c1 = pgn_file.get(); if (c1 == 'E') { int c2 = pgn_file.get(); if (c2 == 'v') { pgn_file.putback(c2); pgn_file.putback(c1); pgn_file.putback(c); break; } } } } hdrs.clear(); ChessIO::collect_headers(pgn_file,hdrs,first); if (!hdrs.size()) continue; bool ok = true; bool done = false; bool exit = false; while (ok && !exit) { ChessIO::Token tok = ChessIO::get_next_token(pgn_file); string num; switch (tok.type) { case ChessIO::Eof: { exit = true; break; } case ChessIO::Number: { num = tok.val; break; } case ChessIO::GameMove: { if (done) { // we should not have moves after the result // if it looks like a tag, push it back if (tok.val.size() && tok.val[0] == '[') { for (int i = (int)tok.val.size()-1; i >= 0; --i) pgn_file.putback(tok.val[0]); } exit = true; break; } // parse the move Move m = Notation::value(board,side,Notation::InputFormat::SAN,tok.val); if (IsNull(m) || !legalMove(board,StartSquare(m), DestSquare(m))) { // echo to both stdout and stderr cerr << "Illegal move: " << tok.val << endl; cout << "Illegal move: " << tok.val << endl; ok = false; } else { BoardState bs = board.state; string img; // convert to SAN Notation::image(board,m,Notation::OutputFormat::SAN,img); moves.add_move(board,bs,m,img,false); board.doMove(m); } side = OppositeColor(side); break; } case ChessIO::Unknown: { if (done) { // ignore unknown text after result // if it looks like a tag, push it back if (tok.val.size() && tok.val[0] == '[') { for (int i = (int)tok.val.size()-1; i >= 0; --i) pgn_file.putback(tok.val[0]); } exit = true; break; } cerr << "Unrecognized text: " << tok.val << endl; break; } case ChessIO::Comment: { // ignored for now break; } case ChessIO::Result: { result = tok.val; done = true; break; } case ChessIO::OpenVar: cerr << "Warning: variations not supported" << endl; done = true; default: break; } // end switch } // output header string ecoC = ""; int found = ChessIO::get_header(hdrs,"ECO",ecoC); if (!found) { string name; eco.classify(moves,ecoC,name); if (ecoC != "") { ChessIO::Header ecoHeader("ECO",ecoC.c_str()); hdrs.push_back(ecoHeader); } } else if (ecoC == "") { string name; eco.classify(moves,ecoC,name); if (ecoC != "") { ChessIO::Header ecoHeader("ECO",ecoC.c_str()); for (auto it = hdrs.begin(); it != hdrs.end(); it++) { const ChessIO::Header &hdr = *it; if (hdr.tag() == "ECO") { // replace old header *it = ecoHeader; break; } } } } if (moves.num_moves()>0) ChessIO::store_pgn(cout,moves,result,hdrs); } pgn_file.close(); } } return 0; }
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)); } }