⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 genotype.cpp

📁 游戏开发人工智能技术 很好的一本书 讲解游戏中的人工智能技术 希望大家喜欢 ps 英文原版
💻 CPP
📖 第 1 页 / 共 2 页
字号:
#include "genotype.h"


//------------------------------------------------------------------------
//
//  default ctor
//------------------------------------------------------------------------
CGenome::CGenome():m_pPhenotype(NULL),
                   m_GenomeID(0),
                   m_dFitness(0),
                   m_dAdjustedFitness(0),
                   m_iNumInputs(0),
                   m_iNumOutPuts(0),
                   m_dAmountToSpawn(0)
{}


//-----------------------------constructor--------------------------------
//	this constructor creates a minimal genome where there are output +
//	input neurons and each input neuron is connected to each output neuron.
//------------------------------------------------------------------------
CGenome::CGenome(int id, int inputs, int outputs):m_pPhenotype(NULL),
                                                  m_GenomeID(id),
                                                  m_dFitness(0),
                                                  m_dAdjustedFitness(0),
                                                  m_iNumInputs(inputs),
                                                  m_iNumOutPuts(outputs),
                                                  m_dAmountToSpawn(0),
                                                  m_iSpecies(0)
												  
{
  //create the input neurons
  double InputRowSlice = 1/(double)(inputs+2);

	for (int i=0; i<inputs; i++)
	{
		m_vecNeurons.push_back(SNeuronGene(input, i, 0, (i+2)*InputRowSlice));
	}

  //create the bias
  m_vecNeurons.push_back(SNeuronGene(bias, inputs, 0, InputRowSlice));

	//create the output neurons
  double OutputRowSlice = 1/(double)(outputs+1);

	for (i=0; i<outputs; i++)
	{
		m_vecNeurons.push_back(SNeuronGene(output, i+inputs+1, 1, (i+1)*OutputRowSlice));
	}

	//create the link genes, connect each input neuron to each output neuron and 
	//assign a random weight -1 < w < 1
	for (i=0; i<inputs+1; i++)
	{
		for (int j=0; j<outputs; j++)
		{
			m_vecLinks.push_back(SLinkGene(m_vecNeurons[i].iID,
                                         m_vecNeurons[inputs+j+1].iID,
                                         true,
                                         inputs+outputs+1+NumGenes(),
                                         RandomClamped()));
		}
	}
 
}

//------------------------------------------------------------------------
//
//  this constructor creates a genome from a vector of SLinkGenes, a 
//  vector of SNeuronGenes and an ID number.
//------------------------------------------------------------------------
CGenome::CGenome(int                 id,
                 vector<SNeuronGene> neurons,
                 vector<SLinkGene>   genes,
                 int                 inputs,
                 int                 outputs):m_GenomeID(id),
                                                  m_pPhenotype(NULL),
                                                  m_vecLinks(genes),
                                                  m_vecNeurons(neurons),
                                                  m_dAmountToSpawn(0),
                                                  m_dFitness(0),
                                                  m_dAdjustedFitness(0),
                                                  m_iNumInputs(inputs),
                                                  m_iNumOutPuts(outputs)
                                           
{}

//-------------------------------dtor-----------------------------------------------------
//
//----------------------------------------------------------------------------------------
CGenome::~CGenome()
{  
  if (m_pPhenotype)
  {
		delete m_pPhenotype;

    m_pPhenotype = NULL;
  }
}

//---------------------------------copy ctor---------------------------------------------
//
//---------------------------------------------------------------------------------------
CGenome::CGenome(const CGenome& g)
{
    m_GenomeID   = g.m_GenomeID;
    m_vecNeurons   = g.m_vecNeurons;
    m_vecLinks   = g.m_vecLinks;
    m_pPhenotype = NULL;              //no need to perform a deep copy
    m_dFitness   = g.m_dFitness;
    m_dAdjustedFitness = g.m_dAdjustedFitness;
    m_iNumInputs  = g.m_iNumInputs;
    m_iNumOutPuts = g.m_iNumOutPuts;
    m_dAmountToSpawn = g.m_dAmountToSpawn;
}

