📄 gpexampledoc.cpp
字号:
//GPExample
//Copyright John Manslow
//29/09/2001
// GPExampleDoc.cpp : implementation of the CGPExampleDoc class
//
#include "stdafx.h"
#include "GPExample.h"
#include "GPExampleDoc.h"
#include "fstream.h"
#include "math.h"
#include "CWorld.h"
#include "CGP.h"
#include "CGPNode.h"
#include "CGPANDNode.h"
#include "CGPIfGreaterThanZeroNode.h"
#include "CGPIsFoodNode.h"
#include "CGPIsPoisonNode.h"
#include "CGPIsWallNode.h"
#include "CGPMoveForwardNode.h"
#include "CGPNOTNode.h"
#include "CGPORNode.h"
#include "CGPRandomNumberNode.h"
#include "CGPTurnLeftNode.h"
#include "CGPTurnRightNode.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
//List of prototype GP functions/node tpyes
extern unsigned long ulNumberOfPrototypes;
extern CGPNode **pPrototypeList;
//Pointer toalog file - useful for debugging
ofstream *pLogFile;
/////////////////////////////////////////////////////////////////////////////
// CGPExampleDoc
IMPLEMENT_DYNCREATE(CGPExampleDoc, CDocument)
BEGIN_MESSAGE_MAP(CGPExampleDoc, CDocument)
//{{AFX_MSG_MAP(CGPExampleDoc)
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
//Pointers to the view so we can draw to its window
class CGPExampleView;
extern CGPExampleView *pView;
//The environment in which the agent will be evaluated
CWorld *pWorld;
//Pointer to the genetic programming class
CGP *pGP;
//Indicates which way the agent is facing 0-4 = E N W S
int nFacing;
long dx,dy;
//The "health" of the agent, i.e. its performance
double dHealth=0.0;
//The number of fitness evaluations
unsigned long ulIteration=0;
//The number of evaluations of the current program
unsigned long ulEvaluationIteration=0;
//The number of food and poison items eaten by the current program
unsigned long ulFoodEaten=0;
unsigned long ulPoisonEaten=0;
//Whether we're running in slow motion (and hance watching the behaviour of the best program discovered
//thus far
int nSlowMotion=0;
//Pointer to the top node of the program
CGPNode *pdChromosome;
/////////////////////////////////////////////////////////////////////////////
// CGPExampleDoc construction/destruction
CGPExampleDoc::CGPExampleDoc()
{
unsigned long i;
//Seed the random number generator
srand(unsigned(time(NULL)));
//Creates a log file that records progress - useful for debugging and comparing debug and release versions
char pString[10000];
#ifdef _DEBUG
pLogFile=new ofstream("c:\\DebugGPLog.txt");
#else
pLogFile=new ofstream("c:\\ReleaseGPLog.txt");
#endif
_strtime(pString);
*pLogFile<<"Starting at: ";
*pLogFile<<pString;
*pLogFile<<"\n";
//This section of code bubble sorts the prorotypes according to their type IDs. This is only necessary in order
//to compare the progress of debug and release versions. Without the sort, direct comparisons can't be made
//because the prortypes register themselves in a different order
int nSwaps;
do
{
nSwaps=0;
for(i=0;i<ulNumberOfPrototypes-1;i++)
{
if(pPrototypeList[i]->nType>pPrototypeList[i+1]->nType)
{
CGPNode *pBackup=pPrototypeList[i];
pPrototypeList[i]=pPrototypeList[i+1];
pPrototypeList[i+1]=pBackup;
nSwaps=1;
}
}
}
while(nSwaps);
//Create the genetic programming class
pGP=new CGP(100);
//Create the world
pWorld=new CWorld(50,50);
}
CGPExampleDoc::~CGPExampleDoc()
{
//Close the log file and deallocate all the memory
pLogFile->close();
delete pLogFile;
delete pGP;
delete pWorld;
delete []pPrototypeList;
}
void TurnLeft(void)
{
//Rotates to the left
nFacing--;
if(nFacing<0)
{
nFacing=3;
}
}
void TurnRight(void)
{
//Rotates to the right
nFacing++;
if(nFacing>3)
{
nFacing=0;
}
}
int nLookForward(void)
{
long lx,ly;
//Set displacements into the world array according the direction we're facing
if(nFacing==0)
{
dx=1;
dy=0;
}
if(nFacing==1)
{
dx=0;
dy=-1;
}
if(nFacing==2)
{
dx=-1;
dy=0;
}
if(nFacing==3)
{
dx=0;
dy=1;
}
//Convert the displacements into indices into the world array
lx=pWorld->ulCharacterLocationX+dx;
ly=pWorld->ulCharacterLocationY+dy;
//If we're looking beyond the edge of the world, return "wall"
if(lx<1 || ly<1 || lx>=long(pWorld->ulWorldSizeX) || ly>=long(pWorld->ulWorldSizeY))
{
return 2;
}
//Otherwise return the contents of the world array
return pWorld->ppnWorld[lx][ly];
}
int nLookLeft(void)
{
int ReturnValue;
//We look left by tunring left, looking and turning back
TurnLeft();
ReturnValue=nLookForward();
TurnRight();
return ReturnValue;
}
int nLookRight(void)
{
int ReturnValue;
//We look right by tunring right, looking and turning back;
TurnRight();
ReturnValue=nLookForward();
TurnLeft();
return ReturnValue;
}
void MoveForward(void)
{
double dScale=10.0*4.0/5.0;
//Create a drawing surface
CClientDC *pDC=new CClientDC((CView*)pView);
//If we're running in slow motion, its so that we can see the motion of the agent - so we bettwer display it.
//Since the agent is about to move, we better remove it from the display
if(nSlowMotion)
{
pDC->SelectStockObject(WHITE_PEN);
pDC->SelectStockObject(WHITE_BRUSH);
pDC->Rectangle(
int(pWorld->ulCharacterLocationX*dScale),
int(pWorld->ulCharacterLocationY*dScale),
int((pWorld->ulCharacterLocationX+1)*dScale+1),
int((pWorld->ulCharacterLocationY+1)*dScale+1));
}
//Work out which way we're going to move from which way we're facing
if(nFacing==0)
{
dx=1;
dy=0;
}
if(nFacing==1)
{
dx=0;
dy=-1;
};
if(nFacing==2)
{
dx=-1;
dy=0;
}
if(nFacing==3)
{
dx=0;
dy=1;
}
//See whether we've eaten any food, poison, etc. and update the health measure accordingly
if(pWorld->ppnWorld[pWorld->ulCharacterLocationX+dx][pWorld->ulCharacterLocationY+dy]==1)
{
ulFoodEaten++;
dHealth++;
}
if(pWorld->ppnWorld[pWorld->ulCharacterLocationX+dx][pWorld->ulCharacterLocationY+dy]==3)
{
ulPoisonEaten++;
dHealth--;
}
//If we can actually move forward (i.e. there's not a wall in front of us) do so
if(pWorld->ppnWorld[pWorld->ulCharacterLocationX+dx][pWorld->ulCharacterLocationY+dy]!=2)
{
pWorld->ppnWorld[pWorld->ulCharacterLocationX][pWorld->ulCharacterLocationY]=0;
pWorld->ulCharacterLocationX+=dx;
pWorld->ulCharacterLocationY+=dy;
}
//If we're running in slow motion, draw the agent in its new position
if(nSlowMotion)
{
pDC->SelectStockObject(BLACK_PEN);
pDC->SelectStockObject(BLACK_BRUSH);
pDC->Rectangle(
int(pWorld->ulCharacterLocationX*dScale),
int(pWorld->ulCharacterLocationY*dScale),
int((pWorld->ulCharacterLocationX+1)*dScale+1),
int((pWorld->ulCharacterLocationY+1)*dScale+1));
//And wait a while before continuing
unsigned long ulDelay=0;
do
{
ulDelay++;
}
while(ulDelay<1e+6);
}
delete pDC;
//Update a counter of the number of steps used so far to evaluate the fitness of this individual
ulEvaluationIteration++;
}
void Evaluate(void)
{
unsigned long ulDelay=0;
SYSTEMTIME StartTime,CurrentTime;
GetSystemTime(&StartTime);
unsigned long ulCurrentTime;
//Create a drawing surface
CClientDC *pDC=new CClientDC((CView*)pView);
//If we've finished evaluating the last chromosome and need a new one
if(ulEvaluationIteration==0)
{
//Reset the record of the amount of food and poison eaten
ulFoodEaten=0;
ulPoisonEaten=0;
//Clear the window
pDC->SelectStockObject(WHITE_PEN);
pDC->Rectangle(500,0,2000,2000);
//Keep track of the number of programs evalutaed so far
ulIteration++;
//Reste the health (fitness/performance) estimate
dHealth=0.0;
//Reset the world
pWorld->Initialise();
//If not we're runnning in slow motion (and hence not watching the best performing program)
if(!nSlowMotion)
{
//Get a new program from the GP class so that we can evaluate its performance
pdChromosome=pGP->pGetChromosomeForEvaluation();
}
else
{
//Otherwise get a copy of the best program found so far so that we can watch it perform
pdChromosome=pGP->pGetBestChromosome();
//Draw the world
pWorld->Draw(pDC);
}
}
char pString[1000];
unsigned long ulStartTime=
StartTime.wMilliseconds
+1000*StartTime.wSecond
+60*StartTime.wMinute
+3600*StartTime.wHour
+24*3600*StartTime.wDay;
do
{
//Run the program
pdChromosome->dEvaluate();
//Keep track of the number of times its been executed
ulEvaluationIteration++;
//Put some info on the screen so that we can monitor the progress
sprintf(pString,"Food eaten: %u",ulFoodEaten);
pDC->TextOut(550,20,pString);
sprintf(pString,"Poison eaten: %u",ulPoisonEaten);
pDC->TextOut(550,40,pString);
sprintf(pString,"Highest fitness: %+6.2lf",pGP->dGetBestPerformance());
pDC->TextOut(550,60,pString);
GetSystemTime(&CurrentTime);
ulCurrentTime=
CurrentTime.wMilliseconds
+1000*CurrentTime.wSecond
+60*CurrentTime.wMinute
+3600*CurrentTime.wHour
+24*3600*CurrentTime.wDay;
}
//Keep going for either 50ms or until we've finished. See additional comments for this line in
//CGAPBILExampleDoc.cpp
while(ulCurrentTime-ulStartTime<1000 && ulEvaluationIteration<=5000);
//If we have actually finished
if(ulEvaluationIteration>5000)
{
//Reset the counter of the number of step made in evaluating the current program
ulEvaluationIteration=0;
//Reduce the estmiate of the program's health (i.e. performance) by subtracting some function of the number
//of nodes (instricutions) in the program. Typcially, the lengths of the programs produced by GP tend to
//increase in length with time and usually contain large redundant sections. This makes the programs inefficient
//and impossible to understand. The penalty provided by the line below helps to encourage the emergence of
//shorter programs
dHealth-=0.1*pow(pdChromosome->ulGetNumberOfNodesInSubtree(0),1.0);
//If we're not just watching the best program perform
if(!nSlowMotion)
{
//Set the health (performance) of the program that was just evaluated
pGP->SetFitness(dHealth);
//If we've reached out performance target, stop evolving and just watch the best performer
if(pGP->dGetBestPerformance()>250)
{
nSlowMotion=1;
}
}
}
//Delete the drawing surface
delete pDC;
}
BOOL CGPExampleDoc::OnNewDocument()
{
if (!CDocument::OnNewDocument())
return FALSE;
// TODO: add reinitialization code here
// (SDI documents will reuse this document)
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CGPExampleDoc serialization
void CGPExampleDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
// TODO: add storing code here
}
else
{
// TODO: add loading code here
}
}
/////////////////////////////////////////////////////////////////////////////
// CGPExampleDoc diagnostics
#ifdef _DEBUG
void CGPExampleDoc::AssertValid() const
{
CDocument::AssertValid();
}
void CGPExampleDoc::Dump(CDumpContext& dc) const
{
CDocument::Dump(dc);
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CGPExampleDoc commands
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -