1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-20 20:23:03 +02:00
vcmi/AI/GeniusAI/AIPriorities.cpp
Trevor Standley a3b6bb4892 AI loads .brain file which contains a list of objects to visit and what features are necessary to determine how valuable that objective is.
AI creates random neural networks and assumes that their outputs are trained values.
2009-08-18 07:37:45 +00:00

244 lines
7.1 KiB
C++

#ifndef AI_PRIORITIES
#define AI_PRIORITIES
#include "AIPriorities.h"
#include <sstream>
using namespace GeniusAI;
Network::Network()
{}
Network::Network(vector<unsigned int> whichFeatures)// random network
:net(whichFeatures.size(), whichFeatures.size()*.601+2, whichFeatures.size()*.251+2, 1),whichFeatures(whichFeatures)
{
}
Network::Network(istream & input)
{
vector<int> whichFeatures;
int feature;
string line;
getline(input,line);
stringstream lineIn(line);
while(lineIn>>feature)
whichFeatures.push_back(feature);
getline(input,line);//get R
net = neuralNetwork(whichFeatures.size(), whichFeatures.size()*.601+2, whichFeatures.size()*.251+2, 1);
}
float Network::feedForward(const vector<float> & stateFeatures)
{
double * input = new double[whichFeatures.size()];
for(int i = 0; i < whichFeatures.size();i++)
input[i]=stateFeatures[whichFeatures[i]];
float ans = net.feedForwardPattern(input)[0];
delete input;
return ans;
}
Priorities::Priorities()//random brain
:numSpecialFeatures(8)
{
/* vector<unsigned int> whichFeatures;//(512);
whichFeatures.push_back(16);
whichFeatures.push_back(17);
networks.push_back(Network(whichFeatures)); //for a friendly hero
networks.push_back(Network(whichFeatures)); //for an enemy hero
whichFeatures.clear();
whichFeatures.push_back(16); //hero's AI value
networks.push_back(Network(whichFeatures)); //for school of magic
whichFeatures.clear();
for(int i = 0; i <=16;i++)
whichFeatures.push_back(i); //hero's AI value is 16
networks.push_back(Network(whichFeatures)); //for treasure chest
whichFeatures.clear();
whichFeatures.push_back(17);
networks.push_back(Network(whichFeatures)); //for a friendly town
networks.push_back(Network(whichFeatures)); //for an enemy town
whichFeatures.clear();
whichFeatures.push_back(16);
networks.push_back(Network(whichFeatures)); //for learning stone
*/
}
Priorities::Priorities(const string & filename) //read brain from file
:numSpecialFeatures(8)
{
ifstream infile(filename.c_str());
// object_num [list of features]
// brain data or "R" for random brain
networks.resize(255);
int object_num;
while(infile>>object_num)
{
networks[object_num].push_back(Network(infile));
}
}
void Priorities::fillFeatures(const CGeniusAI::HypotheticalGameState & hgs)
{
stateFeatures.clear();
stateFeatures.resize(50);
for(int i = 0; i < stateFeatures.size();i++)
stateFeatures[i]=0;
for(int i = 0; i < hgs.resourceAmounts.size();i++) //features 0-7 are resources
stateFeatures[i]=hgs.resourceAmounts[i];
//TODO: //features 8-15 are incomes
specialFeaturesStart = 16; //features 16-23 are special features (filled in by get functions before ANN)
stateFeatures[24] = hgs.AI->m_cb->getDate();
stateFeatures[25] = 1;
}
float Priorities::getCost(vector<int> &resourceCosts,const CGHeroInstance * moved,int distOutOfTheWay)
{
if(resourceCosts.size()==0)return -1;
//TODO: replace with ann
float cost = resourceCosts[0]/4.0+resourceCosts[1]/2.0+resourceCosts[2]/4.0+resourceCosts[3]/2.0+resourceCosts[4]/2.0+resourceCosts[5]/2.0+resourceCosts[6]/3000.0;
if(moved!=NULL) //TODO: multiply by importance of hero
cost+=distOutOfTheWay/10000.0;
return cost;
}
float Priorities::getValue(const CGeniusAI::AIObjective & obj)
{ //resource
vector<int> resourceAmounts(8,0);
int amount;
if(obj.type==CGeniusAI::AIObjective::finishTurn) //TODO: replace with value of visiting that object divided by days till completed
return .0001; //small nonzero
float a;
if(dynamic_cast<const CGeniusAI::HeroObjective* >(&obj))
{
const CGeniusAI::HeroObjective* hobj = dynamic_cast<const CGeniusAI::HeroObjective* >(&obj);
stateFeatures[16] = hobj->whoCanAchieve.front()->h->getTotalStrength();
if(dynamic_cast<const CArmedInstance*>(hobj->object))
stateFeatures[17] = dynamic_cast<const CArmedInstance*>(hobj->object)->getArmyStrength();
switch(hobj->object->ID)
{
case 5: //artifact //TODO: return value of each artifact
return 0;
case 79:
switch(hobj->object->subID)
{
case 6:
amount = 800;
break;
case 0: case 2:
amount = 9.5; //will be rounded, sad
break;
default:
amount = 4;
break;
}
resourceAmounts[hobj->object->subID]=amount;
return getCost(resourceAmounts,NULL,0);
break;
case 55://mystical garden
resourceAmounts[6]=500;
a=getCost(resourceAmounts,NULL,0);
resourceAmounts[6]=0;
resourceAmounts[5]=5;
return (a+getCost(resourceAmounts,NULL,0))*.5;
case 109:
resourceAmounts[6]=1000;
return getCost(resourceAmounts,NULL,0);
case 12://campfire
resourceAmounts[6]=500;
for(int i = 0; i < 6;i++)
resourceAmounts[i]=1;
return getCost(resourceAmounts,NULL,0);
case 112://windmill
for(int i = 1; i < 6;i++)//no wood
resourceAmounts[i]=1;
return getCost(resourceAmounts,NULL,0);
break;
case 49://magic well
//TODO: add features for hero's spell points
break;
case 34: //hero
if(dynamic_cast<const CGHeroInstance*>(hobj->object)->getOwner()==obj.AI->m_cb->getMyColor())//friendly hero
{
stateFeatures[17] = dynamic_cast<const CGHeroInstance*>(hobj->object)->getTotalStrength();
return networks[34][0].feedForward(stateFeatures);
}
else
{
stateFeatures[17] = dynamic_cast<const CGHeroInstance*>(hobj->object)->getTotalStrength();
return networks[34][1].feedForward(stateFeatures);
}
break;
case 98:
if(dynamic_cast<const CGTownInstance*>(hobj->object)->getOwner()==obj.AI->m_cb->getMyColor())//friendly town
{
stateFeatures[17] = dynamic_cast<const CGTownInstance*>(hobj->object)->getArmyStrength();
return networks[98][0].feedForward(stateFeatures);
}
else
{
stateFeatures[17] = dynamic_cast<const CGTownInstance*>(hobj->object)->getArmyStrength();
return networks[98][1].feedForward(stateFeatures);
}
break;
case 88:
//TODO: average value of unknown level 1 spell, or value of known spell
case 89:
//TODO: average value of unknown level 2 spell, or value of known spell
case 90:
//TODO: average value of unknown level 3 spell, or value of known spell
return 0;
break;
case 215://quest guard
return 0;
case 53: //various mines
return networks[53][hobj->object->subID].feedForward(stateFeatures);
case 113://TODO: replace with value of skill for the hero
return 0;
case 103:case 58://TODO: replace with value of seeing x number of new tiles
return 0;
default:
if(networks[hobj->object->ID].size()!=0)
return networks[hobj->object->ID][0].feedForward(stateFeatures);
cout << "don't know the value of ";
switch(obj.type)
{
case CGeniusAI::AIObjective::visit:
cout << "visiting " << hobj->object->ID;
break;
case CGeniusAI::AIObjective::attack:
cout << "attacking " << hobj->object->ID;
break;
case CGeniusAI::AIObjective::finishTurn:
obj.print();
break;
}
cout << endl;
}
}
else //town objective
{
}
return 0;
}
#endif