C++11, CalculatedFail
after i tried a few things in with the little Java i know and was not quite able to achieve what i wanted, i choose to re-write it in C++ and add file handling. problem was, my C++ is quite rusty and not much better, so some parts are whacked together and just the first solution in google, so not really quality code...
still, i was able to get a at least working result that doesn't to suck that much, it wins atleast occasionally, but I cant test it perfectly because i am not able to run all other submissions on this pc. I probably will re-write the targeting altogether and will add it as another answer later today or tomorrow.
#include <iostream> #include <string> #include <vector> #include <sstream> #include <cmath> #include <ratio> #include <fstream> #include <algorithm> using namespace std; class Town { public: Town(int owner, int townId, int knights, int population, int roundToDefBonus); int getOwner(); int getId(); int getKnights(); int getPopulation(); int getFreeKnights(); int neededConquer(); int getKnightsStable(); int getRoundToDef(); bool operator< (const Town &other) const { return townId < other.townId; } private: int owner; int townId; int knights; int population; int roundToDefBonus; double defBonus; }; Town::Town(int inOwner, int inTownId, int inKnights, int inPopulation, int inRoundToDefBonus) { owner = inOwner; townId = inTownId; knights = inKnights; population = inPopulation; roundToDefBonus = inRoundToDefBonus; if(roundToDefBonus > 0) { defBonus = 1; } else{ defBonus = 1.2; } } int Town::getOwner() { return owner; } int Town::getId() { return townId; } int Town::getKnights() { return knights; } int Town::getPopulation() { return population; } int Town::getFreeKnights() { return knights - population / 2; } int Town::neededConquer() { return max(static_cast<int>(ceil(knights * defBonus + population / 2)), 1); } int Town::getKnightsStable() { return population / 2; } int Town::getRoundToDef() { return roundToDefBonus; } int gameRound; int myId; int thisTownId; Town* thisTown; vector <Town> myTowns; vector <Town> enemyTowns; vector <Town> lastTime; string turn(); Town* bestTarget(int knights); Town* bestSafe(int knights); Town* biggestTarget(int knights); Town* biggestSafe(int knights); string out(string, int, int); string attack(Town*); string safe(Town*); bool sortTowns(const Town & t1, const Town & t2); vector <string> stringSplit(string input, string delimeter); int main(int argc, char* argv[]) { if(argc < 2){ cout << "100 100 100"; ofstream myFile; myFile.open("CalculatedFail.txt"); myFile << "0\n"; myFile.close(); } else{ if(argc == 2){ string input = argv[1]; vector <string> params = stringSplit(input, ";"); gameRound = atoi(params.at(0).c_str()); myId = atoi((params.at(1)).c_str()); thisTownId = atoi(params.at(2).c_str()); ifstream myfile("CalculatedFail.txt"); if(myfile.is_open()){ string line; getline(myfile, line); bool newRound = false; if(atoi(line.c_str()) > gameRound) { newRound = true; } vector <string> oldVals; if(!newRound) { while (getline(myfile, line)) { oldVals = stringSplit(line, "_"); int playerId = atoi(oldVals.at(0).c_str()); int townId = atoi(oldVals.at(1).c_str()); int knights = atoi(oldVals.at(2).c_str()); int population = atoi(oldVals.at(3).c_str()); int roundToDefBonus = atoi(oldVals.at(4).c_str()); lastTime.push_back(Town(playerId, townId, knights, population, roundToDefBonus)); oldVals.clear(); } } else { while (getline(myfile, line)) { oldVals = stringSplit(line, "_"); int playerId = atoi(oldVals.at(0).c_str()); int townId = atoi(oldVals.at(1).c_str()); int knights = atoi(oldVals.at(2).c_str()); int population = atoi(oldVals.at(3).c_str()); int roundToDefBonus = atoi(oldVals.at(4).c_str()); if(roundToDefBonus) { //if round def bonus > 0, decrement because new round roundToDefBonus --; } lastTime.push_back(Town(playerId, townId, knights, population, roundToDefBonus)); oldVals.clear(); } } std::sort(lastTime.begin(), lastTime.end()); } if(lastTime.size() > 0) { vector <string> values; for(int i = 3; i < params.size(); i++) { values = stringSplit(params.at(i), "_"); int playerId = atoi(values.at(0).c_str()); int townId = atoi(values.at(1).c_str()); int knights = atoi(values.at(2).c_str()); int population = atoi(values.at(3).c_str()); int roundsToDef = lastTime.at(townId).getRoundToDef(); if(playerId != lastTime.at(townId).getOwner()) { roundsToDef = 2; } if(playerId == myId){ if(thisTownId != townId) myTowns.push_back(Town(playerId, townId, knights, population, roundsToDef)); else{ thisTown = new Town(playerId, townId, knights, population, roundsToDef); } } else{ enemyTowns.push_back(Town(playerId, townId, knights, population, roundsToDef)); } values.clear(); } } else { vector <string> values; for(int i = 3; i < params.size(); i++) { values = stringSplit(params.at(i), "_"); int playerId = atoi(values.at(0).c_str()); int townId = atoi(values.at(1).c_str()); int knights = atoi(values.at(2).c_str()); int population = atoi(values.at(3).c_str()); if(playerId == myId){ if(thisTownId != townId) myTowns.push_back(Town(playerId, townId, knights, population, 0)); else{ thisTown = new Town(playerId, townId, knights, population, 0); } } else{ enemyTowns.push_back(Town(playerId, townId, knights, population, 0)); } values.clear(); } } string tmp = turn(); cout << tmp; ofstream writeFile("CalculatedFail.txt"); if(writeFile.is_open()) { writeFile << gameRound <<"\n"; writeFile << thisTown->getOwner() <<"_"<<thisTown->getId()<<"_"<<thisTown->getKnights()<<"_"<< thisTown->getPopulation()<<"_"<<thisTown->getRoundToDef()<<"\n"; for(vector<Town>::size_type i = 0; i != myTowns.size(); i++) { writeFile << myTowns[i].getOwner() <<"_"<<myTowns[i].getId()<<"_"<<myTowns[i].getKnights()<<"_"<< myTowns[i].getPopulation()<<"_"<<myTowns[i].getRoundToDef()<<"\n"; } for(vector<Town>::size_type i = 0; i != enemyTowns.size(); i++) { writeFile << enemyTowns[i].getOwner() <<"_"<<enemyTowns[i].getId()<<"_"<<enemyTowns[i].getKnights()<<"_"<< enemyTowns[i].getPopulation()<<"_"<<enemyTowns[i].getRoundToDef()<<"\n"; } } } else{ cout<<"error, wrong parameter"; } } delete thisTown; return 0; } string turn() { Town* safeTarget; Town* attackTarget; if(thisTown->getFreeKnights() < 0) { //evacuate safeTarget = biggestSafe(thisTown->getKnights()); attackTarget = biggestTarget(thisTown->getKnights()); if(safeTarget != nullptr && attackTarget != nullptr){ if(safeTarget->getPopulation() > attackTarget->getPopulation()) { return out("S", safeTarget->getId(), thisTown->getKnights()); } else { return out("A", attackTarget->getId(), thisTown->getKnights()); } } if(safeTarget){ return out("S", safeTarget->getId(), thisTown->getKnights()); } if(attackTarget){ return out("A", attackTarget->getId(), thisTown->getKnights()); } Town* target = &myTowns.at(0); for(vector<Town>::size_type i = 1; i != myTowns.size(); i++) { if(target->getPopulation() < myTowns[i].getPopulation()) target = &myTowns[i]; } return out("S", target->getId(), thisTown->getKnights()); } safeTarget = biggestSafe(thisTown->getFreeKnights()); attackTarget = bestTarget(thisTown->getFreeKnights()); if(safeTarget != nullptr && attackTarget != nullptr){ if(safeTarget->getPopulation() > attackTarget->getPopulation()) { return safe(safeTarget); } else { return attack(attackTarget); } } if(safeTarget){ return safe(safeTarget); } if(attackTarget){ return attack(attackTarget); } return "W"; } Town* bestTarget(int knights) { Town* target = nullptr; double ratio = -1; for(vector<Town>::size_type i = 0; i != enemyTowns.size(); i++) { if(enemyTowns[i].neededConquer() < knights) { if(enemyTowns[i].getPopulation() / enemyTowns[i].neededConquer() > ratio) { target = &enemyTowns[i]; ratio = enemyTowns[i].getPopulation() / enemyTowns[i].neededConquer(); } } } return target; } Town* biggestTarget(int knights) { Town* target = nullptr; int population = -1; for(vector<Town>::size_type i = 0; i != enemyTowns.size(); i++) { if(enemyTowns[i].neededConquer() < knights) { if(enemyTowns[i].getPopulation() > population) { target = &enemyTowns[i]; population = target->getPopulation(); } } } return target; } Town* biggestSafe(int knights) { Town* target = nullptr; int population = -1; for(vector<Town>::size_type i = 0; i != myTowns.size(); i++) { if(myTowns[i].getFreeKnights() < 0 && myTowns[i].getFreeKnights() + knights >= 0){ if(myTowns[i].getPopulation() > population) { target = &myTowns[i]; population = target->getPopulation(); } } } return target; } string attack(Town* target){ int knights; if(thisTown->getPopulation() > target->getPopulation()) { knights = target->neededConquer(); } else{ knights = thisTown->getFreeKnights(); } return out("A", target->getId(), knights); } string safe(Town* target){ int knights; if(thisTown->getPopulation() > target->getPopulation()) { knights = target->getFreeKnights() * -1; } else{ knights = thisTown->getFreeKnights(); } return out("S", target->getId(), knights); } string out(string order, int targedId, int knights) { stringstream tmp; tmp << order << " " << targedId << " " << knights; return tmp.str(); } vector <string> stringSplit(string input, string delimeter) { stringstream tmp(input); vector <string> splitted; string pushThis; while (getline(tmp, pushThis, delimeter.at(0))){ splitted.push_back(pushThis); } return splitted; }
compile with: g++ -std=c++11 CalculatedFail.cpp -o CalculatedFail.exe
google says on linux it is CalculatedFail.out instead of the .exe, but i can't test it.
and run CalculatedFail.exe
as it uses a file to check for the def bonus, running the game simultaneously multiple times may lead to errors...
hope it works properly without to much problems
Asupports another townB, the given number of knights is simply transferred fromAtoB, after which they are controlled by the owner ofB, correct? \$\endgroup\$