home *** CD-ROM | disk | FTP | other *** search
/ AI Game Programming Wisdom / AIGameProgrammingWisdom.iso / SourceCode / 11 Learning / 01 Manslow / GPExample / GPExampleDoc.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-10  |  11.5 KB  |  470 lines

  1. //GPExample
  2. //Copyright John Manslow
  3. //29/09/2001
  4.  
  5. // GPExampleDoc.cpp : implementation of the CGPExampleDoc class
  6. //
  7.  
  8. #include "stdafx.h"
  9. #include "GPExample.h"
  10.  
  11. #include "GPExampleDoc.h"
  12. #include "fstream.h"
  13. #include "math.h"
  14.  
  15. #include "CWorld.h"
  16. #include "CGP.h"
  17. #include "CGPNode.h"
  18. #include "CGPANDNode.h"
  19. #include "CGPIfGreaterThanZeroNode.h"
  20. #include "CGPIsFoodNode.h"
  21. #include "CGPIsPoisonNode.h"
  22. #include "CGPIsWallNode.h"
  23. #include "CGPMoveForwardNode.h"
  24. #include "CGPNOTNode.h"
  25. #include "CGPORNode.h"
  26. #include "CGPRandomNumberNode.h"
  27. #include "CGPTurnLeftNode.h"
  28. #include "CGPTurnRightNode.h"
  29.  
  30. #ifdef _DEBUG
  31. #define new DEBUG_NEW
  32. #undef THIS_FILE
  33. static char THIS_FILE[] = __FILE__;
  34. #endif
  35.  
  36. //List of prototype GP functions/node tpyes
  37. extern unsigned long ulNumberOfPrototypes;
  38. extern CGPNode **pPrototypeList;
  39.  
  40. //Pointer toalog file - useful for debugging
  41. ofstream *pLogFile;
  42.  
  43. /////////////////////////////////////////////////////////////////////////////
  44. // CGPExampleDoc
  45.  
  46. IMPLEMENT_DYNCREATE(CGPExampleDoc, CDocument)
  47.  
  48. BEGIN_MESSAGE_MAP(CGPExampleDoc, CDocument)
  49.     //{{AFX_MSG_MAP(CGPExampleDoc)
  50.         // NOTE - the ClassWizard will add and remove mapping macros here.
  51.         //    DO NOT EDIT what you see in these blocks of generated code!
  52.     //}}AFX_MSG_MAP
  53. END_MESSAGE_MAP()
  54.  
  55. //Pointers to the view so we can draw to its window
  56. class CGPExampleView;
  57. extern CGPExampleView *pView;
  58.  
  59. //The environment in which the agent will be evaluated
  60. CWorld *pWorld;
  61.  
  62. //Pointer to the genetic programming class
  63. CGP *pGP;
  64.  
  65. //Indicates which way the agent is facing 0-4 = E N W S
  66. int nFacing;
  67. long dx,dy;
  68.  
  69. //The "health" of the agent, i.e. its performance
  70. double dHealth=0.0;
  71.  
  72. //The number of fitness evaluations
  73. unsigned long ulIteration=0;
  74.  
  75. //The number of evaluations of the current program
  76. unsigned long ulEvaluationIteration=0;
  77.  
  78. //The number of food and poison items eaten by the current program
  79. unsigned long ulFoodEaten=0;
  80. unsigned long ulPoisonEaten=0;
  81.  
  82. //Whether we're running in slow motion (and hance watching the behaviour of the best program discovered
  83. //thus far
  84. int nSlowMotion=0;
  85.  
  86. //Pointer to the top node of the program
  87. CGPNode *pdChromosome;
  88.  
  89. /////////////////////////////////////////////////////////////////////////////
  90. // CGPExampleDoc construction/destruction
  91.  
  92. CGPExampleDoc::CGPExampleDoc()
  93. {
  94.     unsigned long i;
  95.  
  96.     //Seed the random number generator
  97.     srand(unsigned(time(NULL)));
  98.  
  99.     //Creates a log file that records progress - useful for debugging and comparing debug and release versions
  100.     char pString[10000];
  101. #ifdef _DEBUG
  102.     pLogFile=new ofstream("c:\\DebugGPLog.txt");
  103. #else
  104.     pLogFile=new ofstream("c:\\ReleaseGPLog.txt");
  105. #endif
  106.     _strtime(pString);
  107.     *pLogFile<<"Starting at: ";
  108.     *pLogFile<<pString;
  109.     *pLogFile<<"\n";
  110.  
  111.     //This section of code bubble sorts the prorotypes according to their type IDs. This is only necessary in order
  112.     //to compare the progress of debug and release versions. Without the sort, direct comparisons can't be made 
  113.     //because the prortypes register themselves in a different order
  114.     int nSwaps;
  115.     do
  116.     {
  117.         nSwaps=0;
  118.         for(i=0;i<ulNumberOfPrototypes-1;i++)
  119.         {
  120.             if(pPrototypeList[i]->nType>pPrototypeList[i+1]->nType)
  121.             {
  122.                 CGPNode *pBackup=pPrototypeList[i];
  123.                 pPrototypeList[i]=pPrototypeList[i+1];
  124.                 pPrototypeList[i+1]=pBackup;
  125.                 nSwaps=1;
  126.             }
  127.         }
  128.     }
  129.     while(nSwaps);
  130.  
  131.     //Create the genetic programming class
  132.     pGP=new CGP(100);
  133.  
  134.     //Create the world
  135.     pWorld=new CWorld(50,50);
  136. }
  137.  
  138. CGPExampleDoc::~CGPExampleDoc()
  139. {
  140.     //Close the log file and deallocate all the memory
  141.     pLogFile->close();
  142.     delete pLogFile;
  143.     delete pGP;
  144.     delete pWorld;
  145.     delete []pPrototypeList;
  146. }
  147.  
  148. void TurnLeft(void)
  149. {
  150.     //Rotates to the left
  151.     nFacing--;
  152.     if(nFacing<0)
  153.     {
  154.         nFacing=3;
  155.     }    
  156. }
  157.  
  158. void TurnRight(void)
  159. {
  160.     //Rotates to the right
  161.     nFacing++;
  162.     if(nFacing>3)
  163.     {
  164.         nFacing=0;
  165.     }    
  166. }
  167.  
  168. int nLookForward(void)
  169. {
  170.     long lx,ly;
  171.  
  172.     //Set displacements into the world array according the direction we're facing
  173.     if(nFacing==0)
  174.     {
  175.         dx=1;
  176.         dy=0;
  177.     }
  178.     if(nFacing==1)
  179.     {
  180.         dx=0;
  181.         dy=-1;
  182.     }
  183.     if(nFacing==2)
  184.     {
  185.         dx=-1;
  186.         dy=0;
  187.     }
  188.     if(nFacing==3)
  189.     {
  190.         dx=0;
  191.         dy=1;
  192.     }
  193.  
  194.     //Convert the displacements into indices into the world array
  195.     lx=pWorld->ulCharacterLocationX+dx;
  196.     ly=pWorld->ulCharacterLocationY+dy;
  197.  
  198.     //If we're looking beyond the edge of the world, return "wall"
  199.     if(lx<1 || ly<1 || lx>=long(pWorld->ulWorldSizeX) || ly>=long(pWorld->ulWorldSizeY))
  200.     {
  201.         return 2;
  202.     }
  203.  
  204.     //Otherwise return the contents of the world array
  205.     return pWorld->ppnWorld[lx][ly];
  206. }
  207.  
  208. int nLookLeft(void)
  209. {
  210.     int ReturnValue;
  211.         
  212.     //We look left by tunring left, looking and turning back
  213.     TurnLeft();
  214.     ReturnValue=nLookForward();
  215.     TurnRight();
  216.     return ReturnValue;
  217. }
  218.  
  219. int nLookRight(void)
  220. {
  221.     int ReturnValue;
  222.  
  223.     //We look right by tunring right, looking and turning back;
  224.     TurnRight();
  225.     ReturnValue=nLookForward();
  226.     TurnLeft();
  227.     return ReturnValue;
  228. }
  229.  
  230. void MoveForward(void)
  231. {
  232.     double dScale=10.0*4.0/5.0;
  233.     //Create a drawing surface
  234.     CClientDC *pDC=new CClientDC((CView*)pView);
  235.  
  236.     //If we're running in slow motion, its so that we can see the motion of the agent - so we bettwer display it.
  237.     //Since the agent is about to move, we better remove it from the display
  238.     if(nSlowMotion)
  239.     {
  240.         pDC->SelectStockObject(WHITE_PEN);
  241.         pDC->SelectStockObject(WHITE_BRUSH);
  242.         pDC->Rectangle(
  243.                                     int(pWorld->ulCharacterLocationX*dScale),
  244.                                     int(pWorld->ulCharacterLocationY*dScale),
  245.                                     int((pWorld->ulCharacterLocationX+1)*dScale+1),
  246.                                     int((pWorld->ulCharacterLocationY+1)*dScale+1));
  247.     }
  248.  
  249.     //Work out which way we're going to move from which way we're facing
  250.     if(nFacing==0)
  251.     {
  252.         dx=1;
  253.         dy=0;
  254.     }
  255.     if(nFacing==1)
  256.     {
  257.         dx=0;
  258.         dy=-1;
  259.     };
  260.     if(nFacing==2)
  261.     {
  262.         dx=-1;
  263.         dy=0;
  264.     }
  265.     if(nFacing==3)
  266.     {
  267.         dx=0;
  268.         dy=1;
  269.     }
  270.  
  271.     //See whether we've eaten any food, poison, etc. and update the health measure accordingly
  272.     if(pWorld->ppnWorld[pWorld->ulCharacterLocationX+dx][pWorld->ulCharacterLocationY+dy]==1)
  273.     {
  274.         ulFoodEaten++;
  275.         dHealth++;
  276.     }
  277.     if(pWorld->ppnWorld[pWorld->ulCharacterLocationX+dx][pWorld->ulCharacterLocationY+dy]==3)
  278.     {
  279.         ulPoisonEaten++;
  280.         dHealth--;
  281.     }
  282.  
  283.     //If we can actually move forward (i.e. there's not a wall in front of us) do so
  284.     if(pWorld->ppnWorld[pWorld->ulCharacterLocationX+dx][pWorld->ulCharacterLocationY+dy]!=2)
  285.     {
  286.         pWorld->ppnWorld[pWorld->ulCharacterLocationX][pWorld->ulCharacterLocationY]=0;
  287.         pWorld->ulCharacterLocationX+=dx;
  288.         pWorld->ulCharacterLocationY+=dy;
  289.     }
  290.  
  291.     //If we're running in slow motion, draw the agent in its new position 
  292.     if(nSlowMotion)
  293.     {
  294.         pDC->SelectStockObject(BLACK_PEN);
  295.         pDC->SelectStockObject(BLACK_BRUSH);
  296.         pDC->Rectangle(
  297.                                     int(pWorld->ulCharacterLocationX*dScale),
  298.                                     int(pWorld->ulCharacterLocationY*dScale),
  299.                                     int((pWorld->ulCharacterLocationX+1)*dScale+1),
  300.                                     int((pWorld->ulCharacterLocationY+1)*dScale+1));
  301.  
  302.         //And wait a while before continuing
  303.         unsigned long ulDelay=0;
  304.         do
  305.         {
  306.             ulDelay++;
  307.         }
  308.         while(ulDelay<1e+6);
  309.     }
  310.     delete pDC;
  311.  
  312.     //Update a counter of the number of steps used so far to evaluate the fitness of this individual
  313.     ulEvaluationIteration++;
  314. }
  315.  
  316. void Evaluate(void)
  317. {
  318.     unsigned long ulDelay=0;
  319.  
  320.     SYSTEMTIME StartTime,CurrentTime;
  321.     GetSystemTime(&StartTime);
  322.     unsigned long ulCurrentTime;
  323.  
  324.     //Create a drawing surface
  325.     CClientDC *pDC=new CClientDC((CView*)pView);
  326.  
  327.     //If we've finished evaluating the last chromosome and need a new one
  328.     if(ulEvaluationIteration==0)
  329.     {
  330.         //Reset the record of the amount of food and poison eaten
  331.         ulFoodEaten=0;
  332.         ulPoisonEaten=0;
  333.  
  334.         //Clear the window
  335.         pDC->SelectStockObject(WHITE_PEN);
  336.         pDC->Rectangle(500,0,2000,2000);
  337.  
  338.         //Keep track of the number of programs evalutaed so far
  339.         ulIteration++;
  340.  
  341.         //Reste the health (fitness/performance) estimate
  342.         dHealth=0.0;
  343.  
  344.         //Reset the world
  345.         pWorld->Initialise();
  346.  
  347.         //If not we're runnning in slow motion (and hence not watching the best performing program)
  348.         if(!nSlowMotion)
  349.         {
  350.             //Get a new program from the GP class so that we can evaluate its performance
  351.             pdChromosome=pGP->pGetChromosomeForEvaluation();
  352.         }
  353.         else
  354.         {
  355.             //Otherwise get a copy of the best program found so far so that we can watch it perform
  356.             pdChromosome=pGP->pGetBestChromosome();
  357.  
  358.             //Draw the world
  359.             pWorld->Draw(pDC);
  360.         }
  361.     }
  362.     char pString[1000];
  363.     unsigned long ulStartTime=    
  364.                                                     StartTime.wMilliseconds
  365.                                                     +1000*StartTime.wSecond
  366.                                                     +60*StartTime.wMinute
  367.                                                     +3600*StartTime.wHour
  368.                                                     +24*3600*StartTime.wDay;
  369.     do
  370.     {
  371.         //Run the program
  372.         pdChromosome->dEvaluate();
  373.  
  374.         //Keep track of the number of times its been executed
  375.         ulEvaluationIteration++;
  376.  
  377.         //Put some info on the screen so that we can monitor the progress
  378.         sprintf(pString,"Food eaten:           %u",ulFoodEaten);
  379.         pDC->TextOut(550,20,pString);
  380.         sprintf(pString,"Poison eaten:         %u",ulPoisonEaten);
  381.         pDC->TextOut(550,40,pString);
  382.         sprintf(pString,"Highest fitness:    %+6.2lf",pGP->dGetBestPerformance());
  383.         pDC->TextOut(550,60,pString);
  384.  
  385.         GetSystemTime(&CurrentTime);
  386.         ulCurrentTime=    
  387.                                                     CurrentTime.wMilliseconds
  388.                                                     +1000*CurrentTime.wSecond
  389.                                                     +60*CurrentTime.wMinute
  390.                                                     +3600*CurrentTime.wHour
  391.                                                     +24*3600*CurrentTime.wDay;
  392.     }
  393.     //Keep going for either 50ms or until we've finished. See additional comments for this line in 
  394.     //CGAPBILExampleDoc.cpp
  395.     while(ulCurrentTime-ulStartTime<1000 && ulEvaluationIteration<=5000);
  396.  
  397.     //If we have actually finished
  398.     if(ulEvaluationIteration>5000)
  399.     {
  400.         //Reset the counter of the number of step made in evaluating the current program
  401.         ulEvaluationIteration=0;
  402.  
  403.         //Reduce the estmiate of the program's health (i.e. performance) by subtracting some function of the number
  404.         //of nodes (instricutions) in the program. Typcially, the lengths of the programs produced by GP tend to 
  405.         //increase in length with time and usually contain large redundant sections. This makes the programs inefficient
  406.         //and impossible to understand. The penalty provided by the line below helps to encourage the emergence of
  407.         //shorter programs
  408.         dHealth-=0.1*pow(pdChromosome->ulGetNumberOfNodesInSubtree(0),1.0);
  409.  
  410.         //If we're not just watching the best program perform
  411.         if(!nSlowMotion)
  412.         {
  413.             //Set the health (performance) of the program that was just evaluated
  414.             pGP->SetFitness(dHealth);
  415.  
  416.             //If we've reached out performance target, stop evolving and just watch the best performer
  417.             if(pGP->dGetBestPerformance()>250)
  418.             {
  419.                 nSlowMotion=1;
  420.             }
  421.         }
  422.     }
  423.     //Delete the drawing surface
  424.     delete pDC;
  425. }
  426.  
  427. BOOL CGPExampleDoc::OnNewDocument()
  428. {
  429.     if (!CDocument::OnNewDocument())
  430.         return FALSE;
  431.  
  432.     // TODO: add reinitialization code here
  433.     // (SDI documents will reuse this document)
  434.  
  435.     return TRUE;
  436. }
  437.  
  438. /////////////////////////////////////////////////////////////////////////////
  439. // CGPExampleDoc serialization
  440.  
  441. void CGPExampleDoc::Serialize(CArchive& ar)
  442. {
  443.     if (ar.IsStoring())
  444.     {
  445.         // TODO: add storing code here
  446.     }
  447.     else
  448.     {
  449.         // TODO: add loading code here
  450.     }
  451. }
  452.  
  453. /////////////////////////////////////////////////////////////////////////////
  454. // CGPExampleDoc diagnostics
  455.  
  456. #ifdef _DEBUG
  457. void CGPExampleDoc::AssertValid() const
  458. {
  459.     CDocument::AssertValid();
  460. }
  461.  
  462. void CGPExampleDoc::Dump(CDumpContext& dc) const
  463. {
  464.     CDocument::Dump(dc);
  465. }
  466. #endif //_DEBUG
  467.  
  468. /////////////////////////////////////////////////////////////////////////////
  469. // CGPExampleDoc commands
  470.