|
@@ -16,6 +16,36 @@ std::string servername;
|
|
|
std::string runnername;
|
|
|
extern DLL_EXPORT LibClasses * VLC;
|
|
|
|
|
|
+typedef std::map<int, CArtifactInstance*> TArtSet;
|
|
|
+
|
|
|
+namespace Utilities
|
|
|
+{
|
|
|
+ std::string addQuotesIfNeeded(const std::string &s)
|
|
|
+ {
|
|
|
+ if(s.find_first_of(' ') != std::string::npos)
|
|
|
+ return "\"" + s + "\"";
|
|
|
+
|
|
|
+ return s;
|
|
|
+ }
|
|
|
+
|
|
|
+ void prog_help()
|
|
|
+ {
|
|
|
+ std::cout << "If run without args, then StupidAI will be run on b1.json.\n";
|
|
|
+ }
|
|
|
+
|
|
|
+ string toString(int i)
|
|
|
+ {
|
|
|
+ return boost::lexical_cast<string>(i);
|
|
|
+ }
|
|
|
+
|
|
|
+ string describeBonus(const Bonus &b)
|
|
|
+ {
|
|
|
+ return "+" + toString(b.val) + "_to_" + bonusTypeToString(b.type)+"_sub"+toString(b.subtype);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+using namespace Utilities;
|
|
|
+
|
|
|
struct Example
|
|
|
{
|
|
|
//ANN input
|
|
@@ -35,7 +65,6 @@ struct Example
|
|
|
{}
|
|
|
|
|
|
|
|
|
-
|
|
|
inline bool operator<(const Example & rhs) const
|
|
|
{
|
|
|
if (k<rhs.k)
|
|
@@ -64,7 +93,28 @@ struct Example
|
|
|
}
|
|
|
};
|
|
|
|
|
|
-vector<string> getFileNames(const string &dirname = "./examples/", const std::string &ext = "example")
|
|
|
+class Framework
|
|
|
+{
|
|
|
+ static CArtifactInstance *generateArtWithBonus(const Bonus &b);
|
|
|
+ static DuelParameters generateDuel(const ArmyDescriptor &ad); //generates simple duel where both sides have given army
|
|
|
+ static void runCommand(const std::string &command, const std::string &name, const std::string &logsDir = "");
|
|
|
+ static double playBattle(const DuelParameters &dp);
|
|
|
+ static double cmpArtSets(DuelParameters dp, TArtSet setL, TArtSet setR);
|
|
|
+ static double rateArt(const DuelParameters dp, CArtifactInstance * inst); //rates given artifact
|
|
|
+ static int theLastN();
|
|
|
+ static vector<string> getFileNames(const string &dirname = "./examples/", const std::string &ext = "example");
|
|
|
+ static vector<ArmyDescriptor> learningArmies();
|
|
|
+ static vector<Bonus> learningBonuses();
|
|
|
+
|
|
|
+public:
|
|
|
+ Framework();
|
|
|
+ ~Framework();
|
|
|
+
|
|
|
+ static void buildLearningSet();
|
|
|
+ static vector<Example> loadExamples(bool printInfo = true);
|
|
|
+};
|
|
|
+
|
|
|
+vector<string> Framework::getFileNames(const string &dirname, const std::string &ext)
|
|
|
{
|
|
|
vector<string> ret;
|
|
|
if(!fs::exists(dirname))
|
|
@@ -87,7 +137,7 @@ vector<string> getFileNames(const string &dirname = "./examples/", const std::st
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-vector<Example> loadExamples(bool printInfo = true)
|
|
|
+vector<Example> Framework::loadExamples(bool printInfo)
|
|
|
{
|
|
|
std::vector<Example> examples;
|
|
|
BOOST_FOREACH(auto fname, getFileNames("./examples/", "example"))
|
|
@@ -110,34 +160,90 @@ vector<Example> loadExamples(bool printInfo = true)
|
|
|
return examples;
|
|
|
}
|
|
|
|
|
|
-bool matchExample(const Example &ex, int i, int j, int k)
|
|
|
+int Framework::theLastN()
|
|
|
{
|
|
|
- return ex.i == i && ex.j == j && ex.k == k;
|
|
|
+ auto fnames = getFileNames();
|
|
|
+ if(!fnames.size())
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ range::sort(fnames, [](const std::string &a, const std::string &b)
|
|
|
+ {
|
|
|
+ return boost::lexical_cast<int>(fs::basename(a)) < boost::lexical_cast<int>(fs::basename(b));
|
|
|
+ });
|
|
|
+
|
|
|
+ return boost::lexical_cast<int>(fs::basename(fnames.back()));
|
|
|
}
|
|
|
|
|
|
-//generates simple duel where both sides have given army
|
|
|
-DuelParameters generateDuel(const ArmyDescriptor &ad)
|
|
|
+void Framework::buildLearningSet()
|
|
|
{
|
|
|
- DuelParameters dp;
|
|
|
- dp.bfieldType = 1;
|
|
|
- dp.terType = 1;
|
|
|
+ vector<Example> examples = loadExamples();
|
|
|
+ range::sort(examples);
|
|
|
|
|
|
- auto &side = dp.sides[0];
|
|
|
- side.heroId = 0;
|
|
|
- side.heroPrimSkills.resize(4,0);
|
|
|
- BOOST_FOREACH(auto &stack, ad)
|
|
|
+
|
|
|
+ int startExamplesFrom = 0;
|
|
|
+ ofstream learningLog("log.txt", std::ios::app);
|
|
|
+
|
|
|
+ int n = theLastN()+1;
|
|
|
+
|
|
|
+ auto armies = learningArmies();
|
|
|
+ auto bonuese = learningBonuses();
|
|
|
+
|
|
|
+ for(int i = 0; i < armies.size(); i++)
|
|
|
{
|
|
|
- side.stacks[stack.first] = DuelParameters::SideSettings::StackSettings(stack.second.type->idNumber, stack.second.count);
|
|
|
+ string army = "army" + toString(i);
|
|
|
+ for(int j = 0; j < bonuese.size(); j++)
|
|
|
+ {
|
|
|
+ Bonus b = bonuese[j];
|
|
|
+ string bonusStr = "bonus" + toString(j) + describeBonus(b);
|
|
|
+ for(int k = 0; k < 10; k++)
|
|
|
+ {
|
|
|
+ int nHere = n++;
|
|
|
+
|
|
|
+// if(nHere < startExamplesFrom)
|
|
|
+// continue;
|
|
|
+//
|
|
|
+
|
|
|
+
|
|
|
+ tlog2 << "n="<<nHere<<std::endl;
|
|
|
+ b.val = k;
|
|
|
+
|
|
|
+ Example ex;
|
|
|
+ ex.i = i;
|
|
|
+ ex.j = j;
|
|
|
+ ex.k = k;
|
|
|
+ ex.art = generateArtWithBonus(b);
|
|
|
+ ex.dp = generateDuel(armies[i]);
|
|
|
+ ex.description = army + "\t" + describeBonus(b) + "\t";
|
|
|
+
|
|
|
+ if(vstd::contains(examples, ex))
|
|
|
+ {
|
|
|
+ string msg = str(format("n=%d \tarmy %d \tbonus %d \tresult %lf \t Bonus#%s#") % nHere % i %j % ex.value % describeBonus(b));
|
|
|
+ tlog0 << "Already present example, skipping " << msg;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ ex.value = rateArt(ex.dp, ex.art);
|
|
|
+
|
|
|
+ CSaveFile output("./examples/" + toString(nHere) + ".example");
|
|
|
+ output << ex;
|
|
|
+ time_t rawtime;
|
|
|
+ struct tm * timeinfo;
|
|
|
+ time ( &rawtime );
|
|
|
+ timeinfo = localtime ( &rawtime );
|
|
|
+ string msg = str(format("n=%d \tarmy %d \tbonus %d \tresult %lf \t Bonus#%s# \tdate: %s") % nHere % i %j % ex.value % describeBonus(b) % asctime(timeinfo));
|
|
|
+ learningLog << msg << flush;
|
|
|
+ tlog0 << msg;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
- dp.sides[1] = side;
|
|
|
- dp.sides[1].heroId = 1;
|
|
|
- return dp;
|
|
|
+
|
|
|
+ tlog0 << "Set of learning/testing examples is complete and ready!\n";
|
|
|
}
|
|
|
|
|
|
-std::vector<ArmyDescriptor> learningArmies()
|
|
|
+vector<ArmyDescriptor> Framework::learningArmies()
|
|
|
{
|
|
|
- std::vector<ArmyDescriptor> ret;
|
|
|
-
|
|
|
+ vector<ArmyDescriptor> ret;
|
|
|
+
|
|
|
//armia zlozona ze stworow z malymi HP-kami
|
|
|
ArmyDescriptor lowHP;
|
|
|
lowHP[0] = CStackBasicDescriptor(1, 9); //halabardier
|
|
@@ -190,9 +296,9 @@ std::vector<ArmyDescriptor> learningArmies()
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-std::vector<Bonus> learningBonuses()
|
|
|
+vector<Bonus> Framework::learningBonuses()
|
|
|
{
|
|
|
- std::vector<Bonus> ret;
|
|
|
+ vector<Bonus> ret;
|
|
|
|
|
|
|
|
|
Bonus b;
|
|
@@ -231,36 +337,34 @@ std::vector<Bonus> learningBonuses()
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-std::string addQuotesIfNeeded(const std::string &s)
|
|
|
+double Framework::rateArt(const DuelParameters dp, CArtifactInstance * inst)
|
|
|
{
|
|
|
- if(s.find_first_of(' ') != std::string::npos)
|
|
|
- return "\"" + s + "\"";
|
|
|
+ TArtSet setL, setR;
|
|
|
+ setL[inst->artType->possibleSlots[0]] = inst;
|
|
|
|
|
|
- return s;
|
|
|
-}
|
|
|
+ double resultLR = cmpArtSets(dp, setL, setR),
|
|
|
+ resultRL = cmpArtSets(dp, setR, setL),
|
|
|
+ resultsBase = cmpArtSets(dp, TArtSet(), TArtSet());
|
|
|
|
|
|
-void prog_help()
|
|
|
-{
|
|
|
- std::cout << "If run without args, then StupidAI will be run on b1.json.\n";
|
|
|
+ //lewa strona z art 0.9
|
|
|
+ //bez artefaktow -0.41
|
|
|
+ //prawa strona z art. -0.926
|
|
|
+
|
|
|
+ double LRgain = resultLR - resultsBase,
|
|
|
+ RLgain = resultsBase - resultRL;
|
|
|
+ return LRgain+RLgain;
|
|
|
}
|
|
|
|
|
|
-void runCommand(const std::string &command, const std::string &name, const std::string &logsDir = "")
|
|
|
+double Framework::cmpArtSets(DuelParameters dp, TArtSet setL, TArtSet setR)
|
|
|
{
|
|
|
- static std::string commands[100000];
|
|
|
- static int i = 0;
|
|
|
- std::string &cmd = commands[i++];
|
|
|
- if(logsDir.size() && name.size())
|
|
|
- {
|
|
|
- std::string directionLogs = logsDir + "/" + name + ".txt";
|
|
|
- cmd = command + " > " + addQuotesIfNeeded(directionLogs);
|
|
|
- }
|
|
|
- else
|
|
|
- cmd = command;
|
|
|
+ dp.sides[0].artifacts = setL;
|
|
|
+ dp.sides[1].artifacts = setR;
|
|
|
|
|
|
- boost::thread tt(boost::bind(std::system, cmd.c_str()));
|
|
|
+ auto battleOutcome = playBattle(dp);
|
|
|
+ return battleOutcome;
|
|
|
}
|
|
|
|
|
|
-double playBattle(const DuelParameters &dp)
|
|
|
+double Framework::playBattle(const DuelParameters &dp)
|
|
|
{
|
|
|
string battleFileName = "pliczek.ssnb";
|
|
|
{
|
|
@@ -293,24 +397,46 @@ double playBattle(const DuelParameters &dp)
|
|
|
return code / 1000000.0;
|
|
|
}
|
|
|
|
|
|
-typedef std::map<int, CArtifactInstance*> TArtSet;
|
|
|
+void Framework::runCommand(const std::string &command, const std::string &name, const std::string &logsDir /*= ""*/)
|
|
|
+{
|
|
|
+ static std::string commands[100000];
|
|
|
+ static int i = 0;
|
|
|
+ std::string &cmd = commands[i++];
|
|
|
+ if(logsDir.size() && name.size())
|
|
|
+ {
|
|
|
+ std::string directionLogs = logsDir + "/" + name + ".txt";
|
|
|
+ cmd = command + " > " + addQuotesIfNeeded(directionLogs);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ cmd = command;
|
|
|
|
|
|
+ boost::thread tt(boost::bind(std::system, cmd.c_str()));
|
|
|
+}
|
|
|
|
|
|
-double cmpArtSets(DuelParameters dp, TArtSet setL, TArtSet setR)
|
|
|
+DuelParameters Framework::generateDuel(const ArmyDescriptor &ad)
|
|
|
{
|
|
|
- dp.sides[0].artifacts = setL;
|
|
|
- dp.sides[1].artifacts = setR;
|
|
|
+ DuelParameters dp;
|
|
|
+ dp.bfieldType = 1;
|
|
|
+ dp.terType = 1;
|
|
|
|
|
|
- auto battleOutcome = playBattle(dp);
|
|
|
- return battleOutcome;
|
|
|
+ auto &side = dp.sides[0];
|
|
|
+ side.heroId = 0;
|
|
|
+ side.heroPrimSkills.resize(4,0);
|
|
|
+ BOOST_FOREACH(auto &stack, ad)
|
|
|
+ {
|
|
|
+ side.stacks[stack.first] = DuelParameters::SideSettings::StackSettings(stack.second.type->idNumber, stack.second.count);
|
|
|
+ }
|
|
|
+ dp.sides[1] = side;
|
|
|
+ dp.sides[1].heroId = 1;
|
|
|
+ return dp;
|
|
|
}
|
|
|
|
|
|
-CArtifactInstance *generateArtWithBonus(const Bonus &b)
|
|
|
+CArtifactInstance * Framework::generateArtWithBonus(const Bonus &b)
|
|
|
{
|
|
|
std::vector<CArtifactInstance*> ret;
|
|
|
|
|
|
static CArtifact *nowy = NULL;
|
|
|
-
|
|
|
+
|
|
|
if(!nowy)
|
|
|
{
|
|
|
nowy = new CArtifact();
|
|
@@ -325,48 +451,90 @@ CArtifactInstance *generateArtWithBonus(const Bonus &b)
|
|
|
return artinst;
|
|
|
}
|
|
|
|
|
|
-std::vector<CArtifactInstance*> genArts(const std::vector<Bonus> & bonusesToGive)
|
|
|
+class SSN
|
|
|
{
|
|
|
- std::vector<CArtifactInstance*> ret;
|
|
|
- BOOST_FOREACH(auto b, bonusesToGive)
|
|
|
- {
|
|
|
- ret.push_back(generateArtWithBonus(b));
|
|
|
- }
|
|
|
+ FANN::neural_net net;
|
|
|
|
|
|
-// auto bonuses = artinst->getBonuses([](const Bonus *){ return true; });
|
|
|
-// BOOST_FOREACH(Bonus *b, *bonuses)
|
|
|
-// {
|
|
|
-// std::cout << format("%s (%d) value:%d, description: %s\n") % bonusTypeToString(b->type) % b->subtype % b->val % b->Description();
|
|
|
-// }
|
|
|
+ void init();
|
|
|
+ static int ANNCallback(FANN::neural_net &net, FANN::training_data &train, unsigned int max_epochs, unsigned int epochs_between_reports, float desired_error, unsigned int epochs, void *user_data);
|
|
|
+ static double * genSSNinput(const DuelParameters::SideSettings & dp, CArtifactInstance * art, si32 bfieldType, si32 terType);
|
|
|
+ static const unsigned int num_input = 18;
|
|
|
+public:
|
|
|
+ SSN();
|
|
|
+ ~SSN();
|
|
|
|
|
|
- return ret;
|
|
|
+ void learn(const std::vector<Example> & input);
|
|
|
+ double run(const DuelParameters &dp, CArtifactInstance * inst);
|
|
|
+
|
|
|
+ void save(const std::string &filename);
|
|
|
+};
|
|
|
+
|
|
|
+SSN::SSN()
|
|
|
+{
|
|
|
+ init();
|
|
|
}
|
|
|
|
|
|
-//rates given artifact
|
|
|
-double rateArt(const DuelParameters dp, CArtifactInstance * inst)
|
|
|
+void SSN::init()
|
|
|
{
|
|
|
- TArtSet setL, setR;
|
|
|
- setL[inst->artType->possibleSlots[0]] = inst;
|
|
|
+ const float learning_rate = 0.7f;
|
|
|
+ const unsigned int num_layers = 3;
|
|
|
+ const unsigned int num_hidden = 30;
|
|
|
+ const unsigned int num_output = 1;
|
|
|
+ const float desired_error = 0.001f;
|
|
|
+ const unsigned int max_iterations = 300000;
|
|
|
+ const unsigned int iterations_between_reports = 1000;
|
|
|
|
|
|
- double resultLR = cmpArtSets(dp, setL, setR),
|
|
|
- resultRL = cmpArtSets(dp, setR, setL),
|
|
|
- resultsBase = cmpArtSets(dp, TArtSet(), TArtSet());
|
|
|
+ net.create_standard(num_layers, num_input, num_hidden, num_output);
|
|
|
|
|
|
+ net.set_learning_rate(learning_rate);
|
|
|
|
|
|
+ net.set_activation_steepness_hidden(0.9);
|
|
|
+ net.set_activation_steepness_output(1.0);
|
|
|
|
|
|
- //lewa strona z art 0.9
|
|
|
- //bez artefaktow -0.41
|
|
|
- //prawa strona z art. -0.926
|
|
|
+ net.set_activation_function_hidden(FANN::SIGMOID_SYMMETRIC_STEPWISE);
|
|
|
+ net.set_activation_function_output(FANN::SIGMOID_SYMMETRIC_STEPWISE);
|
|
|
|
|
|
- double LRgain = resultLR - resultsBase,
|
|
|
- RLgain = resultsBase - resultRL;
|
|
|
- return LRgain+RLgain;
|
|
|
+ net.randomize_weights(0.0, 1.0);
|
|
|
}
|
|
|
|
|
|
+double SSN::run(const DuelParameters &dp, CArtifactInstance * inst)
|
|
|
+{
|
|
|
+ double * input = genSSNinput(dp.sides[0], inst, dp.bfieldType, dp.terType);
|
|
|
+ double * out = net.run(input);
|
|
|
+ double ret = *out;
|
|
|
+ free(out);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
|
|
|
-const unsigned int num_input = 18;
|
|
|
+int SSN::ANNCallback(FANN::neural_net &net, FANN::training_data &train, unsigned int max_epochs, unsigned int epochs_between_reports, float desired_error, unsigned int epochs, void *user_data)
|
|
|
+{
|
|
|
+ //cout << "Epochs " << setw(8) << epochs << ". "
|
|
|
+ // << "Current Error: " << left << net.get_MSE() << right << endl;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
|
|
|
-double * genSSNinput(const DuelParameters::SideSettings & dp, CArtifactInstance * art, si32 bfieldType, si32 terType)
|
|
|
+void SSN::learn(const std::vector<Example> & input)
|
|
|
+{
|
|
|
+ //FIXME - sypie przy destrukcji
|
|
|
+ //FANN::training_data td;
|
|
|
+ FANN::training_data &td = *new FANN::training_data;
|
|
|
+
|
|
|
+ double ** inputs = new double *[input.size()];
|
|
|
+ double ** outputs = new double *[input.size()];
|
|
|
+ for(int i=0; i<input.size(); ++i)
|
|
|
+ {
|
|
|
+ const auto & ci = input[i];
|
|
|
+ inputs[i] = genSSNinput(ci.dp.sides[0], ci.art, ci.dp.bfieldType, ci.dp.terType);
|
|
|
+ outputs[i] = new double;
|
|
|
+ *(outputs[i]) = ci.value;
|
|
|
+ }
|
|
|
+ td.set_train_data(input.size(), num_input, inputs, 1, outputs);
|
|
|
+ net.set_callback(ANNCallback, NULL);
|
|
|
+ net.train_on_data(td, 1000, 1000, 0.01);
|
|
|
+}
|
|
|
+
|
|
|
+double * SSN::genSSNinput(const DuelParameters::SideSettings & dp, CArtifactInstance * art, si32 bfieldType, si32 terType)
|
|
|
{
|
|
|
double * ret = new double[num_input];
|
|
|
double * cur = ret;
|
|
@@ -378,7 +546,7 @@ double * genSSNinput(const DuelParameters::SideSettings & dp, CArtifactInstance
|
|
|
|
|
|
//creature & hero description
|
|
|
|
|
|
-
|
|
|
+
|
|
|
*(cur++) = dp.heroId/200.0;
|
|
|
for(int k=0; k<4; ++k)
|
|
|
*(cur++) = dp.heroPrimSkills[k]/20.0;
|
|
@@ -400,7 +568,6 @@ double * genSSNinput(const DuelParameters::SideSettings & dp, CArtifactInstance
|
|
|
return ret/div;
|
|
|
};
|
|
|
|
|
|
-
|
|
|
*(cur++) = avg([](CCreature * c){return c->attack;})/50.0;
|
|
|
*(cur++) = avg([](CCreature * c){return c->defence;})/50.0;
|
|
|
*(cur++) = avg([](CCreature * c){return c->speed;})/15.0;
|
|
@@ -408,7 +575,7 @@ double * genSSNinput(const DuelParameters::SideSettings & dp, CArtifactInstance
|
|
|
|
|
|
//bonus description
|
|
|
auto & blist = art->getBonusList();
|
|
|
-
|
|
|
+
|
|
|
*(cur++) = blist[0]->type/100.0;
|
|
|
*(cur++) = blist[0]->subtype/10.0;
|
|
|
*(cur++) = blist[0]->val/100.0;;
|
|
@@ -420,252 +587,27 @@ double * genSSNinput(const DuelParameters::SideSettings & dp, CArtifactInstance
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-//returns how good the artifact is for the neural network
|
|
|
-double runSSN(FANN::neural_net & net, const DuelParameters dp, CArtifactInstance * inst)
|
|
|
+void SSN::save(const std::string &filename)
|
|
|
{
|
|
|
- double * input = genSSNinput(dp.sides[0], inst, dp.bfieldType, dp.terType);
|
|
|
- double * out = net.run(input);
|
|
|
- double ret = *out;
|
|
|
- free(out);
|
|
|
-
|
|
|
- return ret;
|
|
|
+ net.save(filename);
|
|
|
}
|
|
|
|
|
|
-int ANNCallback(FANN::neural_net &net, FANN::training_data &train,
|
|
|
- unsigned int max_epochs, unsigned int epochs_between_reports,
|
|
|
- float desired_error, unsigned int epochs, void *user_data)
|
|
|
+SSN::~SSN()
|
|
|
{
|
|
|
- //cout << "Epochs " << setw(8) << epochs << ". "
|
|
|
- // << "Current Error: " << left << net.get_MSE() << right << endl;
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-void learnSSN(FANN::neural_net & net, const std::vector<Example> & input)
|
|
|
-{
|
|
|
- FANN::training_data td;
|
|
|
-
|
|
|
- double ** inputs = new double *[input.size()];
|
|
|
- double ** outputs = new double *[input.size()];
|
|
|
- for(int i=0; i<input.size(); ++i)
|
|
|
- {
|
|
|
- const auto & ci = input[i];
|
|
|
- inputs[i] = genSSNinput(ci.dp.sides[0], ci.art, ci.dp.bfieldType, ci.dp.terType);
|
|
|
- outputs[i] = new double;
|
|
|
- *(outputs[i]) = ci.value;
|
|
|
- }
|
|
|
- td.set_train_data(input.size(), num_input, inputs, 1, outputs);
|
|
|
- net.set_callback(ANNCallback, NULL);
|
|
|
- net.train_on_data(td, 1000, 1000, 0.01);
|
|
|
-}
|
|
|
-
|
|
|
-void initNet(FANN::neural_net & ret)
|
|
|
-{
|
|
|
- const float learning_rate = 0.7f;
|
|
|
- const unsigned int num_layers = 3;
|
|
|
- const unsigned int num_hidden = 30;
|
|
|
- const unsigned int num_output = 1;
|
|
|
- const float desired_error = 0.001f;
|
|
|
- const unsigned int max_iterations = 300000;
|
|
|
- const unsigned int iterations_between_reports = 1000;
|
|
|
-
|
|
|
- ret.create_standard(num_layers, num_input, num_hidden, num_output);
|
|
|
-
|
|
|
- ret.set_learning_rate(learning_rate);
|
|
|
-
|
|
|
- ret.set_activation_steepness_hidden(0.9);
|
|
|
- ret.set_activation_steepness_output(1.0);
|
|
|
-
|
|
|
- ret.set_activation_function_hidden(FANN::SIGMOID_SYMMETRIC_STEPWISE);
|
|
|
- ret.set_activation_function_output(FANN::SIGMOID_SYMMETRIC_STEPWISE);
|
|
|
-
|
|
|
- ret.randomize_weights(0.0, 1.0);
|
|
|
}
|
|
|
|
|
|
void SSNRun()
|
|
|
{
|
|
|
- std::vector<std::pair<CArtifactInstance *, double> > artNotes;
|
|
|
-
|
|
|
- TArtSet setL, setR;
|
|
|
-
|
|
|
- FANN::neural_net network;
|
|
|
- initNet(network);
|
|
|
-
|
|
|
-// for(int i=0; i<availableArts.size(); ++i)
|
|
|
-// {
|
|
|
-// artNotes.push_back(std::make_pair(availableArts[i], runSSN(network, availableArts[i])));
|
|
|
-// }
|
|
|
-// boost::range::sort(artNotes,
|
|
|
-// [](const std::pair<CArtifactInstance *, double> & a1, const std::pair<CArtifactInstance *, double> & a2)
|
|
|
-// {return a1.second > a2.second;});
|
|
|
-//
|
|
|
-// //pick best arts into setL
|
|
|
-// BOOST_FOREACH(auto & ap, artNotes)
|
|
|
-// {
|
|
|
-// auto art = ap.first;
|
|
|
-// BOOST_FOREACH(auto slot, art->artType->possibleSlots)
|
|
|
-// {
|
|
|
-// if(setL.find(slot) != setL.end())
|
|
|
-// {
|
|
|
-// setL[slot] = art;
|
|
|
-// break;
|
|
|
-// }
|
|
|
-// }
|
|
|
-// }
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- //duels to test on
|
|
|
- std::vector<DuelParameters> dps;
|
|
|
- for(int k = 0; k<10; ++k)
|
|
|
- {
|
|
|
- DuelParameters dp;
|
|
|
-
|
|
|
- dps.push_back(dp);
|
|
|
- }
|
|
|
-
|
|
|
- std::vector<Bonus> btt; //bonuses to test on
|
|
|
- for(int i=0; i<5; ++i)
|
|
|
- {
|
|
|
- Bonus b;
|
|
|
- b.additionalInfo = -1;
|
|
|
- b.duration = Bonus::PERMANENT;
|
|
|
- b.source = Bonus::ARTIFACT;
|
|
|
- b.sid = 0;
|
|
|
- b.turnsRemain = 0xda;
|
|
|
- b.valType = Bonus::ADDITIVE_VALUE;
|
|
|
- b.effectRange = Bonus::NO_LIMIT;
|
|
|
-
|
|
|
- b.type = Bonus::PRIMARY_SKILL;
|
|
|
- b.subtype = PrimarySkill::ATTACK;
|
|
|
- b.val = 5 * i + 1;
|
|
|
- btt.push_back(b);
|
|
|
-
|
|
|
- b.subtype = PrimarySkill::DEFENSE;
|
|
|
- btt.push_back(b);
|
|
|
-
|
|
|
- b.type = Bonus::STACKS_SPEED;
|
|
|
- b.subtype = 0;
|
|
|
- btt.push_back(b);
|
|
|
-
|
|
|
- b.type = Bonus::STACK_HEALTH;
|
|
|
- btt.push_back(b);
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- auto arts = genArts(btt);
|
|
|
-
|
|
|
- //evaluate
|
|
|
- std::vector<Example> setups;
|
|
|
+ //buildLearningSet();
|
|
|
|
|
|
- std::ofstream desOuts("desiredOuts.dat");
|
|
|
|
|
|
- for(int i=0; i<dps.size(); ++i)
|
|
|
- {
|
|
|
- for(int j=0; j<arts.size(); ++j)
|
|
|
- {
|
|
|
- setups.push_back(Example(dps[i], arts[j], rateArt(dps[i], arts[i])));
|
|
|
- desOuts << (*setups.rbegin()).value << " ";
|
|
|
- }
|
|
|
- desOuts << std::endl;
|
|
|
- }
|
|
|
+ auto examples = Framework::loadExamples(false);
|
|
|
|
|
|
- learnSSN(network, setups);
|
|
|
+ SSN network;
|
|
|
+ network.learn(examples);
|
|
|
network.save("network_config_file.net");
|
|
|
}
|
|
|
|
|
|
-string toString(int i)
|
|
|
-{
|
|
|
- return boost::lexical_cast<string>(i);
|
|
|
-}
|
|
|
-
|
|
|
-string describeBonus(const Bonus &b)
|
|
|
-{
|
|
|
- return "+" + toString(b.val) + "_to_" + bonusTypeToString(b.type)+"_sub"+toString(b.subtype);
|
|
|
-}
|
|
|
-
|
|
|
-int theLastN()
|
|
|
-{
|
|
|
- auto fnames = getFileNames();
|
|
|
- if(!fnames.size())
|
|
|
- return -1;
|
|
|
-
|
|
|
- range::sort(fnames, [](const std::string &a, const std::string &b)
|
|
|
- {
|
|
|
- return boost::lexical_cast<int>(fs::basename(a)) < boost::lexical_cast<int>(fs::basename(b));
|
|
|
- });
|
|
|
-
|
|
|
- return boost::lexical_cast<int>(fs::basename(fnames.back()));
|
|
|
-}
|
|
|
-
|
|
|
-void buildLearningSet()
|
|
|
-{
|
|
|
- vector<Example> examples = loadExamples();
|
|
|
- range::sort(examples);
|
|
|
-
|
|
|
-
|
|
|
- int startExamplesFrom = 0;
|
|
|
- ofstream learningLog("log.txt", std::ios::app);
|
|
|
-
|
|
|
- int n = theLastN()+1;
|
|
|
-
|
|
|
- auto armies = learningArmies();
|
|
|
- auto bonuese = learningBonuses();
|
|
|
-
|
|
|
- for(int i = 0; i < armies.size(); i++)
|
|
|
- {
|
|
|
- string army = "army" + toString(i);
|
|
|
- for(int j = 0; j < bonuese.size(); j++)
|
|
|
- {
|
|
|
- Bonus b = bonuese[j];
|
|
|
- string bonusStr = "bonus" + toString(j) + describeBonus(b);
|
|
|
- for(int k = 0; k < 10; k++)
|
|
|
- {
|
|
|
- int nHere = n++;
|
|
|
-
|
|
|
-// if(nHere < startExamplesFrom)
|
|
|
-// continue;
|
|
|
-//
|
|
|
-
|
|
|
-
|
|
|
- tlog2 << "n="<<nHere<<std::endl;
|
|
|
- b.val = k;
|
|
|
-
|
|
|
- Example ex;
|
|
|
- ex.i = i;
|
|
|
- ex.j = j;
|
|
|
- ex.k = k;
|
|
|
- ex.art = generateArtWithBonus(b);
|
|
|
- ex.dp = generateDuel(armies[i]);
|
|
|
- ex.description = army + "\t" + describeBonus(b) + "\t";
|
|
|
-
|
|
|
- if(vstd::contains(examples, ex))
|
|
|
- {
|
|
|
- string msg = str(format("n=%d \tarmy %d \tbonus %d \tresult %lf \t Bonus#%s#") % nHere % i %j % ex.value % describeBonus(b));
|
|
|
- tlog0 << "Already present example, skipping " << msg;
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- ex.value = rateArt(ex.dp, ex.art);
|
|
|
-
|
|
|
- CSaveFile output("./examples/" + toString(nHere) + ".example");
|
|
|
- output << ex;
|
|
|
- time_t rawtime;
|
|
|
- struct tm * timeinfo;
|
|
|
- time ( &rawtime );
|
|
|
- timeinfo = localtime ( &rawtime );
|
|
|
- string msg = str(format("n=%d \tarmy %d \tbonus %d \tresult %lf \t Bonus#%s# \tdate: %s") % nHere % i %j % ex.value % describeBonus(b) % asctime(timeinfo));
|
|
|
- learningLog << msg << flush;
|
|
|
- tlog0 << msg;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- tlog0 << "Set of learning/testing examples is complete and ready!\n";
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
int main(int argc, char **argv)
|
|
|
{
|
|
|
std::cout << "VCMI Odpalarka\nMy path: " << argv[0] << std::endl;
|
|
@@ -736,9 +678,6 @@ int main(int argc, char **argv)
|
|
|
VLC = new LibClasses();
|
|
|
VLC->init();
|
|
|
|
|
|
-
|
|
|
- //buildLearningSet();
|
|
|
-
|
|
|
SSNRun();
|
|
|
|
|
|
return EXIT_SUCCESS;
|