//---------------------------------assignment operator-----------------------------------
//
//----------------------------------------------------------------------------------------
CGenome& CGenome::operator =(const CGenome& g)
{
    //self assignment guard
	  if (this != &g)
	  {
      m_GenomeID         = g.m_GenomeID;
      m_vecNeurons         = g.m_vecNeurons;
      m_vecLinks         = g.m_vecLinks;
      m_pPhenotype       = NULL;        //no need to perform a deep copy
      m_dFitness         = g.m_dFitness;
      m_dAdjustedFitness = g.m_dAdjustedFitness;
      m_iNumInputs        = g.m_iNumInputs;
      m_iNumOutPuts       = g.m_iNumOutPuts;
      m_dAmountToSpawn   = g.m_dAmountToSpawn;
    }

    return *this;
}

//-------------------------------CreatePhenotype--------------------------
//
//	Creates a neural network based upon the information in the genome.
//	Returns a pointer to the newly created ANN
//------------------------------------------------------------------------
CNeuralNet* CGenome::CreatePhenotype(int depth)
{
  //first make sure there is no existing phenotype for this genome
  DeletePhenotype();
	
  //this will hold all the neurons required for the phenotype
  vector<SNeuron*>  vecNeurons;

  //first, create all the required neurons
  for (int i=0; i<m_vecNeurons.size(); i++)
  {
    SNeuron* pNeuron = new SNeuron(m_vecNeurons[i].NeuronType,
                                   m_vecNeurons[i].iID,
                                   m_vecNeurons[i].dSplitY,
                                   m_vecNeurons[i].dSplitX,
                                   m_vecNeurons[i].dActivationResponse);
    
    vecNeurons.push_back(pNeuron);
  }
	
  //now to create the links. 
  for (int cGene=0; cGene<m_vecLinks.size(); ++cGene)
  {
    //make sure the link gene is enabled before the connection is created
    if (m_vecLinks[cGene].bEnabled)
    {
      //get the pointers to the relevant neurons
      int element         = GetElementPos(m_vecLinks[cGene].FromNeuron);
      SNeuron* FromNeuron = vecNeurons[element];

      element           = GetElementPos(m_vecLinks[cGene].ToNeuron);
      SNeuron* ToNeuron = vecNeurons[element];

      //create a link between those two neurons and assign the weight stored
      //in the gene
      SLink tmpLink(m_vecLinks[cGene].dWeight,
                    FromNeuron,
                    ToNeuron,
                    m_vecLinks[cGene].bRecurrent);
			
      //add new links to neuron
      FromNeuron->vecLinksOut.push_back(tmpLink);
      ToNeuron->vecLinksIn.push_back(tmpLink);
    }
  }

  //now the neurons contain all the connectivity information, a neural
  //network may be created from them.
  m_pPhenotype = new CNeuralNet(vecNeurons, depth);
	
  return m_pPhenotype;
}

//--------------------------- DeletePhenotype ----------------------------
//
//------------------------------------------------------------------------
void CGenome::DeletePhenotype()
{
  if (m_pPhenotype)
  {
    delete m_pPhenotype;
  }

  m_pPhenotype = NULL;
}

//---------------------------- GetElementPos -----------------------------
//
//	given a neuron ID this little function just finds its position in 
//  m_vecNeurons
//------------------------------------------------------------------------
int CGenome::GetElementPos(int neuron_id)
{  
  for (int i=0; i<m_vecNeurons.size(); i++)
	{
		if (m_vecNeurons[i].iID == neuron_id)
    {
      return i;
    }
	}

  MessageBox(NULL, "Error in CGenome::GetElementPos", "Problem!", MB_OK);

	return -1;
}

//------------------------------DuplicateLink-----------------------------
//
// returns true if the link is already part of the genome
//------------------------------------------------------------------------
bool CGenome::DuplicateLink(int NeuronIn, int NeuronOut)
{
	for (int cGene = 0; cGene < m_vecLinks.size(); ++cGene)
	{
		if ((m_vecLinks[cGene].FromNeuron == NeuronIn) && 
        (m_vecLinks[cGene].ToNeuron == NeuronOut))
		{
			//we already have this link
			return true;
		}
	}

	return false;
}

