std::vector<std::tuple<int, int, int>> ImmediateBestValueStrategy1::fortify(GameState state) { if (beVerbose) std::cout << "________________________________" << std::endl; if (beVerbose) std::cout << "ImmediateBestValueStrategy1 "<<myPlayerNumber<<" is fortifying" << std::endl; if (beVerbose) state.display(); std::vector<std::tuple<int, int, int>> actions; std::vector<int> myRegions = state.getRegionsOwnedByPlayer(myPlayerNumber); for (int i=0; i<myRegions.size(); i++) { std::vector<int> neighbors = map->getNeighborsOfRegion(myRegions[i]); bool isOnBattleFront = false; for (int j=0; j<neighbors.size(); j++) { if (state.getRegionInfo(neighbors[j]).first != myPlayerNumber) { isOnBattleFront = true; break; } } if (!isOnBattleFront) { //move it, randomly, hoping to find the battlefront int whereFrom = myRegions[i]; int whereTo = neighbors[rand() % neighbors.size()]; int howManyToMove = state.getRegionInfo(whereFrom).second - 2; if (howManyToMove > 0) { if (beVerbose) std::cout<<"Moving "<<howManyToMove<<" from "<<whereFrom<<" to "<<whereTo<<std::endl; actions.push_back(std::tuple<int,int,int>(whereFrom,whereTo,howManyToMove)); } } } if (beVerbose) { if (actions.size()==0) std::cout<<"Not moving anyone"<<std::endl; } if (beVerbose) std::cout << "________________________________" << std::endl; return actions; }
int ImmediateBestValueStrategy1::claim(GameState state) { if (beVerbose) std::cout << "________________________________" << std::endl; if (beVerbose) std::cout << "ImmediateBestValueStrategy1 "<<myPlayerNumber<<" is claiming his land" << std::endl; if (beVerbose) state.display(); std::vector<std::pair<int,double>> choices; for (int i=0; i<state.getNumRegions(); i++) { if (state.getRegionInfo(i).first < 0) choices.push_back(std::pair<int,double>(i,testValue(state, i))); } std::sort(choices.begin(), choices.end(), [](const std::pair<int, double> &lhs, const std::pair<int, double> &rhs) { return lhs.second < rhs.second; }); int pickedRegion = choices[choices.size()-1].first; if (beVerbose) std::cout << "Chose: " << pickedRegion << std::endl; if (beVerbose) std::cout << "________________________________" << std::endl; // return the available country with the lowest region count return pickedRegion; }
int ObtainSmallestContinentsFirstStrategy::claim(GameState state) { if (beVerbose) std::cout << "________________________________" << std::endl; if (beVerbose) std::cout << "ObtainSmallestContinentsFirstStrategy "<<myPlayerNumber<<" is claiming his land" << std::endl; if (beVerbose) state.display(); // get list of continents std::vector<Continent> continentList = this->map->getContinentList(); // sort the list from the lowest region count to the largest region count // std::vector<index> == index from lowest region count to largest region count // (1) Continent index // (2) region count std::vector<std::pair<int, int> > lowRegioncountList; if (beVerbose) std::cout << "continentList.size(): " << continentList.size() << std::endl; for (int i = 0; i < continentList.size(); i++) { lowRegioncountList.push_back(std::make_pair(i, continentList[i].getRegionList().size())); } // sort lowRegioncountList by the second element in the pair: region count. End result is a sorted list of the smallest number of regions // to the largest number of regions. its original index is preserved as established in the map->continentList std::sort(lowRegioncountList.begin(), lowRegioncountList.end(), [](const std::pair<int, int> &lhs, const std::pair<int, int> &rhs) { return lhs.second < rhs.second; }); // select the first continent unless it is already taken. // If the continent has been taken, grab the continent with the next smallest region count int index = 0; std::vector<std::pair<int, std::string>> regionList; int pickedContinent = -1; int pickedRegion = -1; bool placeSelected = false; while (!placeSelected && index < lowRegioncountList.size()) { // grab the index of the continent with the lowest region count // countries with the lowest region count have been sorted from lowest to highest pickedContinent = lowRegioncountList[index].first; regionList = continentList[pickedContinent].getRegionList(); int regionIndex = 0; // loop through each region within the continent for availability while (regionIndex < regionList.size()) { pickedRegion = regionList[regionIndex].first; // the region is already claimed if (state.getRegionInfo(pickedRegion).first == -1) { // select this continent (Found a winner) placeSelected = true; break; } regionIndex++; } if (placeSelected) break; index++; } if (beVerbose) std::cout << "Chose: " << pickedRegion << std::endl; if (beVerbose) std::cout << "________________________________" << std::endl; // return the available country with the lowest region count return pickedRegion; }
std::pair<int, int> ObtainSmallestContinentsFirstStrategy::attack(GameState state) { if (beVerbose) std::cout << "________________________________" << std::endl; if (beVerbose) std::cout << "ObtainSmallestContinentsFirstStrategy "<<myPlayerNumber<<" is attacking" << std::endl; if (beVerbose) state.display(); // get a list of continents to conquer, and of continents I own std::vector<std::pair<int, int>> continentsToConquer; //first int is the continent's index; the second is its region count std::vector<int> continentsIOwn; std::vector<Continent> continentList = this->map->getContinentList(); for (int i = 0; i < continentList.size(); i++) { bool iOwnThisContinent = true; std::vector<std::pair<int, std::string>> regionList = continentList[i].getRegionList(); for (int j=0; j<regionList.size(); j++) { if (regionList[j].first != myPlayerNumber) { iOwnThisContinent = false; break; } } if (iOwnThisContinent) continentsIOwn.push_back(i); else continentsToConquer.push_back(std::make_pair(i, continentList[i].getRegionList().size())); } std::sort(continentsToConquer.begin(), continentsToConquer.end(), [](const std::pair<int, int> &lhs, const std::pair<int, int> &rhs) { return lhs.second < rhs.second; }); //determine which regions are important to me std::vector<int> myImportantRegions; for (int i=0; i<continentsIOwn.size(); i++) { std::vector<std::pair<int,std::string>> tempRegions = continentList[continentsIOwn[i]].getRegionList(); for (int j=0; j<tempRegions.size(); j++) myImportantRegions.push_back(tempRegions[j].first); } // Get a list of regions where to send attackers, and get the number of hostile regions std::vector<std::pair<int,int>> attackWorthyLocations; //the first int is the region#, and the second is the score for (int h=0; h<continentsToConquer.size(); h++) { Continent targetContinent = continentList[continentsToConquer[h].first]; if (beVerbose) std::cout<<"Target Continent: " << continentsToConquer[h].first << std::endl; std::vector<std::pair<int, std::string>> tempRegionList = targetContinent.getRegionList(); for (int i=0; i<tempRegionList.size(); i++) { if (state.getRegionInfo(tempRegionList[i].first).first != myPlayerNumber) { int regionTheirs = tempRegionList[i].first; if (beVerbose) std::cout<<"Considering hostile: " << regionTheirs << std::endl; std::vector<int> neighborsTheirs = map->getNeighborsOfRegion(regionTheirs); for (int j=0; j<neighborsTheirs.size(); j++) { if (state.getRegionInfo(neighborsTheirs[j]).first==myPlayerNumber) { int regionMine = neighborsTheirs[j]; if (beVerbose) std::cout<<"Considering attack-from region: " << regionMine << std::endl; int surroundingEnemies = 0; std::vector<int> neighborsMine = map->getNeighborsOfRegion(regionMine); for (int k=0; k<neighborsMine.size(); k++) surroundingEnemies += state.getRegionInfo(neighborsMine[k]).second; int diffrence = state.getRegionInfo(regionMine).second - surroundingEnemies; for (int k=0; k<myImportantRegions.size(); k++) { if (myImportantRegions[i]==regionMine) { diffrence -= 4; break; } } attackWorthyLocations.push_back(std::pair<int,int>(regionMine, diffrence)); } } } } std::sort(attackWorthyLocations.begin(), attackWorthyLocations.end(), [](const std::pair<int, int> &lhs, const std::pair<int, int> &rhs) { return lhs.second < rhs.second; }); //Now attack from the best region that we can for (int i=0; i<attackWorthyLocations.size(); i++) { int troopsAvailiable = state.getRegionInfo(attackWorthyLocations[i].first).second; for (int k=0; k<myImportantRegions.size(); k++) { if (myImportantRegions[k]==attackWorthyLocations[i].first) { troopsAvailiable -= 4; break; } } if (troopsAvailiable>2) { int attackFrom = attackWorthyLocations[i].first; std::vector<int> neighborsMine = map->getNeighborsOfRegion(attackFrom); for (int k=0; k<neighborsMine.size(); k++) { int whereIsMyNeighbor = map->whereIs(neighborsMine[k]); if (beVerbose) std::cout<< "Where is my neighbor: "<<whereIsMyNeighbor<<"; Neighbor Allegance: "<<state.getRegionInfo(neighborsMine[k]).first << std::endl; if (state.getRegionInfo(neighborsMine[k]).first != myPlayerNumber && whereIsMyNeighbor==continentsToConquer[h].first) { int attackTo = neighborsMine[k]; if (beVerbose) std::cout << "Attacking " << attackTo << " with " << attackFrom << std::endl; if (beVerbose) std::cout << "________________________________" << std::endl; return std::pair<int,int>(attackFrom,attackTo); } } } } } //if we made it this far, there's nowhere good to attack from if (beVerbose) std::cout<<"Not attacking."<<std::endl; if (beVerbose) std::cout << "________________________________" << std::endl; return std::pair<int,int>(-1,-1); }
std::vector<std::pair<int, int>> ObtainSmallestContinentsFirstStrategy::place(GameState state, int numTroops) { if (beVerbose) std::cout << "________________________________" << std::endl; if (beVerbose) std::cout << "ObtainSmallestContinentsFirstStrategy " << myPlayerNumber << " is placing " << numTroops << " troops." << std::endl; if (beVerbose) state.display(); std::vector<std::pair<int, int>> actions; // get lists for the two types of continents we care about std::vector<std::pair<int, int>> continentsToConquer; //first int is the continent's index; the second is its region count std::vector<int> continentsIOwn; std::vector<Continent> continentList = this->map->getContinentList(); for (int i = 0; i < continentList.size(); i++) { bool iOwnThisContinent = true; std::vector<std::pair<int, std::string>> regionList = continentList[i].getRegionList(); for (int j=0; j<regionList.size(); j++) { if (regionList[j].first != myPlayerNumber) { iOwnThisContinent = false; break; } } if (iOwnThisContinent) continentsIOwn.push_back(i); else continentsToConquer.push_back(std::make_pair(i, continentList[i].getRegionList().size())); } std::sort(continentsToConquer.begin(), continentsToConquer.end(), [](const std::pair<int, int> &lhs, const std::pair<int, int> &rhs) { return lhs.second < rhs.second; }); if (beVerbose) std::cout<<"Continents I own: "<<continentsIOwn.size() << std::endl; //get all friendly regions on the battlefront int regionCountInOwnedContinents = 0; std::vector<std::pair<int, int>> frontlineRegions; //first int is the region's index, the second is its "score" for (int i = 0; i < continentsIOwn.size(); i++) { std::vector<std::pair<int, std::string>> tempRegionList = continentList[i].getRegionList(); regionCountInOwnedContinents += tempRegionList.size(); bool iOwnThisContinent = true; for (int j=0; j<tempRegionList.size(); j++) { int regionBeingConsidered = tempRegionList[j].first; std::vector<int> neighbors = map->getNeighborsOfRegion(regionBeingConsidered); int enemyCount = 0; for (int k=0; k<neighbors.size(); k++) { if (state.getRegionInfo(neighbors[k]).first != myPlayerNumber) enemyCount += state.getRegionInfo(neighbors[k]).second; } if (enemyCount>0) { int score = state.getRegionInfo(regionBeingConsidered).second - enemyCount; frontlineRegions.push_back(std::pair<int,int>(regionBeingConsidered, score)); } } } std::sort(frontlineRegions.begin(), frontlineRegions.end(), [](const std::pair<int, int> &lhs, const std::pair<int, int> &rhs) { return lhs.second < rhs.second; }); if (beVerbose) std::cout<<"Regions in my continents: "<<regionCountInOwnedContinents<<"; Regions on my frontline: "<<frontlineRegions.size()<<std::endl; // Get a list of regions where to send attackers, and get the number of hostile regions there Continent targetContinent = continentList[continentsToConquer[0].first]; std::vector<int> attackWorthyLocations; int hostileRegions; for (int h=0; h<continentsToConquer.size()&&attackWorthyLocations.size()==0; h++) { targetContinent = continentList[continentsToConquer[h].first]; if (beVerbose) std::cout<<"Considering target continent: " << continentsToConquer[h].first << std::endl; hostileRegions = 0; std::vector<std::pair<int, std::string>> tempRegionList = targetContinent.getRegionList(); for (int i=0; i<tempRegionList.size(); i++) { int regionBeingConsidered = tempRegionList[i].first; if (state.getRegionInfo(regionBeingConsidered).first != myPlayerNumber) { if (beVerbose) std::cout << "Hostile: " << regionBeingConsidered << std::endl; hostileRegions++; std::vector<int> neighbors = map->getNeighborsOfRegion(regionBeingConsidered); for (int j=0; j<neighbors.size(); j++) { if (state.getRegionInfo(neighbors[j]).first==myPlayerNumber) { attackWorthyLocations.push_back(neighbors[j]); if (beVerbose) std::cout << "Attack worthy: " << neighbors[j] << std::endl; } } } } } if (beVerbose) std::cout<<"In my target continenet: Hostile regions: "<<hostileRegions<<"; Attack worthy locations: "<<attackWorthyLocations.size()<<std::endl; // Decide an appropriate number of troops to each type of location int numberOfTroopsToSendToAttack = (int)(numTroops*attackPlacementPreferenceFactor*hostileRegions/(hostileRegions+regionCountInOwnedContinents)); if (numberOfTroopsToSendToAttack > numTroops || regionCountInOwnedContinents==0) numberOfTroopsToSendToAttack = numTroops; int numberOfTroopsToSendToDefend = numTroops - numberOfTroopsToSendToAttack; if (beVerbose) std::cout<<"Attacking troops: "<<numberOfTroopsToSendToAttack<<"; Defending troops: "<<numberOfTroopsToSendToDefend<<std::endl; // Send troops to target continent if (numberOfTroopsToSendToAttack > 0) { int numToSendPerRegion = numberOfTroopsToSendToAttack / attackWorthyLocations.size(); int remainder = numberOfTroopsToSendToAttack - numToSendPerRegion; for (int i=0; i<attackWorthyLocations.size(); i++) { int howMany = numToSendPerRegion + ((i<remainder)?1:0); actions.push_back(std::pair<int,int>(attackWorthyLocations[i], howMany)); if (beVerbose) std::cout << "Placing "<<howMany<<" troops at "<<attackWorthyLocations[i] << std::endl; } } // Send troops to frontline defenses if (numberOfTroopsToSendToDefend > 0) { int numToSendPerRegion = numberOfTroopsToSendToDefend / frontlineRegions.size(); int remainder = numberOfTroopsToSendToDefend - numToSendPerRegion; for (int i=0; i<frontlineRegions.size(); i++) { int howMany = numToSendPerRegion + ((i<remainder)?1:0); actions.push_back(std::pair<int,int>(frontlineRegions[i].first, howMany)); if (beVerbose) std::cout << "Placing "<<howMany<<" troops at "<<attackWorthyLocations[i] << std::endl; } } if (beVerbose) std::cout << "________________________________" << std::endl; return actions; }
std::vector<std::pair<int, int>> ImmediateBestValueStrategy1::place(GameState state, int numTroops) { if (beVerbose) std::cout << "________________________________" << std::endl; if (beVerbose) std::cout << "ImmediateBestValueStrategy1 " << myPlayerNumber << " is placing " << numTroops << " troops." << std::endl; if (beVerbose) state.display(); std::vector<std::pair<int, int>> actions; //First, make sure there are no regions with only one troop std::vector<int> myRegions = state.getRegionsOwnedByPlayer(myPlayerNumber); for (int i=0; i<myRegions.size() && numTroops>0; i++) { if (state.getRegionInfo(myRegions[i]).second == 1) { if (beVerbose) std::cout<<"Placing a troop at "<<myRegions[i]<<" to meet the minimum."<<std::endl; actions.push_back(std::pair<int,int>(myRegions[i],1)); numTroops--; } } //Now, get a list of all exposed borders, sorted by danger, and give them troops, if needed if (numTroops>0) { std::vector<std::pair<int,int>> borders = state.getAllExposedBorders(myPlayerNumber, map); //border's second index is the number of enemy troops; change it to the amount of danger for (int i=0; i<borders.size(); i++) { int danger = borders[i].second - state.getRegionInfo(borders[i].first).second; borders[i].second = danger; } std::sort(borders.begin(), borders.end(), [](const std::pair<int, int> &lhs, const std::pair<int, int> &rhs) { return lhs.second < rhs.second; }); for (int i=borders.size()-1; i>=0 && numTroops>0; i--) { if (borders[i].second > dangerThreshold) { int troopsToSend = borders[i].second - dangerThreshold; if (troopsToSend > numTroops) troopsToSend = numTroops; if (beVerbose) std::cout<<"Placing "<<troopsToSend<<" troops at "<<borders[i].first<<" to get down to the danger threshold."<<std::endl; actions.push_back(std::pair<int,int>(borders[i].first,troopsToSend)); numTroops -= troopsToSend; } } } //if we still have troops, put them all in the border region that would score the highest points if (numTroops > 0) { //get a list of ideal targets std::vector<std::pair<int,double>> targets; std::vector<int> options = state.getAllNeighborsOfPlayer(myPlayerNumber, map); for (int i=0; i<options.size(); i++) targets.push_back(std::pair<int,double>(options[i], testValue(state, options[i]))); std::sort(targets.begin(), targets.end(), [](const std::pair<int, double> &lhs, const std::pair<int, double> &rhs) { return lhs.second < rhs.second; }); //and pick a neighboring spot to strengthen std::vector<int> theirNeighbors = map->getNeighborsOfRegion(targets[targets.size()-1].first); for (int i=0; i<theirNeighbors.size(); i++) { if (state.getRegionInfo(theirNeighbors[i]).first == myPlayerNumber) { if (beVerbose) std::cout<<"Placing "<<numTroops<<" troop at "<<theirNeighbors[i]<<" to prepare to attack "<<targets[targets.size()-1].first<<std::endl; actions.push_back(std::pair<int,int>(theirNeighbors[i],numTroops)); break; } } } if (beVerbose) std::cout << "________________________________" << std::endl; return actions; }
std::pair<int, int> ImmediateBestValueStrategy1::attack(GameState state) { if (beVerbose) std::cout << "________________________________" << std::endl; if (beVerbose) std::cout << "ImmediateBestValueStrategy1 "<<myPlayerNumber<<" is attacking" << std::endl; if (beVerbose) state.display(); //sort neighbors by weight=valueOfVictory*probabilyOfVictory std::vector<std::tuple<int,int,double>> weightedNeighborList; //first int is whereTo, second is whereFrom; double is the weight std::vector<int> myNeighbors = state.getAllNeighborsOfPlayer(myPlayerNumber, map); for (int i=0; i<myNeighbors.size(); i++) { double value = testValue(state,myNeighbors[i]); //we have the value, now we need the probability at the best attack-from location double probability = 0; int bestAttackFromSpot = -1; std::vector<int> theirNeighbors = map->getNeighborsOfRegion(myNeighbors[i]); for (int j=0; j<theirNeighbors.size(); j++) { if (state.getRegionInfo(theirNeighbors[j]).first == myPlayerNumber) { double currentProbability = Game::getProbabilityOfVictory(state.getRegionInfo(theirNeighbors[j]).second - 1, state.getRegionInfo(myNeighbors[i]).second); if (currentProbability>probability) { probability = currentProbability; bestAttackFromSpot = theirNeighbors[j]; } } } if (bestAttackFromSpot >= 0) { if (beVerbose) std::cout<<"Region "<<myNeighbors[i]<<" has weight "<<probability*value<<" when attacked from "<<bestAttackFromSpot<<std::endl; weightedNeighborList.push_back(std::tuple<int,int,double>(myNeighbors[i],bestAttackFromSpot,probability*value)); } } std::sort(weightedNeighborList.begin(), weightedNeighborList.end(), [](const std::tuple<int,int,double> &lhs, const std::tuple<int,int,double> &rhs) { return std::get<2>(lhs) < std::get<2>(rhs); }); //Now, we pick one to attack int chosen = weightedNeighborList.size() - 1; while (chosen >= 0) { if (beVerbose) std::cout<<"Considering attacking "<<std::get<0>(weightedNeighborList[chosen])<<std::endl; int attackFrom = std::get<1>(weightedNeighborList[chosen]); int armiesAtAttackFrom = state.getRegionInfo(attackFrom).second; if (armiesAtAttackFrom>10) //if we have at least 10 and are still in danger, the game is stagnating. Just let it happen, danger or no break; if (armiesAtAttackFrom>2) { int danger = 0 - armiesAtAttackFrom; std::vector<int> localNeighbors = map->getNeighborsOfRegion(attackFrom); for (int k=0; k<localNeighbors.size(); k++) { if (state.getRegionInfo(localNeighbors[k]).first != myPlayerNumber) danger += state.getRegionInfo(localNeighbors[k]).second; } if (danger < dangerThreshold) break; } chosen--; } //And attack it if (chosen >= 0) { int attackTo = std::get<0>(weightedNeighborList[chosen]); int attackFrom = std::get<1>(weightedNeighborList[chosen]); if (beVerbose) std::cout << "Attacking " << attackTo << " with " << attackFrom << std::endl; if (beVerbose) std::cout << "________________________________" << std::endl; return std::pair<int,int>(attackFrom,attackTo); } else { if (beVerbose) std::cout<<"Not attacking."<<std::endl; if (beVerbose) std::cout << "________________________________" << std::endl; return std::pair<int,int>(-1,-1); } }