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
I assume that when a town
A
supports another townB
, the given number of knights is simply transferred fromA
toB
, after which they are controlled by the owner ofB
, correct? – Zgarb – 2015-01-13T11:21:35.893@Zgarb Correct :) – CommonGuy – 2015-01-13T11:23:38.883
Will you be conducting matches and showing a leaderboard? – Logic Knight – 2015-01-14T05:41:54.157
@CarpetPython Of course, I post it as soon as I have time – CommonGuy – 2015-01-14T06:28:13.403
1@Manu, I have to say I love your KOTHs. THIS is my type of Codegolf.SE questions. Until when are you accepting submissions? I'll start thinking of an algorithm now. Also, I think you should add another rule - max number of submissions per user. – Zaenille – 2015-01-14T06:58:25.530
@MarkGabriel I will add a bounty in some days. When it runs out, it is awarded to the winner. At the moment, there aren't many submissions, so I won't add that rule yet ;) – CommonGuy – 2015-01-14T07:14:21.550
No prob. I have a question about the game loop, which would be answerable if I checked the code but sadly I don't have much time now. Haha! Let's say Town 2 wants to attack using 100 knights. However, before Town 2, Town 1 attacks Town 2 and reduces Town 2's knights to 80. Will Town 2's turn be skipped or will Town 2 still continue his action but with only 80 knights? – Zaenille – 2015-01-14T07:20:23.033
@MarkGabriel Since the game is sequential, Town 1 will attack first. Then the controller calls Town 2 and asks it what to do (Town 2 should now know it only has 80 knights). If Town 2 still attacks with 100 knights, the attack will be cancelled (it is treated as "wait"). – CommonGuy – 2015-01-14T07:31:12.390
I see. That answers my question. Thanks @Manu – Zaenille – 2015-01-14T07:37:55.800
How many times will the simulation be ran? – TheNumberOne – 2015-01-14T20:57:55.527
@TheBestOne the final simulation will be ran 10 times, but in the meantime there will be 3 runs. – CommonGuy – 2015-01-14T21:18:52.487
The description of this game reminds me of TribalWars (an online game where each player starts with one town.) Don't play it. If you want to play to win in the late game, you'll have to forfeit sleeping. And probably working, too. – mbomb007 – 2015-01-22T19:40:05.950
Deleted post until can confirm for all cases. – Moogie – 2015-01-22T21:17:56.147
You should probably shuffle the players before each game. I don't think you're using the new version of Frankenstein. – TheNumberOne – 2015-01-24T18:13:08.833