//--------------------------------AddLink---------------------------------
//
// create a new link with the probability of CParams::dChanceAddLink
//------------------------------------------------------------------------
void CGenome::AddLink(double       MutationRate,
                      double       ChanceOfLooped,
                      CInnovation  &innovation,
                      int          NumTrysToFindLoop,
                      int          NumTrysToAddLink)
{
  //just return dependent on the mutation rate
  if (RandFloat() > MutationRate) return;

  //define holders for the two neurons to be linked. If we have find two 
  //valid neurons to link these values will become >= 0.
  int ID_neuron1 = -1;
  int ID_neuron2 = -1;

  //flag set if a recurrent link is selected (looped or normal)
  bool bRecurrent = false;

  //first test to see if an attempt shpould be made to create a 
  //link that loops back into the same neuron
  if (RandFloat() < ChanceOfLooped)
  {
    //YES: try NumTrysToFindLoop times to find a neuron that is not an
    //input or bias neuron and that does not already have a loopback
    //connection
    while(NumTrysToFindLoop--)
    {      
      //grab a random neuron
      int NeuronPos = RandInt(m_iNumInputs+1, m_vecNeurons.size()-1);

      //check to make sure the neuron does not already have a loopback 
      //link and that it is not an input or bias neuron
      if (!m_vecNeurons[NeuronPos].bRecurrent && 
         (m_vecNeurons[NeuronPos].NeuronType != bias) && 
         (m_vecNeurons[NeuronPos].NeuronType != input))
      {
        ID_neuron1 = ID_neuron2 = m_vecNeurons[NeuronPos].iID;

        m_vecNeurons[NeuronPos].bRecurrent = true;

        bRecurrent = true;

        NumTrysToFindLoop = 0;
      }
    }
  }

  else
  {		
    //No: try to find two unlinked neurons. Make NumTrysToAddLink
    //attempts
    while(NumTrysToAddLink--)
    {
      //choose two neurons, the second must not be an input or a bias
      ID_neuron1 = m_vecNeurons[RandInt(0, m_vecNeurons.size()-1)].iID;
      
      ID_neuron2 =
      m_vecNeurons[RandInt(m_iNumInputs+1, m_vecNeurons.size()-1)].iID;

      if (ID_neuron2 == 2)
      {
        continue;
      }

      //make sure these two are not already linked and that they are
      //not the same neuron
      if ( !( DuplicateLink(ID_neuron1, ID_neuron2) ||
              (ID_neuron1 == ID_neuron2)))
      {
        NumTrysToAddLink = 0;
      }

      else
      {
        ID_neuron1 = -1;
        ID_neuron2 = -1;
      }
    }
  }

  //return if unsuccessful in finding a link
  if ( (ID_neuron1 < 0) || (ID_neuron2 < 0) )
  {
    return;
  }
  
  //check to see if we have already created this innovation
  int id = innovation.CheckInnovation(ID_neuron1, ID_neuron2, new_link);

  //is this link recurrent?
  if (m_vecNeurons[GetElementPos(ID_neuron1)].dSplitY > 
      m_vecNeurons[GetElementPos(ID_neuron2)].dSplitY)
  {
    bRecurrent = true;
  }

  if ( id < 0)
  {
    //we need to create a new innovation
    innovation.CreateNewInnovation(ID_neuron1, ID_neuron2, new_link);

    //then create the new gene
    int id = innovation.NextNumber() - 1;

    SLinkGene NewGene(ID_neuron1,
                          ID_neuron2,
                          true,
                          id,
                          RandomClamped(),
                          bRecurrent);
		
    m_vecLinks.push_back(NewGene);
  }

  else
  {
    //the innovation has already been created so all we need to
    //do is create the new gene using the existing innovation ID
    SLinkGene NewGene(ID_neuron1,
                          ID_neuron2,
                          true,
                          id,
                          RandomClamped(),
                          bRecurrent);
	
    m_vecLinks.push_back(NewGene);
  }

  return;
}

//---------------------------------AddNeuron------------------------------
//
//	this function adds a neuron to the genotype by examining the network, 
//	splitting one of the links and inserting the new neuron.
//------------------------------------------------------------------------
void CGenome::AddNeuron(double       MutationRate,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -