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
A
supports another townB
, the given number of knights is simply transferred fromA
toB
, after which they are controlled by the owner ofB
, correct? \$\endgroup\$