mirror of
https://github.com/vcmi/vcmi.git
synced 2024-11-24 08:32:34 +02:00
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.
This commit is contained in:
parent
c7a307dfed
commit
a3b6bb4892
52
AI/GeniusAI.brain
Normal file
52
AI/GeniusAI.brain
Normal file
@ -0,0 +1,52 @@
|
||||
34 16 17
|
||||
R
|
||||
34 16 17
|
||||
R
|
||||
47 16
|
||||
R
|
||||
101 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 24
|
||||
R
|
||||
98 16 17
|
||||
R
|
||||
98 16 17
|
||||
R
|
||||
100 16
|
||||
R
|
||||
38 16
|
||||
R
|
||||
61 16
|
||||
R
|
||||
53 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
||||
R
|
||||
53 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
||||
R
|
||||
53 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
||||
R
|
||||
53 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
||||
R
|
||||
53 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
||||
R
|
||||
53 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
||||
R
|
||||
53 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
||||
R
|
||||
53 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
||||
R
|
||||
28 16
|
||||
R
|
||||
81 16
|
||||
R
|
||||
83 25
|
||||
R
|
||||
31 16
|
||||
R
|
||||
57 24
|
||||
R
|
||||
23 16
|
||||
R
|
||||
102 16
|
||||
R
|
||||
37 24
|
||||
R
|
||||
51 16
|
||||
R
|
244
AI/GeniusAI/AIPriorities.cpp
Normal file
244
AI/GeniusAI/AIPriorities.cpp
Normal file
@ -0,0 +1,244 @@
|
||||
|
||||
#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
|
39
AI/GeniusAI/AIPriorities.h
Normal file
39
AI/GeniusAI/AIPriorities.h
Normal file
@ -0,0 +1,39 @@
|
||||
#ifndef AIP_H
|
||||
#define AIP_H
|
||||
|
||||
#include <string>
|
||||
#include "CGeniusAI.h"
|
||||
#include "neuralNetwork.h"
|
||||
|
||||
namespace GeniusAI {
|
||||
|
||||
class Network
|
||||
{
|
||||
public:
|
||||
Network();
|
||||
Network(vector<unsigned int> whichFeatures);// random network
|
||||
Network(istream & input);
|
||||
vector<unsigned int> whichFeatures;
|
||||
float feedForward(const vector<float> & stateFeatures);
|
||||
neuralNetwork net; //a network with whichFeatures.size() inputs, and 1 output
|
||||
};
|
||||
|
||||
|
||||
class Priorities
|
||||
{
|
||||
public:
|
||||
Priorities(); //random brain
|
||||
Priorities(const string & filename); //read brain from file
|
||||
|
||||
|
||||
vector<float> stateFeatures;
|
||||
int specialFeaturesStart;
|
||||
int numSpecialFeatures;
|
||||
void fillFeatures(const CGeniusAI::HypotheticalGameState & AI);
|
||||
float getValue(const CGeniusAI::AIObjective & obj);
|
||||
float getCost(vector<int> &resourceCosts,const CGHeroInstance * moved,int distOutOfTheWay);
|
||||
vector<vector<Network> > networks;
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
@ -1,9 +1,11 @@
|
||||
#include "CGeniusAI.h"
|
||||
#include "AIPriorities.h"
|
||||
#include <iostream>
|
||||
#include "../../hch/CBuildingHandler.h"
|
||||
#include "../../hch/CHeroHandler.h"
|
||||
#include "../../lib/VCMI_Lib.h"
|
||||
#include "../../lib/NetPacks.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace GeniusAI;
|
||||
|
||||
@ -49,31 +51,33 @@ CGeniusAI::HypotheticalGameState::TownModel::TownModel(const CGTownInstance *t):
|
||||
creaturesInGarrison = t->army;
|
||||
}
|
||||
|
||||
CGeniusAI::HypotheticalGameState::HypotheticalGameState(CGeniusAI & AI)
|
||||
:knownVisitableObjects(AI.knownVisitableObjects)
|
||||
CGeniusAI::HypotheticalGameState::HypotheticalGameState(CGeniusAI & ai)
|
||||
:knownVisitableObjects(ai.knownVisitableObjects)
|
||||
{
|
||||
std::vector < const CGHeroInstance *> heroes = AI.m_cb->getHeroesInfo();
|
||||
AI = &ai;
|
||||
std::vector < const CGHeroInstance *> heroes = ai.m_cb->getHeroesInfo();
|
||||
for(std::vector < const CGHeroInstance *>::iterator i = heroes.begin(); i != heroes.end(); i++)
|
||||
heroModels.push_back(HeroModel(*i));
|
||||
|
||||
std::vector < const CGTownInstance *> towns = AI.m_cb->getTownsInfo();
|
||||
std::vector < const CGTownInstance *> towns = ai.m_cb->getTownsInfo();
|
||||
for(std::vector < const CGTownInstance *>::iterator i = towns.begin(); i != towns.end(); i++)
|
||||
if((*i)->tempOwner==AI.m_cb->getMyColor())
|
||||
if((*i)->tempOwner==ai.m_cb->getMyColor())
|
||||
townModels.push_back(TownModel(*i));
|
||||
|
||||
if(AI.m_cb->howManyTowns()!=0)
|
||||
AvailableHeroesToBuy = AI.m_cb->getAvailableHeroes(AI.m_cb->getTownInfo(0,0));
|
||||
if(ai.m_cb->howManyTowns()!=0)
|
||||
AvailableHeroesToBuy = ai.m_cb->getAvailableHeroes(ai.m_cb->getTownInfo(0,0));
|
||||
|
||||
for(int i = 0; i < 8;i++)resourceAmounts.push_back(AI.m_cb->getResourceAmount(i));
|
||||
for(int i = 0; i < 8;i++)resourceAmounts.push_back(ai.m_cb->getResourceAmount(i));
|
||||
}
|
||||
|
||||
void CGeniusAI::HypotheticalGameState::update(CGeniusAI & AI)
|
||||
void CGeniusAI::HypotheticalGameState::update(CGeniusAI & ai)
|
||||
{
|
||||
knownVisitableObjects = AI.knownVisitableObjects;
|
||||
AI = &ai;
|
||||
// knownVisitableObjects = ai.knownVisitableObjects;
|
||||
|
||||
std::vector<HeroModel> oldModels = heroModels;
|
||||
heroModels.clear();
|
||||
std::vector < const CGHeroInstance *> heroes = AI.m_cb->getHeroesInfo();
|
||||
std::vector < const CGHeroInstance *> heroes = ai.m_cb->getHeroesInfo();
|
||||
for(std::vector < const CGHeroInstance *>::iterator i = heroes.begin(); i != heroes.end(); i++)
|
||||
heroModels.push_back(HeroModel(*i));
|
||||
for(int i = 0; i < oldModels.size();i++)
|
||||
@ -82,19 +86,19 @@ void CGeniusAI::HypotheticalGameState::update(CGeniusAI & AI)
|
||||
heroModels[ii].finished = true;
|
||||
|
||||
townModels.clear();
|
||||
std::vector < const CGTownInstance *> towns = AI.m_cb->getTownsInfo();
|
||||
std::vector < const CGTownInstance *> towns = ai.m_cb->getTownsInfo();
|
||||
for(std::vector < const CGTownInstance *>::iterator i = towns.begin(); i != towns.end(); i++)
|
||||
if((*i)->tempOwner==AI.m_cb->getMyColor())
|
||||
if((*i)->tempOwner==ai.m_cb->getMyColor())
|
||||
townModels.push_back(TownModel(*i));
|
||||
|
||||
if(AI.m_cb->howManyTowns()!=0)
|
||||
AvailableHeroesToBuy = AI.m_cb->getAvailableHeroes(AI.m_cb->getTownInfo(0,0));
|
||||
if(ai.m_cb->howManyTowns()!=0)
|
||||
AvailableHeroesToBuy = ai.m_cb->getAvailableHeroes(ai.m_cb->getTownInfo(0,0));
|
||||
|
||||
resourceAmounts.clear();
|
||||
for(int i = 0; i < 8;i++)resourceAmounts.push_back(AI.m_cb->getResourceAmount(i));
|
||||
for(int i = 0; i < 8;i++)resourceAmounts.push_back(ai.m_cb->getResourceAmount(i));
|
||||
}
|
||||
|
||||
CGeniusAI::HeroObjective::HeroObjective(Type t,const CGObjectInstance * object,HypotheticalGameState::HeroModel *h,CGeniusAI * ai):object(object)
|
||||
CGeniusAI::HeroObjective::HeroObjective(const HypotheticalGameState &hgs,Type t,const CGObjectInstance * object,HypotheticalGameState::HeroModel *h,CGeniusAI * ai):object(object),hgs(hgs)
|
||||
{
|
||||
AI = ai;
|
||||
pos = object->pos;
|
||||
@ -105,15 +109,18 @@ CGeniusAI::HeroObjective::HeroObjective(Type t,const CGObjectInstance * object,H
|
||||
|
||||
float CGeniusAI::HeroObjective::getValue() const
|
||||
{
|
||||
if(_value>0)
|
||||
return _value;
|
||||
if(_value>=0)
|
||||
return _value-_cost;
|
||||
|
||||
vector<int> resourceCosts;
|
||||
vector<int> resourceCosts; //TODO: each object should have an associated cost to visit IE (tree of knowledge 1000 gold/10 gems)
|
||||
for(int i = 0; i < 8;i++)
|
||||
resourceCosts.push_back(0);
|
||||
if(object->ID==47) //school of magic
|
||||
resourceCosts[6]+=1000;
|
||||
|
||||
float bestCost = 9e9;
|
||||
if(type !=AIObjective::finishTurn)
|
||||
{
|
||||
for(int i = 0; i < whoCanAchieve.size();i++)
|
||||
{
|
||||
int distOutOfTheWay = 0;
|
||||
@ -133,15 +140,17 @@ float CGeniusAI::HeroObjective::getValue() const
|
||||
|
||||
|
||||
|
||||
float cost = CostModel(resourceCosts,whoCanAchieve[i]->h,distOutOfTheWay).getCost();
|
||||
float cost = AI->m_priorities->getCost(resourceCosts,whoCanAchieve[i]->h,distOutOfTheWay);
|
||||
if(cost < bestCost)
|
||||
bestCost = cost;
|
||||
|
||||
}
|
||||
if(bestCost < 10000)
|
||||
cout << "best cost = " << bestCost << endl;
|
||||
_value = rand()%1000+100-bestCost;
|
||||
return _value;
|
||||
}
|
||||
else bestCost = 0;
|
||||
//if(bestCost < 10000) cout << "best cost = " << bestCost << endl;
|
||||
_value = AI->m_priorities->getValue(*this);
|
||||
_cost=bestCost;
|
||||
return _value-_cost;
|
||||
}
|
||||
bool CGeniusAI::HeroObjective::operator < (const HeroObjective &other)const
|
||||
{
|
||||
@ -162,17 +171,19 @@ void CGeniusAI::HeroObjective::print() const
|
||||
switch(type)
|
||||
{
|
||||
case visit:
|
||||
cout << "visit " << object->hoverName;
|
||||
cout << "visit " << object->hoverName << " at (" <<object->pos.x << ","<<object->pos.y << ")" ;
|
||||
break;
|
||||
case attack:
|
||||
cout << "attack " << object->hoverName;
|
||||
case finishTurn:
|
||||
cout << "finish turn";
|
||||
}
|
||||
if(whoCanAchieve.size()==1)
|
||||
cout << " with " << whoCanAchieve.front()->h->hoverName;
|
||||
}
|
||||
|
||||
CGeniusAI::TownObjective::TownObjective(Type t,HypotheticalGameState::TownModel * tn,int Which,CGeniusAI * ai)
|
||||
:whichTown(tn),which(Which)
|
||||
CGeniusAI::TownObjective::TownObjective(const HypotheticalGameState &hgs,Type t,HypotheticalGameState::TownModel * tn,int Which,CGeniusAI * ai)
|
||||
:whichTown(tn),which(Which),hgs(hgs)
|
||||
{
|
||||
AI=ai;
|
||||
type = t;
|
||||
@ -181,22 +192,53 @@ CGeniusAI::TownObjective::TownObjective(Type t,HypotheticalGameState::TownModel
|
||||
|
||||
float CGeniusAI::TownObjective::getValue() const
|
||||
{
|
||||
if(_value>0)
|
||||
return _value;
|
||||
_value = rand()%1000+100;
|
||||
return _value;
|
||||
}
|
||||
if(_value>=0)
|
||||
return _value-_cost;
|
||||
float cost;
|
||||
|
||||
vector<int> resourceCosts(8,0);
|
||||
CBuilding * b;
|
||||
CCreature * creature;
|
||||
int ID,newID, howMany;
|
||||
switch(type)
|
||||
{
|
||||
case recruitHero:
|
||||
resourceCosts[6]=2500;
|
||||
break;
|
||||
case buildBuilding:
|
||||
b = VLC->buildh->buildings[whichTown->t->subID][which];
|
||||
for(int i = 0; b && i < b->resources.size();i++)
|
||||
resourceCosts[i]=b->resources[i];
|
||||
break;
|
||||
|
||||
case recruitCreatures:
|
||||
ID = whichTown->creaturesToRecruit[which].second.back(); //buy upgraded if possible
|
||||
creature = &VLC->creh->creatures[ID];
|
||||
howMany = whichTown->creaturesToRecruit[which].first;
|
||||
for(int i = 0; i < creature->cost.size();i++)
|
||||
amin(howMany,creature->cost[i]?hgs.resourceAmounts[i]/creature->cost[i]:INT_MAX);
|
||||
for(int i = 0; creature && i < creature->cost.size();i++)
|
||||
resourceCosts[i]=creature->cost[i]*howMany;
|
||||
|
||||
|
||||
break;
|
||||
case upgradeCreatures:
|
||||
UpgradeInfo ui = AI->m_cb->getUpgradeInfo(whichTown->t,which);
|
||||
ID = whichTown->creaturesInGarrison.slots[which].first;
|
||||
howMany = whichTown->creaturesInGarrison.slots[which].second;
|
||||
newID = ui.newID.back();
|
||||
for(std::set<std::pair<int,int> >::iterator i = ui.cost[which].begin();i!=ui.cost[which].end();i++)
|
||||
resourceCosts[i->first] = i->second*howMany;
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
|
||||
CGeniusAI::CostModel::CostModel(vector<int> &resourceCosts,const CGHeroInstance * moved,int distOutOfTheWay)
|
||||
:resourceCosts(resourceCosts),moved(moved),distOutOfTheWay(distOutOfTheWay)
|
||||
{}
|
||||
|
||||
float CGeniusAI::CostModel::getCost()
|
||||
{
|
||||
if(resourceCosts.size()==0||moved == NULL)return -1;
|
||||
//TODO: replace with ann
|
||||
return 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+distOutOfTheWay/10000.0;
|
||||
_cost = AI->m_priorities->getCost(resourceCosts,NULL,0);
|
||||
_value = AI->m_priorities->getValue(*this);
|
||||
return _value-_cost;
|
||||
}
|
||||
|
||||
|
||||
@ -257,7 +299,7 @@ void CGeniusAI::TownObjective::print() const
|
||||
case upgradeCreatures:
|
||||
UpgradeInfo ui = AI->m_cb->getUpgradeInfo(whichTown->t,which);
|
||||
ID = whichTown->creaturesInGarrison.slots[which].first;
|
||||
cout << "upgrade " << VLC->creh->creatures[ID].namePl << endl;
|
||||
cout << "upgrade " << VLC->creh->creatures[ID].namePl;
|
||||
//ui.cost
|
||||
|
||||
break;
|
||||
@ -268,10 +310,12 @@ void CGeniusAI::TownObjective::print() const
|
||||
CGeniusAI::CGeniusAI()
|
||||
: m_generalAI(), m_state(NO_BATTLE)
|
||||
{
|
||||
m_priorities = new Priorities("AI/GeniusAI.brain");
|
||||
}
|
||||
|
||||
CGeniusAI::~CGeniusAI()
|
||||
{
|
||||
delete m_priorities;
|
||||
}
|
||||
|
||||
void CGeniusAI::init(ICallback *CB)
|
||||
@ -336,9 +380,9 @@ void CGeniusAI::addHeroObjectives(CGeniusAI::HypotheticalGameState::HeroModel &h
|
||||
if(dynamic_cast<const CGHeroInstance *> (i->o))
|
||||
enemyStrength = (dynamic_cast<const CGHeroInstance *> (i->o))->getHeroStrength();
|
||||
if(dynamic_cast<const CGTownInstance *> (i->o))
|
||||
enemyStrength = (dynamic_cast<const CGTownInstance *> (i->o))->getArmyStrength()*1.5;
|
||||
enemyStrength = (dynamic_cast<const CGTownInstance *> (i->o))->getArmyStrength()*1.2;
|
||||
|
||||
if(enemyStrength*1.5 > h.h->getHeroStrength()) //TODO: ballence these numbers using objective cost formula.
|
||||
if(enemyStrength*1.2 > h.h->getHeroStrength()) //TODO: ballence these numbers using objective cost formula.
|
||||
continue;
|
||||
if(enemyStrength!=0)tp = AIObjective::attack;
|
||||
}
|
||||
@ -352,6 +396,13 @@ void CGeniusAI::addHeroObjectives(CGeniusAI::HypotheticalGameState::HeroModel &h
|
||||
if(i->o->id==h.h->id) //don't visit yourself
|
||||
continue;
|
||||
|
||||
if(i->o->ID==88||i->o->ID==89||i->o->ID==90)
|
||||
{
|
||||
//TODO: if no spell book continue
|
||||
//TODO: if the shrine's spell is identified, and the hero already has it, continue
|
||||
|
||||
}
|
||||
|
||||
destination = i->o->getSightCenter();
|
||||
|
||||
if(hpos.z==destination.z) //don't try to take a path from the underworld to the top or vice versa
|
||||
@ -362,7 +413,7 @@ void CGeniusAI::addHeroObjectives(CGeniusAI::HypotheticalGameState::HeroModel &h
|
||||
if(path.nodes[0].dist<movement)
|
||||
{
|
||||
|
||||
HeroObjective ho(tp,i->o,&h,this);
|
||||
HeroObjective ho(hgs,tp,i->o,&h,this);
|
||||
std::set<HeroObjective>::iterator found = currentHeroObjectives.find(ho);
|
||||
if(found==currentHeroObjectives.end())
|
||||
currentHeroObjectives.insert(ho);
|
||||
@ -387,7 +438,7 @@ void CGeniusAI::addHeroObjectives(CGeniusAI::HypotheticalGameState::HeroModel &h
|
||||
|
||||
h.interestingPos = interestingPos;
|
||||
if(h.remainingMovement>0&&m_cb->getPath(hpos,interestingPos,h.h,path)) // there ought to be a path
|
||||
currentHeroObjectives.insert(HeroObjective(HeroObjective::finishTurn,h.h,&h,this));
|
||||
currentHeroObjectives.insert(HeroObjective(hgs,HeroObjective::finishTurn,h.h,&h,this));
|
||||
|
||||
|
||||
}
|
||||
@ -406,6 +457,7 @@ void CGeniusAI::HeroObjective::fulfill(CGeniusAI & cg,HypotheticalGameState & hg
|
||||
{
|
||||
case finishTurn:
|
||||
h = whoCanAchieve.front();
|
||||
h->finished=true;
|
||||
hpos = h->pos;
|
||||
destination = h->interestingPos;
|
||||
if(!cg.m_cb->getPath(hpos,destination,h->h,path)) {cout << "AI error: invalid destination" << endl; return;}
|
||||
@ -445,7 +497,6 @@ void CGeniusAI::HeroObjective::fulfill(CGeniusAI & cg,HypotheticalGameState & hg
|
||||
}
|
||||
|
||||
destination = bestPos;
|
||||
h->finished=true;
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
break;
|
||||
@ -472,7 +523,7 @@ void CGeniusAI::HeroObjective::fulfill(CGeniusAI & cg,HypotheticalGameState & hg
|
||||
|
||||
|
||||
|
||||
float cost = CostModel(resourceCosts,whoCanAchieve[i]->h,distOutOfTheWay).getCost();
|
||||
float cost = AI->m_priorities->getCost(resourceCosts,whoCanAchieve[i]->h,distOutOfTheWay);
|
||||
if(cost < bestCost)
|
||||
{
|
||||
bestCost = cost;
|
||||
@ -481,7 +532,7 @@ void CGeniusAI::HeroObjective::fulfill(CGeniusAI & cg,HypotheticalGameState & hg
|
||||
|
||||
}
|
||||
|
||||
h = whoCanAchieve[bestHero];//TODO:replace with best hero for the job
|
||||
h = whoCanAchieve[bestHero]; //lowest cost hero
|
||||
//if(dynamic_cast<const CGVisitableOPH *> (object))
|
||||
// std::cout << h->h->name << " is visiting " << object->hoverName << std::endl;
|
||||
hpos = h->pos;
|
||||
@ -595,7 +646,7 @@ void CGeniusAI::addTownObjectives(HypotheticalGameState::TownModel &t, Hypotheti
|
||||
for(int i =0; i < hgs.AvailableHeroesToBuy.size();i++)
|
||||
if(hgs.AvailableHeroesToBuy[i]!=NULL&&(t.t->subID==(hgs.AvailableHeroesToBuy[i]->type->heroType/2)))
|
||||
{
|
||||
TownObjective to(AIObjective::recruitHero,&t,0,this);
|
||||
TownObjective to(hgs,AIObjective::recruitHero,&t,0,this);
|
||||
currentTownObjectives.insert(to);
|
||||
}
|
||||
}
|
||||
@ -608,7 +659,7 @@ void CGeniusAI::addTownObjectives(HypotheticalGameState::TownModel &t, Hypotheti
|
||||
{
|
||||
if(m_cb->canBuildStructure(t.t,i->first)==7)
|
||||
{
|
||||
TownObjective to(AIObjective::buildBuilding,&t,i->first,this);
|
||||
TownObjective to(hgs,AIObjective::buildBuilding,&t,i->first,this);
|
||||
currentTownObjectives.insert(to);
|
||||
//cout <<"can build " << i->first << " "<< i->second->Name() << endl;
|
||||
}
|
||||
@ -630,7 +681,7 @@ void CGeniusAI::addTownObjectives(HypotheticalGameState::TownModel &t, Hypotheti
|
||||
if(!canAfford) continue;
|
||||
|
||||
//cout << "town has " << t.t->creatures[i].first << " "<< creature->namePl << " (AI Strength " << creature->AIValue << ")." << endl;
|
||||
TownObjective to(AIObjective::recruitCreatures,&t,i,this);
|
||||
TownObjective to(hgs,AIObjective::recruitCreatures,&t,i,this);
|
||||
currentTownObjectives.insert(to);
|
||||
|
||||
}
|
||||
@ -649,7 +700,7 @@ void CGeniusAI::addTownObjectives(HypotheticalGameState::TownModel &t, Hypotheti
|
||||
canAfford = false;
|
||||
if(canAfford)
|
||||
{
|
||||
TownObjective to(AIObjective::upgradeCreatures,&t,i->first,this);
|
||||
TownObjective to(hgs,AIObjective::upgradeCreatures,&t,i->first,this);
|
||||
currentTownObjectives.insert(to);
|
||||
}
|
||||
}
|
||||
@ -725,11 +776,13 @@ void CGeniusAI::fillObjectiveQueue(HypotheticalGameState & hgs)
|
||||
|
||||
for(std::vector <CGeniusAI::HypotheticalGameState::TownModel>::iterator i = hgs.townModels.begin(); i != hgs.townModels.end(); i++)
|
||||
addTownObjectives(*i,hgs);
|
||||
|
||||
for(std::set<CGeniusAI::HeroObjective>::iterator i = currentHeroObjectives.begin(); i != currentHeroObjectives.end(); i++)
|
||||
objectiveQueue.push_back(AIObjectivePtrCont((CGeniusAI::HeroObjective *)&(*i)));
|
||||
for(std::set<CGeniusAI::TownObjective>::iterator i = currentTownObjectives.begin(); i != currentTownObjectives.end(); i++)
|
||||
objectiveQueue.push_back(AIObjectivePtrCont((CGeniusAI::TownObjective *)&(*i)));
|
||||
}
|
||||
|
||||
CGeniusAI::AIObjective * CGeniusAI::getBestObjective()
|
||||
{
|
||||
trueGameState.update(*this);
|
||||
@ -738,16 +791,25 @@ CGeniusAI::AIObjective * CGeniusAI::getBestObjective()
|
||||
|
||||
// if(!objectiveQueue.empty())
|
||||
// return max_element(objectiveQueue.begin(),objectiveQueue.end())->obj;
|
||||
|
||||
m_priorities->fillFeatures(trueGameState);
|
||||
if(objectiveQueue.empty()) return NULL;
|
||||
sort(objectiveQueue.begin(),objectiveQueue.end());
|
||||
reverse(objectiveQueue.begin(),objectiveQueue.end());
|
||||
int num= 1;
|
||||
for(std::vector<AIObjectivePtrCont> ::iterator i = objectiveQueue.begin(); i < objectiveQueue.end();i++)
|
||||
{
|
||||
cout << num++ << ": ";
|
||||
i->obj->print();
|
||||
cout << endl;
|
||||
}
|
||||
// for(std::vector<AIObjectivePtrCont> ::iterator i = objectiveQueue.begin(); i < objectiveQueue.end();i++)
|
||||
// {
|
||||
// if(!dynamic_cast<HeroObjective*>(i->obj))continue;
|
||||
// cout << num++ << ": ";
|
||||
// i->obj->print();
|
||||
// cout << " value: " << i->obj->getValue();
|
||||
// cout << endl;
|
||||
// }
|
||||
// int choice = 0;
|
||||
// cout << "which would you do? (enter 0 for none): ";
|
||||
// cin >> choice;
|
||||
cout << "doing best of " << objectiveQueue.size() << " ";
|
||||
objectiveQueue.front().obj->print();
|
||||
cout << endl;
|
||||
|
||||
return objectiveQueue.front().obj;
|
||||
|
||||
@ -788,7 +850,7 @@ void CGeniusAI::yourTurn()
|
||||
|
||||
m_cb->waitTillRealize = false;
|
||||
}
|
||||
|
||||
/*
|
||||
void CGeniusAI::startFirstTurn()
|
||||
{
|
||||
|
||||
@ -797,7 +859,7 @@ void CGeniusAI::startFirstTurn()
|
||||
const CGTownInstance * town = m_cb->getTownInfo(0,0);
|
||||
const CGHeroInstance * heroInst = m_cb->getHeroInfo(0,0);
|
||||
|
||||
TownObjective(AIObjective::recruitHero,&hgs.townModels.front(),0,this).fulfill(*this,hgs);
|
||||
TownObjective(hgs,AIObjective::recruitHero,&hgs.townModels.front(),0,this).fulfill(*this,hgs);
|
||||
|
||||
m_cb->swapGarrisonHero(town);
|
||||
hgs.update(*this);
|
||||
@ -811,14 +873,14 @@ void CGeniusAI::startFirstTurn()
|
||||
if(creature->cost[ii]>hgs.resourceAmounts[ii])
|
||||
canAfford = false; // can we afford at least one creature?
|
||||
if(!canAfford) continue;
|
||||
TownObjective(AIObjective::recruitCreatures,&hgs.townModels.front(),i,this).fulfill(*this,hgs);
|
||||
TownObjective(hgs,AIObjective::recruitCreatures,&hgs.townModels.front(),i,this).fulfill(*this,hgs);
|
||||
}
|
||||
hgs.update(*this);
|
||||
|
||||
HypotheticalGameState::HeroModel *hero;
|
||||
for(int i = 0; i < hgs.heroModels.size();i++)
|
||||
if(hgs.heroModels[i].h->id==heroInst->id)
|
||||
HeroObjective(AIObjective::visit,town,hero=&hgs.heroModels[i],this).fulfill(*this,hgs);
|
||||
HeroObjective(hgs,AIObjective::visit,town,hero=&hgs.heroModels[i],this).fulfill(*this,hgs);
|
||||
|
||||
hgs.update(*this);
|
||||
|
||||
@ -829,6 +891,7 @@ void CGeniusAI::startFirstTurn()
|
||||
|
||||
}
|
||||
|
||||
*/
|
||||
void CGeniusAI::heroKilled(const CGHeroInstance * hero)
|
||||
{
|
||||
|
||||
|
@ -21,12 +21,17 @@ enum BattleState
|
||||
ENDING_BATTLE
|
||||
};
|
||||
|
||||
|
||||
class Priorities;
|
||||
|
||||
class CGeniusAI : public CGlobalAI
|
||||
{
|
||||
private:
|
||||
ICallback* m_cb;
|
||||
GeniusAI::BattleAI::CBattleLogic* m_battleLogic;
|
||||
GeniusAI::GeneralAI::CGeneralAI m_generalAI;
|
||||
GeniusAI::Priorities * m_priorities;
|
||||
|
||||
|
||||
CondSh<BattleState> m_state; //are we engaged into battle?
|
||||
|
||||
@ -59,10 +64,10 @@ private:
|
||||
bool hasBuilt;
|
||||
};
|
||||
HypotheticalGameState(){}
|
||||
HypotheticalGameState(CGeniusAI & AI);
|
||||
|
||||
void update(CGeniusAI & AI);
|
||||
HypotheticalGameState(CGeniusAI & ai);
|
||||
|
||||
void update(CGeniusAI & ai);
|
||||
CGeniusAI * AI;
|
||||
std::vector<const CGHeroInstance *> AvailableHeroesToBuy;
|
||||
std::vector<int> resourceAmounts;
|
||||
std::vector<HeroModel> heroModels;
|
||||
@ -70,28 +75,18 @@ private:
|
||||
std::set< AIObjectContainer > knownVisitableObjects;
|
||||
};
|
||||
|
||||
struct CostModel
|
||||
{
|
||||
CostModel(vector<int> &resourceCosts,const CGHeroInstance * moved,int distOutOfTheWay);
|
||||
CostModel():moved(NULL){}
|
||||
vector<int> resourceCosts;
|
||||
const CGHeroInstance * moved;
|
||||
int distOutOfTheWay;
|
||||
float getCost();
|
||||
};
|
||||
|
||||
class AIObjective
|
||||
{
|
||||
public:
|
||||
enum Type
|
||||
{
|
||||
//hero objectives
|
||||
visit, //done
|
||||
visit, //done TODO: upon visit friendly hero, trade
|
||||
attack, //done
|
||||
flee,
|
||||
//flee,
|
||||
dismissUnits,
|
||||
dismissYourself,
|
||||
finishTurn, //done //uses up remaining motion to get somewhere nice.
|
||||
finishTurn, //done //uses up remaining motion to get somewhere interesting.
|
||||
|
||||
//town objectives
|
||||
recruitHero, //done
|
||||
@ -99,7 +94,6 @@ private:
|
||||
recruitCreatures, //done
|
||||
upgradeCreatures //done
|
||||
};
|
||||
CostModel cost;
|
||||
CGeniusAI * AI;
|
||||
Type type;
|
||||
virtual void fulfill(CGeniusAI &,HypotheticalGameState & hgs)=0;
|
||||
@ -111,13 +105,14 @@ private:
|
||||
class HeroObjective: public AIObjective
|
||||
{
|
||||
public:
|
||||
HypotheticalGameState hgs;
|
||||
int3 pos;
|
||||
const CGObjectInstance * object;
|
||||
std::vector<HypotheticalGameState::HeroModel *> whoCanAchieve;
|
||||
|
||||
HeroObjective(){}
|
||||
HeroObjective(Type t):object(NULL){type = t;}
|
||||
HeroObjective(Type t,const CGObjectInstance * object,HypotheticalGameState::HeroModel *h,CGeniusAI * AI);
|
||||
HeroObjective(const HypotheticalGameState &hgs,Type t,const CGObjectInstance * object,HypotheticalGameState::HeroModel *h,CGeniusAI * AI);
|
||||
bool operator < (const HeroObjective &other)const;
|
||||
void fulfill(CGeniusAI &,HypotheticalGameState & hgs);
|
||||
HypotheticalGameState pretend(const HypotheticalGameState &hgs){return hgs;};
|
||||
@ -125,6 +120,7 @@ private:
|
||||
void print() const;
|
||||
private:
|
||||
mutable float _value;
|
||||
mutable float _cost;
|
||||
};
|
||||
|
||||
//town objectives
|
||||
@ -136,10 +132,11 @@ private:
|
||||
class TownObjective: public AIObjective
|
||||
{
|
||||
public:
|
||||
HypotheticalGameState hgs;
|
||||
HypotheticalGameState::TownModel * whichTown;
|
||||
int which; //which hero, which building, which creature,
|
||||
|
||||
TownObjective(Type t,HypotheticalGameState::TownModel * tn,int Which,CGeniusAI * AI);
|
||||
TownObjective(const HypotheticalGameState &hgs,Type t,HypotheticalGameState::TownModel * tn,int Which,CGeniusAI * AI);
|
||||
|
||||
bool operator < (const TownObjective &other)const;
|
||||
void fulfill(CGeniusAI &,HypotheticalGameState & hgs);
|
||||
@ -148,6 +145,7 @@ private:
|
||||
void print() const;
|
||||
private:
|
||||
mutable float _value;
|
||||
mutable float _cost;
|
||||
};
|
||||
|
||||
class AIObjectivePtrCont
|
||||
@ -211,6 +209,7 @@ public:
|
||||
virtual void battleStackIsAttacked(int ID, int dmg, int killed, int IDby, bool byShooting);
|
||||
virtual BattleAction activeStack(int stackID);
|
||||
void battleResultsApplied();
|
||||
friend class Priorities;
|
||||
};
|
||||
}
|
||||
|
||||
|
416
AI/GeniusAI/neuralNetwork.cpp
Normal file
416
AI/GeniusAI/neuralNetwork.cpp
Normal file
@ -0,0 +1,416 @@
|
||||
|
||||
#include "neuralNetwork.h"
|
||||
//using namespace std;
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
float norm(void)//add desired mean, multiply to get desired SD
|
||||
{
|
||||
static float kept = 0;
|
||||
static bool in = 0;
|
||||
if(!in)
|
||||
{
|
||||
float x = (rand()+1)/float(RAND_MAX+1);
|
||||
float f = sqrtf( - 2.0f * log(x) );
|
||||
x = (rand()+1)/float(RAND_MAX+1);
|
||||
kept = f * cosf( 2.0f * M_PI * x );
|
||||
in = true;
|
||||
return f * sinf( 2.0f * M_PI * x );
|
||||
}
|
||||
else
|
||||
{
|
||||
in = false;
|
||||
return kept;
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
* Constructors
|
||||
********************************************************************/
|
||||
neuralNetwork::neuralNetwork() : nInput(0), nHidden1(0), nHidden2(0), nOutput(0)
|
||||
{
|
||||
inputNeurons = new double[1] ;
|
||||
hiddenNeurons1 = new double[1] ;
|
||||
hiddenNeurons2 = new double[1] ;
|
||||
outputNeurons = new double[1] ;
|
||||
wInputHidden = new double*[1] ;
|
||||
wInputHidden[0] = new double[1];
|
||||
wHidden2Hidden = new double*[1] ;
|
||||
wHidden2Hidden[0] = new (double[1]);
|
||||
wHiddenOutput = new double*[1] ;
|
||||
wHiddenOutput[0] = new double[1];
|
||||
}
|
||||
|
||||
neuralNetwork::neuralNetwork(const neuralNetwork& other): nInput(0), nHidden1(0), nHidden2(0), nOutput(0)
|
||||
{
|
||||
inputNeurons = new double[1] ;
|
||||
hiddenNeurons1 = new double[1] ;
|
||||
hiddenNeurons2 = new double[1] ;
|
||||
outputNeurons = new double[1] ;
|
||||
wInputHidden = new double*[1] ;
|
||||
wInputHidden[0] = new double[1];
|
||||
wHidden2Hidden = new double*[1] ;
|
||||
wHidden2Hidden[0] = new (double[1]);
|
||||
wHiddenOutput = new double*[1] ;
|
||||
wHiddenOutput[0] = new double[1];
|
||||
*this = other;
|
||||
}
|
||||
|
||||
neuralNetwork::neuralNetwork(int nI, int nH1, int nH2, int nO) : nInput(nI), nHidden1(nH1), nHidden2(nH2), nOutput(nO)
|
||||
{
|
||||
//create neuron lists
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
inputNeurons = new double[nInput + 1] ;
|
||||
for ( int i=0; i < nInput; i++ ) inputNeurons[i] = 0;
|
||||
|
||||
//create input bias neuron
|
||||
inputNeurons[nInput] = -1;
|
||||
|
||||
hiddenNeurons1 = new double[nHidden1 + 1] ;
|
||||
for ( int i=0; i < nHidden1; i++ ) hiddenNeurons1[i] = 0;
|
||||
|
||||
//create hidden bias neuron
|
||||
hiddenNeurons1[nHidden1] = -1;
|
||||
|
||||
hiddenNeurons2 = new double[nHidden2 + 1] ;
|
||||
for ( int i=0; i < nHidden2; i++ ) hiddenNeurons2[i] = 0;
|
||||
|
||||
//create hidden bias neuron
|
||||
hiddenNeurons2[nHidden2] = -1;
|
||||
|
||||
outputNeurons = new double[nOutput] ;
|
||||
for ( int i=0; i < nOutput; i++ ) outputNeurons[i] = 0;
|
||||
|
||||
//create weight lists (include bias neuron weights)
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
wInputHidden = new double*[nInput + 1] ;
|
||||
for ( int i=0; i <= nInput; i++ )
|
||||
{
|
||||
wInputHidden[i] = new double[nHidden1];
|
||||
for ( int j=0; j < nHidden1; j++ ) wInputHidden[i][j] = 0;
|
||||
}
|
||||
|
||||
wHidden2Hidden = new double*[nHidden1 + 1] ;
|
||||
for ( int i=0; i <= nHidden1; i++ )
|
||||
{
|
||||
wHidden2Hidden[i] = new (double[nHidden2]);
|
||||
for ( int j=0; j < nHidden2; j++ ) wHidden2Hidden[i][j] = 0;
|
||||
}
|
||||
|
||||
wHiddenOutput = new double*[nHidden2 + 1] ;
|
||||
for ( int i=0; i <= nHidden2; i++ )
|
||||
{
|
||||
wHiddenOutput[i] = new double[nOutput];
|
||||
for ( int j=0; j < nOutput; j++ ) wHiddenOutput[i][j] = 0;
|
||||
}
|
||||
|
||||
//initialize weights
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
initializeWeights();
|
||||
}
|
||||
|
||||
|
||||
void neuralNetwork::operator = (const neuralNetwork&cpy)//assumes same structure
|
||||
{
|
||||
if( nInput != cpy.nInput || nHidden1 != cpy.nHidden1 || nHidden2 != cpy.nHidden2 || nOutput != cpy.nOutput)
|
||||
{
|
||||
delete[] inputNeurons;
|
||||
delete[] hiddenNeurons1;
|
||||
delete[] hiddenNeurons2;
|
||||
delete[] outputNeurons;
|
||||
|
||||
//delete weight storage
|
||||
for (int i=0; i <= nInput; i++) delete[] wInputHidden[i];
|
||||
delete[] wInputHidden;
|
||||
|
||||
for (int j=0; j <= nHidden2; j++) delete[] wHiddenOutput[j];
|
||||
delete[] wHiddenOutput;
|
||||
|
||||
for (int j=0; j <= nHidden1; j++) delete[] wHidden2Hidden[j];
|
||||
delete[] wHidden2Hidden;
|
||||
|
||||
nInput = cpy.nInput;
|
||||
nHidden1 = cpy.nHidden1;
|
||||
nHidden2 = cpy.nHidden2;
|
||||
nOutput = cpy.nOutput;
|
||||
|
||||
inputNeurons = new double[nInput + 1] ;
|
||||
inputNeurons[nInput] = -1;
|
||||
|
||||
hiddenNeurons1 = new double[nHidden1 + 1] ;
|
||||
hiddenNeurons1[nHidden1] = -1;
|
||||
|
||||
hiddenNeurons2 = new double[nHidden2 + 1] ;
|
||||
hiddenNeurons2[nHidden2] = -1;
|
||||
|
||||
outputNeurons = new double[nOutput] ;
|
||||
|
||||
//create weight lists (include bias neuron weights)
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
wInputHidden = new double*[nInput + 1] ;
|
||||
for ( int i=0; i <= nInput; i++ )
|
||||
wInputHidden[i] = new double[nHidden1];
|
||||
|
||||
wHidden2Hidden = new double*[nHidden1 + 1] ;
|
||||
for ( int i=0; i <= nHidden1; i++ )
|
||||
wHidden2Hidden[i] = new (double[nHidden2]);
|
||||
|
||||
wHiddenOutput = new double*[nHidden2 + 1] ;
|
||||
for ( int i=0; i <= nHidden2; i++ )
|
||||
wHiddenOutput[i] = new double[nOutput];
|
||||
}
|
||||
|
||||
for ( int i=0; i < nInput; i++ ) inputNeurons[i] = cpy.inputNeurons[i];
|
||||
for ( int i=0; i < nHidden1; i++ ) hiddenNeurons1[i] = cpy.hiddenNeurons1[i];
|
||||
for ( int i=0; i < nHidden2; i++ ) hiddenNeurons2[i] = cpy.hiddenNeurons2[i];
|
||||
for ( int i=0; i < nOutput; i++ ) outputNeurons[i] = cpy.outputNeurons[i];
|
||||
|
||||
for ( int i=0; i <= nInput; i++ )
|
||||
for ( int j=0; j < nHidden1; j++ )
|
||||
wInputHidden[i][j] = cpy.wInputHidden[i][j];
|
||||
|
||||
for ( int i=0; i <= nHidden1; i++ )
|
||||
for ( int j=0; j < nHidden2; j++ )
|
||||
wHidden2Hidden[i][j] = cpy.wHidden2Hidden[i][j];
|
||||
|
||||
for ( int i=0; i <= nHidden2; i++ )
|
||||
for ( int j=0; j < nOutput; j++ )
|
||||
wHiddenOutput[i][j] = cpy.wHiddenOutput[i][j];
|
||||
|
||||
}
|
||||
/*******************************************************************
|
||||
* Destructor
|
||||
********************************************************************/
|
||||
neuralNetwork::~neuralNetwork()
|
||||
{
|
||||
//delete neurons
|
||||
delete[] inputNeurons;
|
||||
delete[] hiddenNeurons1;
|
||||
delete[] hiddenNeurons2;
|
||||
delete[] outputNeurons;
|
||||
|
||||
//delete weight storage
|
||||
for (int i=0; i <= nInput; i++) delete[] wInputHidden[i];
|
||||
delete[] wInputHidden;
|
||||
|
||||
for (int j=0; j <= nHidden2; j++) delete[] wHiddenOutput[j];
|
||||
delete[] wHiddenOutput;
|
||||
|
||||
for (int j=0; j <= nHidden1; j++) delete[] wHidden2Hidden[j];
|
||||
delete[] wHidden2Hidden;
|
||||
}
|
||||
|
||||
double* neuralNetwork::feedForwardPattern(double *pattern)
|
||||
{
|
||||
feedForward(pattern);
|
||||
|
||||
|
||||
return outputNeurons;
|
||||
}
|
||||
|
||||
void neuralNetwork::mate(const neuralNetwork&n1,const neuralNetwork&n2)
|
||||
{
|
||||
for(int i = 0; i <= nInput; i++)
|
||||
{
|
||||
for(int j = 0; j < nHidden1; j++)
|
||||
{
|
||||
if(rand()%2==0)
|
||||
wInputHidden[i][j] = n1.wInputHidden[i][j];
|
||||
else
|
||||
wInputHidden[i][j] = n2.wInputHidden[i][j];
|
||||
}
|
||||
}
|
||||
for(int i = 0; i <= nHidden1; i++)
|
||||
{
|
||||
for(int j = 0; j < nHidden2; j++)
|
||||
{
|
||||
if(rand()%2==0)
|
||||
wHidden2Hidden[i][j] =n1.wHidden2Hidden[i][j];
|
||||
else
|
||||
wHidden2Hidden[i][j] =n2.wHidden2Hidden[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; i <= nHidden2; i++)
|
||||
{
|
||||
for(int j = 0; j < nOutput; j++)
|
||||
{
|
||||
if(rand()%2==0)
|
||||
wHiddenOutput[i][j] =n1.wHiddenOutput[i][j];
|
||||
else
|
||||
wHiddenOutput[i][j] =n2.wHiddenOutput[i][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void neuralNetwork::tweakWeights(double howMuch)
|
||||
{
|
||||
//set range
|
||||
double rH = 1/sqrt( (double) nInput);
|
||||
double rO = 1/sqrt( (double) nHidden1);
|
||||
|
||||
for(int i = 0; i <= nInput; i++)
|
||||
{
|
||||
for(int j = 0; j < nHidden1; j++)
|
||||
{
|
||||
wInputHidden[i][j] += howMuch*norm();
|
||||
}
|
||||
}
|
||||
for(int i = 0; i <= nHidden1; i++)
|
||||
{
|
||||
for(int j = 0; j < nHidden2; j++)
|
||||
{
|
||||
wHidden2Hidden[i][j] += howMuch*norm();
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; i <= nHidden2; i++)
|
||||
{
|
||||
for(int j = 0; j < nOutput; j++)
|
||||
{
|
||||
wHiddenOutput[i][j] += howMuch* norm();
|
||||
}
|
||||
}
|
||||
//initializeWeights();
|
||||
}
|
||||
|
||||
void neuralNetwork::initializeWeights()
|
||||
{
|
||||
//set range
|
||||
double rH = 2.0/sqrt( (double) nInput);
|
||||
double rO = 2.0/sqrt( (double) nHidden1);
|
||||
|
||||
//set weights between input and hidden
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
for(int i = 0; i <= nInput; i++)
|
||||
{
|
||||
for(int j = 0; j < nHidden1; j++)
|
||||
{
|
||||
//set weights to random values
|
||||
wInputHidden[i][j] = norm()* rH;
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; i <= nHidden1; i++)
|
||||
{
|
||||
for(int j = 0; j < nHidden2; j++)
|
||||
{
|
||||
//set weights to random values
|
||||
wHidden2Hidden[i][j] = norm()* rO;
|
||||
}
|
||||
}
|
||||
|
||||
//set weights between hidden and output
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
for(int i = 0; i <= nHidden2; i++)
|
||||
{
|
||||
for(int j = 0; j < nOutput; j++)
|
||||
{
|
||||
//set weights to random values
|
||||
wHiddenOutput[i][j] = norm()* rO;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*******************************************************************
|
||||
* Activation Function
|
||||
********************************************************************/
|
||||
inline double neuralNetwork::activationFunction( double x )
|
||||
{
|
||||
//sigmoid function
|
||||
return 1/(1+exp(-x));
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
* Feed Forward Operation
|
||||
********************************************************************/
|
||||
void neuralNetwork::feedForward(double* pattern)
|
||||
{
|
||||
//set input neurons to input values
|
||||
for(int i = 0; i < nInput; i++) inputNeurons[i] = pattern[i];
|
||||
|
||||
//Calculate Hidden Layer values - include bias neuron
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
for(int j=0; j < nHidden1; j++)
|
||||
{
|
||||
//clear value
|
||||
hiddenNeurons1[j] = 0;
|
||||
|
||||
//get weighted sum of pattern and bias neuron
|
||||
for( int i=0; i <= nInput; i++ ) hiddenNeurons1[j] += inputNeurons[i] * wInputHidden[i][j];
|
||||
|
||||
//set to result of sigmoid
|
||||
hiddenNeurons1[j] = activationFunction( hiddenNeurons1[j] );
|
||||
}
|
||||
|
||||
for(int j=0; j < nHidden2; j++)
|
||||
{
|
||||
//clear value
|
||||
hiddenNeurons2[j] = 0;
|
||||
|
||||
//get weighted sum of pattern and bias neuron
|
||||
for( int i=0; i <= nHidden1; i++ ) hiddenNeurons2[j] += hiddenNeurons1[i] * wHidden2Hidden[i][j];
|
||||
|
||||
//set to result of sigmoid
|
||||
hiddenNeurons2[j] = activationFunction( hiddenNeurons2[j] );
|
||||
}
|
||||
|
||||
//Calculating Output Layer values - include bias neuron
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
for(int k=0; k < nOutput; k++)
|
||||
{
|
||||
//clear value
|
||||
outputNeurons[k] = 0;
|
||||
|
||||
//get weighted sum of pattern and bias neuron
|
||||
for( int j=0; j <= nHidden2; j++ ) outputNeurons[k] += hiddenNeurons2[j] * wHiddenOutput[j][k];
|
||||
|
||||
//set to result of sigmoid
|
||||
//outputNeurons[k] = activationFunction( outputNeurons[k] );
|
||||
}
|
||||
}
|
||||
|
||||
void neuralNetwork::backpropigate(double* pattern, double OLR, double H2LR, double H1LR )
|
||||
{
|
||||
//inputError = new double[nInput + 1] ;
|
||||
double * hiddenError1 = new double[nHidden1 + 1] ;
|
||||
double * hiddenError2 = new double[nHidden2 + 1] ;
|
||||
double * outputError = new double[nOutput] ;
|
||||
memset(hiddenError1,0,sizeof(double)*nHidden1);
|
||||
memset(hiddenError2,0,sizeof(double)*nHidden2);
|
||||
|
||||
for(int i = 0; i < nOutput; i++)
|
||||
{
|
||||
outputError[i] = (pattern[i]-outputNeurons[i]);//*(outputNeurons[i]*(1-outputNeurons[i]));
|
||||
for(int ii = 0; ii <= nHidden2;ii++)
|
||||
hiddenError2[ii]+=outputError[i]*wHiddenOutput[ii][i];
|
||||
for(int ii = 0; ii <= nHidden2;ii++)
|
||||
wHiddenOutput[ii][i]+=OLR*hiddenNeurons2[ii]*outputError[i];
|
||||
|
||||
}
|
||||
|
||||
for(int i = 0; i < nHidden2; i++)
|
||||
{
|
||||
hiddenError2[i] *= (hiddenNeurons2[i]*(1-hiddenNeurons2[i]));
|
||||
for(int ii = 0; ii <= nHidden1;ii++)
|
||||
hiddenError1[ii]+=hiddenError2[i]*wHidden2Hidden[ii][i];
|
||||
for(int ii = 0; ii <= nHidden1;ii++)
|
||||
wHidden2Hidden[ii][i]+=H2LR*hiddenNeurons1[ii]*hiddenError2[i];
|
||||
|
||||
}
|
||||
|
||||
for(int i = 0; i < nHidden1; i++)
|
||||
{
|
||||
hiddenError1[i] *= (hiddenNeurons1[i]*(1-hiddenNeurons1[i]));
|
||||
|
||||
for(int ii = 0; ii <= nInput;ii++)
|
||||
wInputHidden[ii][i]+=H1LR*inputNeurons[ii]*hiddenError1[i];
|
||||
|
||||
}
|
||||
|
||||
|
||||
delete [] hiddenError1;
|
||||
delete [] hiddenError2;
|
||||
delete [] outputError;
|
||||
}
|
67
AI/GeniusAI/neuralNetwork.h
Normal file
67
AI/GeniusAI/neuralNetwork.h
Normal file
@ -0,0 +1,67 @@
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* addapted by Trevor Standley for use as a function approximator
|
||||
* Addapted from:
|
||||
* Basic Feed Forward Neural Network Class
|
||||
* ------------------------------------------------------------------
|
||||
* Bobby Anguelov - takinginitiative.wordpress.com (2008)
|
||||
* MSN & email: banguelov@cs.up.ac.za
|
||||
********************************************************************/
|
||||
#ifndef NEURAL_NETWORK_H
|
||||
#define NEURAL_NETWORK_H
|
||||
//standard includes
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
|
||||
|
||||
class neuralNetwork
|
||||
{
|
||||
private:
|
||||
|
||||
//number of neurons
|
||||
int nInput, nHidden1, nHidden2, nOutput;
|
||||
|
||||
//neurons
|
||||
double* inputNeurons;
|
||||
double* hiddenNeurons1;
|
||||
double* hiddenNeurons2;
|
||||
double* outputNeurons;
|
||||
|
||||
//weights
|
||||
double** wInputHidden;
|
||||
double** wHidden2Hidden;
|
||||
double** wHiddenOutput;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
//constructor & destructor
|
||||
neuralNetwork(int numInput, int numHidden1, int numHidden2, int numOutput);
|
||||
neuralNetwork(const neuralNetwork&);
|
||||
neuralNetwork();
|
||||
void operator = (const neuralNetwork&);
|
||||
~neuralNetwork();
|
||||
|
||||
//weight operations
|
||||
double* feedForwardPattern( double* pattern );
|
||||
void backpropigate(double* pattern, double OLR, double H2LR, double H1LR );
|
||||
|
||||
void tweakWeights(double howMuch);
|
||||
void mate(const neuralNetwork&n1,const neuralNetwork&n2);
|
||||
|
||||
|
||||
|
||||
private:
|
||||
void initializeWeights();
|
||||
inline double activationFunction( double x );
|
||||
void feedForward( double* pattern );
|
||||
|
||||
};
|
||||
|
||||
std::istream & operator >> (std::istream &, neuralNetwork & ann);
|
||||
std::ostream & operator << (std::ostream &, const neuralNetwork & ann);
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user