home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C ++ / Applications / TimGA 1.2.1 / .cp / CGraphNodes.cp < prev    next >
Encoding:
Text File  |  1997-07-16  |  31.2 KB  |  1,091 lines  |  [TEXT/CWIE]

  1. // ===========================================================================
  2. //    CGraphNodes.cp        ©1995-97 Timo Eloranta        All rights reserved.
  3. // ===========================================================================
  4. //    This class takes care of storing the nodes of a single graph drawing
  5. //    (i.e. instances of this class are owned by CGraphDrawing objects...).
  6. //    Since almost all of the mutation and crossover operations manipulate
  7. //    the positions of the nodes, you can find the code for those operations
  8. //    from this class.
  9.  
  10. #include <PP_Constants.h>
  11.  
  12. #include "CFitness.h"
  13. #include "CGraphNodes.h"
  14.  
  15. #include "MyUtils.h"
  16.  
  17. // ---------------------------------------------------------------------------
  18. //        • CGraphNodes
  19. // ---------------------------------------------------------------------------
  20. //    Constructor.
  21.  
  22. CGraphNodes::CGraphNodes()
  23. {
  24.     mNodeCount    = 0;
  25. }
  26.  
  27. // ---------------------------------------------------------------------------
  28. //        • Initialize
  29. //
  30. //          Called by:    CGraphDrawing::Initialize
  31. // ---------------------------------------------------------------------------
  32.  
  33. void 
  34. CGraphNodes::Initialize( 
  35.         Int16     inNodeCount,
  36.         Int16     inGridSize,
  37.         Boolean    inFirstTime)
  38. {
  39.     Int16    theIndex, theNodeX, theNodeY;
  40.  
  41.     mGridSize    = inGridSize;
  42.  
  43.     if ( inNodeCount != mNodeCount ) {
  44.         mNodesArray.erase( mNodesArray.begin(), mNodesArray.end() );
  45.         mNodesArray.reserve( inNodeCount + 1 );
  46.  
  47.         for ( theIndex = 0; theIndex <= inNodeCount; ++theIndex )
  48.             mNodesArray.push_back( CNode() );
  49.             
  50.         mNodeCount = inNodeCount;
  51.     }
  52.  
  53.     if ( ! inFirstTime )
  54.         ClearAll();
  55.  
  56.     theIndex = 1;
  57.     while ( theIndex <= mNodeCount ) {
  58.     
  59.         // Choose random coordinates
  60.         theNodeX = RangedRdm( 1, mGridSize );
  61.         theNodeY = RangedRdm( 1, mGridSize );
  62.  
  63.         // Test if the square is already taken...
  64.         if (! NodeInSquare( theNodeX, theNodeY ) ) {
  65.             SetNode( theIndex, theNodeX, theNodeY );    // Add it ...
  66.             theIndex++;                                 // ... and advance
  67.         }
  68.     }
  69. }
  70.  
  71. // ---------------------------------------------------------------------------
  72. //        • NodeInSquare    (PRIVATE)
  73. //
  74. //          Called by:    CGraphNodes::Initialize
  75. //                        CGraphNodes::SingleMutate
  76. //                        CGraphNodes::MoveEdge
  77. //                        CGraphNodes::Move3ConnectedNodes etc.
  78. // ---------------------------------------------------------------------------
  79. //  Returns a pointer to the node in a given location or nil if square empty.
  80.  
  81. CNodePtr
  82. CGraphNodes::NodeInSquare( Int16 inX, Int16 inY ) const
  83. {
  84.     NodeVector::const_iterator    theIter = mNodesArray.begin() + 1;
  85.  
  86.     while ( theIter != mNodesArray.end() ) {
  87.         if ( theIter -> HasPosition( inX, inY ) )
  88.             return (CNodePtr) theIter;
  89.         ++theIter;
  90.     }
  91.     return nil;        // The square is empty...
  92. }
  93.  
  94. // ---------------------------------------------------------------------------
  95. //        • ClearAll        (PRIVATE)
  96. //
  97. //          Called by:    CGraphNodes::Initialize
  98. //                        CGraphNodes::RectCrossover
  99. // ---------------------------------------------------------------------------
  100.  
  101. void
  102. CGraphNodes::ClearAll( )
  103. {
  104.     // Clear out the old stuff
  105.  
  106.     NodeVector::iterator    theIter = mNodesArray.begin() + 1;
  107.  
  108.     while ( theIter != mNodesArray.end() ) {
  109.         theIter -> Set( 0, 0, 0 );
  110.         ++theIter;
  111.     }
  112. }
  113.  
  114. // ---------------------------------------------------------------------------
  115. //        • SingleMutate
  116. //
  117. //          Called by:    CGraphDrawing::Mutate
  118. // ---------------------------------------------------------------------------
  119. //      One of the mutation variations.
  120. //        Move a single node to a random new position (square must be empty...).
  121.  
  122. void
  123. CGraphNodes::SingleMutate()
  124. {
  125.     Int16    theNodeNbr, theNewNodeX, theNewNodeY;
  126.  
  127.     theNodeNbr    = RangedRdm( 1, mNodeCount );    // Random node nbr
  128.     
  129.     do {
  130.         theNewNodeX = RangedRdm( 1, mGridSize );
  131.         theNewNodeY = RangedRdm( 1, mGridSize );
  132.         
  133.     } while ( NodeInSquare( theNewNodeX, theNewNodeY ));
  134.  
  135.     SetNodePos( theNodeNbr, theNewNodeX, theNewNodeY );
  136. }
  137.  
  138. // ---------------------------------------------------------------------------
  139. //        • TinyMutate
  140. //
  141. //          Called by:    CGraphDrawing::Mutate
  142. // ---------------------------------------------------------------------------
  143. //      One of the mutation variations. Move a single node just a bit.
  144.  
  145. Boolean
  146. CGraphNodes::TinyMutate()
  147. {
  148.     Int16    theNodeNbr, theX, theY, theNewX, theNewY, theFails = 0;
  149.     
  150.     theNodeNbr    = RangedRdm( 1, mNodeCount );    // Random node nbr
  151.     
  152.     mNodesArray[ theNodeNbr ].GetNodePos( theX, theY );
  153.  
  154.     do {
  155.         theNewX    = RangedRdm( theX - 1, theX + 1 );
  156.         theNewY = RangedRdm( theY - 1, theY + 1 );
  157.         
  158.         if ( InsideAndFree( theNewX, theNewY ) ) {
  159.              SetNodePos( theNodeNbr, theNewX, theNewY );
  160.              return true;
  161.         }
  162.         else ++theFails;
  163.         
  164.     } while ( theFails < 3 );    // Try max 3 times before giving up...
  165.     
  166.     return false;    // We were unsuccessful in placing the node!
  167. }
  168.  
  169. // ---------------------------------------------------------------------------
  170. //        • TinyMoveEdge
  171. //
  172. //          Called by:    CGraphDrawing::EdgeMutation
  173. // ---------------------------------------------------------------------------
  174. //      One of the mutation variations. Move a single edge just a bit.
  175.  
  176. Boolean 
  177. CGraphNodes::TinyMoveEdge( 
  178.     CNodePtr inNode1, 
  179.     CNodePtr inNode2 )
  180. {
  181.     Int16    theNodeNbr1, theNodeNbr2,
  182.             theX1, theY1, theX2, theY2,
  183.             theNewX1, theNewY1, theNewX2, theNewY2,
  184.             thePreferredX2, thePreferredY2, theFails = 0;
  185.     Boolean theNode1Moved = false;
  186.  
  187.     theNodeNbr1    = inNode1 -> GetNodeNbr();
  188.     theNodeNbr2    = inNode2 -> GetNodeNbr();
  189.     
  190.     inNode1        -> GetNodePos( theX1, theY1 );
  191.     inNode2        -> GetNodePos( theX2, theY2 );
  192.     
  193.     // First we try to relocate the    other end of the edge
  194.     
  195.     do {
  196.     
  197.         theNewX1 = RangedRdm( theX1 - 1, theX1 + 1 );
  198.         theNewY1 = RangedRdm( theY1 - 1, theY1 + 1 );
  199.         
  200.         if ( InsideAndFree( theNewX1, theNewY1 )) {
  201.              SetNodePos( theNodeNbr1, theNewX1, theNewY1 );
  202.              theNode1Moved = true;
  203.              break;
  204.         }
  205.         else ++theFails;
  206.         
  207.     } while ( theFails < 3 );    // Try max 3 times before giving up...
  208.     
  209.     if ( theNode1Moved )
  210.         theFails = 0;
  211.     else
  212.         return false;    // If we couldn't move the first node, 
  213.                         // we'll leave the other node untouched as well
  214.     theFails = 0;
  215.     
  216.     // We'll try to keep the edge in its original length and form.
  217.  
  218.     theNewX2 = thePreferredX2 = theNewX1 + ( theX2 - theX1 );
  219.     theNewY2 = thePreferredY2 = theNewY1 + ( theY2 - theY1 );
  220.  
  221.     do {
  222.  
  223.         if (! ( InsideAndFree( theNewX1, theNewY1 ))) {
  224.     
  225.             ++theFails;
  226.     
  227.             theNewX2 = RangedRdm( thePreferredX2 - 1, thePreferredX2 + 1 );
  228.             theNewY2 = RangedRdm( thePreferredY2 - 1, thePreferredY2 + 1 );
  229.         }
  230.         else {
  231.              SetNodePos( theNodeNbr2, theNewX2, theNewY2 );
  232.              return true;
  233.         }
  234.         
  235.     } while ( theFails < 3 );    // Try max 3 times before giving up...
  236.  
  237.     return true;    // The 2nd node didn't move but the 1st did!
  238. }
  239.  
  240. // ---------------------------------------------------------------------------
  241. //        • MoveEdge
  242. //
  243. //          Called by:    CGraphDrawing::EdgeMutation
  244. //                        CGraphDrawing::TwoEdgeMutation
  245. // ---------------------------------------------------------------------------
  246. //      One of the mutation variations.
  247.  
  248. void
  249. CGraphNodes::MoveEdge( 
  250.     CNodePtr    inNode1, 
  251.     CNodePtr    inNode2,
  252.     Boolean        inPreserveLength )
  253. {
  254.     Int16    theNodeNbr1, theNodeNbr2,
  255.             theX1, theY1, theX2, theY2, theXdiff, theYdiff,
  256.             theNewX1, theNewY1, theNewX2, theNewY2;
  257.  
  258.     theNodeNbr1    = inNode1 -> GetNodeNbr();
  259.     theNodeNbr2    = inNode2 -> GetNodeNbr();
  260.     
  261.     inNode1    -> GetNodePos( theX1, theY1 );
  262.     inNode2    -> GetNodePos( theX2, theY2 );
  263.     
  264.     do {
  265.         theNewX1 = RangedRdm( 1, mGridSize);
  266.         theNewY1 = RangedRdm( 1, mGridSize);
  267.     } while ( NodeInSquare( theNewX1, theNewY1 ) );
  268.     
  269.     SetNodePos( theNodeNbr1, theNewX1, theNewY1 );
  270.     
  271.     // We have now moved the other end (= node1) of the edge. We now move 
  272.     // the other end. If the boolean parameter inPreserveLength is true,
  273.     // we try to place the other node to an equal location in relation to
  274.     // the first node. If that cannot be done (if the wanted square is
  275.     // outside the grid or already taken) we try the other three squares
  276.     // in the original distance before giving up and placing the other end
  277.     // to a random free square...
  278.     
  279.     if ( inPreserveLength ) {
  280.     
  281.         theXdiff = ( RandomBool() ) ? theX2 - theX1 : theX1 - theX2;
  282.         theYdiff = ( RandomBool() ) ? theY2 - theY1 : theY1 - theY2;
  283.         
  284.         theNewX2 = theNewX1 + theXdiff;
  285.         theNewY2 = theNewY1 + theYdiff;
  286.         
  287.         if ( ! InsideAndFree( theNewX2, theNewY2 )) {
  288.             theNewX2 = theNewX1 - theXdiff;
  289.             
  290.             if ( ! InsideAndFree( theNewX2, theNewY2 )) {
  291.                 theNewY2 = theNewY1 - theYdiff;
  292.                 
  293.                 if ( ! InsideAndFree( theNewX2, theNewY2 )) {
  294.                     theNewX2 = theNewX1 + theXdiff;
  295.                     
  296.                     if ( ! InsideTheGrid( theNewX2, theNewY2 )) {
  297.                         theNewX2 = RangedRdm( 1, mGridSize );
  298.                         theNewY2 = RangedRdm( 1, mGridSize );
  299.                     }
  300.  
  301.                     while ( NodeInSquare( theNewX2, theNewY2 ) ) {
  302.                         theNewX2 = RangedRdm( 1, mGridSize );
  303.                         theNewY2 = RangedRdm( 1, mGridSize );
  304.                     }
  305.                 }
  306.             }
  307.         }
  308.         
  309.     } else {
  310.  
  311.         do {
  312.             theNewX2 = RangedRdm( 1, mGridSize );
  313.             theNewY2 = RangedRdm( 1, mGridSize );
  314.         } while ( NodeInSquare( theNewX2, theNewY2 ) );
  315.     }
  316.  
  317.     SetNodePos( theNodeNbr2, theNewX2, theNewY2 );            
  318. }
  319.  
  320. // ---------------------------------------------------------------------------
  321. //        • Move3ConnectedNodes
  322. //
  323. //          Called by:    CGraphDrawing::TwoEdgeMutation
  324. // ---------------------------------------------------------------------------
  325. //      One of the mutation variations. 
  326. //        Moves two edges which share one of their endpoints.
  327. //        For comments see MoveEdge. This is very similar... 
  328.  
  329. void
  330. CGraphNodes::Move3ConnectedNodes( 
  331.     CNodePtr    inNode1, 
  332.     CNodePtr    inNode2,
  333.     CNodePtr    inNode3 )
  334. {
  335.     Int16    theX1, theY1, theX2, theY2, theX3, theY3,
  336.             theNewX1, theNewY1, theNewX2, theNewY2, theNewX3, theNewY3;
  337.  
  338.     Int16    theNodeNbr1    = inNode1 -> GetNodeNbr();
  339.     Int16    theNodeNbr2    = inNode2 -> GetNodeNbr();
  340.     Int16    theNodeNbr3    = inNode3 -> GetNodeNbr();
  341.     
  342.     inNode1    -> GetNodePos( theX1, theY1 );
  343.     inNode2    -> GetNodePos( theX2, theY2 );
  344.     inNode3    -> GetNodePos( theX3, theY3 );
  345.     
  346.     do {
  347.         theNewX1 = RangedRdm( 1, mGridSize);
  348.         theNewY1 = RangedRdm( 1, mGridSize);
  349.     } while ( NodeInSquare( theNewX1, theNewY1 ) );
  350.     
  351.     SetNodePos( theNodeNbr1, theNewX1, theNewY1 );
  352.     
  353.     // One node done. Two to go...
  354.     
  355.     Int16    theX12diff = ( RandomBool() ) ? theX2 - theX1 : theX1 - theX2;
  356.     Int16    theY12diff = ( RandomBool() ) ? theY2 - theY1 : theY1 - theY2;
  357.  
  358.     theNewX2 = theNewX1 + theX12diff;
  359.     theNewY2 = theNewY1 + theY12diff;
  360.  
  361.     if ( ! InsideAndFree( theNewX2, theNewY2 )) {
  362.         theNewX2 = theNewX1 - theX12diff;
  363.         
  364.         if ( ! InsideAndFree( theNewX2, theNewY2 )) {
  365.             theNewY2 = theNewY1 - theY12diff;
  366.             
  367.             if ( ! InsideAndFree( theNewX2, theNewY2 )) {
  368.                 theNewX2 = theNewX1 + theX12diff;
  369.                 
  370.                 if ( ! InsideTheGrid( theNewX2, theNewY2 )) {
  371.                     theNewX2 = RangedRdm( 1, mGridSize );
  372.                     theNewY2 = RangedRdm( 1, mGridSize );
  373.                 }
  374.  
  375.                 while ( NodeInSquare( theNewX2, theNewY2 ) ) {
  376.                     theNewX2 = RangedRdm( 1, mGridSize );
  377.                     theNewY2 = RangedRdm( 1, mGridSize );
  378.                 }
  379.             }
  380.         }
  381.     }
  382.  
  383.     SetNodePos( theNodeNbr2, theNewX2, theNewY2 );
  384.     
  385.     // And one more...            
  386.  
  387.     Int16    theX13diff = ( RandomBool() ) ? theX3 - theX1 : theX1 - theX3;
  388.     Int16    theY13diff = ( RandomBool() ) ? theY3 - theY1 : theY1 - theY3;
  389.  
  390.     theNewX3 = theNewX1 + theX13diff;
  391.     theNewY3 = theNewY1 + theY13diff;
  392.  
  393.     if ( ! InsideAndFree( theNewX3, theNewY3 )) {
  394.         theNewX3 = theNewX1 - theX13diff;
  395.         
  396.         if ( ! InsideAndFree( theNewX3, theNewY3 )) {
  397.             theNewY3 = theNewY1 - theY13diff;
  398.             
  399.             if ( ! InsideAndFree( theNewX3, theNewY3 )) {
  400.                 theNewX3 = theNewX1 + theX13diff;
  401.                 
  402.                 if ( ! InsideTheGrid( theNewX3, theNewY3 )) {
  403.                     theNewX3 = RangedRdm( 1, mGridSize );
  404.                     theNewY3 = RangedRdm( 1, mGridSize );
  405.                 }
  406.  
  407.                 while ( NodeInSquare( theNewX3, theNewY3 ) ) {
  408.                     theNewX3 = RangedRdm( 1, mGridSize );
  409.                     theNewY3 = RangedRdm( 1, mGridSize );
  410.                 }
  411.             }
  412.         }
  413.     }
  414.  
  415.     SetNodePos( theNodeNbr3, theNewX3, theNewY3 );
  416. }
  417.  
  418. // ---------------------------------------------------------------------------
  419. //        • SwapRows
  420. //
  421. //          Called by:    CGraphDrawing::Mutate
  422. // ---------------------------------------------------------------------------
  423. //      One of the mutation variations.
  424.  
  425. void
  426. CGraphNodes::SwapRows()
  427. {
  428.     Int16    theRowNbr1, theRowNbr2,
  429.             theNodeX, theNodeY;
  430.  
  431.     theRowNbr1 = GetRdmRowOrColWithNode( true );
  432.     theRowNbr2 = GetRdmRowOrColWithException( theRowNbr1 );
  433.  
  434.     NodeVector::iterator    theIter = mNodesArray.begin() + 1;
  435.     
  436.     while ( theIter != mNodesArray.end() ) {
  437.         theIter -> GetNodePos( theNodeX, theNodeY );
  438.         
  439.         if ( theNodeY == theRowNbr1 )
  440.             theIter -> SetNodePos( theNodeX, theRowNbr2 );
  441.         else if ( theNodeY == theRowNbr2 )
  442.             theIter -> SetNodePos( theNodeX, theRowNbr1 );
  443.     
  444.         ++theIter;
  445.     }
  446. }
  447.  
  448. // ---------------------------------------------------------------------------
  449. //        • SwapCols
  450. //
  451. //          Called by:    CGraphDrawing::Mutate
  452. // ---------------------------------------------------------------------------
  453. //      One of the mutation variations.
  454.  
  455. void
  456. CGraphNodes::SwapCols()
  457. {
  458.     Int16    theColNbr1, theColNbr2,
  459.             theNodeX, theNodeY;
  460.     
  461.     theColNbr1 = GetRdmRowOrColWithNode( false );
  462.     theColNbr2 = GetRdmRowOrColWithException( theColNbr1 );
  463.  
  464.     NodeVector::iterator    theIter = mNodesArray.begin() + 1;
  465.     
  466.     while ( theIter != mNodesArray.end() ) {
  467.         theIter -> GetNodePos( theNodeX, theNodeY);
  468.         
  469.         if ( theNodeX == theColNbr1 )
  470.             theIter -> SetNodePos( theColNbr2, theNodeY );
  471.         else if ( theNodeX == theColNbr2 )
  472.             theIter -> SetNodePos( theColNbr1, theNodeY );
  473.             
  474.         ++theIter;
  475.     }
  476. }
  477.  
  478. // ---------------------------------------------------------------------------
  479. //        • SwapInRowOrCol
  480. //
  481. //          Called by:    CGraphDrawing::Mutate
  482. // ---------------------------------------------------------------------------
  483. //      Two of the mutation variations (SwapInRow & SwapInCol combined).
  484.  
  485. Boolean
  486. CGraphNodes::SwapInRowOrCol( Boolean inRowSwap )
  487. {
  488.     Int16    theRowOrColNbr,
  489.             theNodeNbr1        = 0, theNodeNbr2    = 0,
  490.             theColOrRow1     = 0, theColOrRow2    = 0;
  491.  
  492.     theRowOrColNbr = GetRdmRowOrColWithAtLeast2Nodes( inRowSwap );
  493.     if ( theRowOrColNbr == 0 )
  494.         return false;        // No row/col with at least 2 nodes was found!
  495.     
  496.     GetRdmTwoFromRowOrCol(    inRowSwap, theRowOrColNbr,
  497.                             theNodeNbr1, theNodeNbr2, 
  498.                             theColOrRow1, theColOrRow2 ); 
  499.  
  500.     if ( inRowSwap ) {
  501.         mNodesArray[ theNodeNbr1 ].SetNodePos( theColOrRow2, theRowOrColNbr );
  502.         mNodesArray[ theNodeNbr2 ].SetNodePos( theColOrRow1, theRowOrColNbr );
  503.     } else {
  504.         mNodesArray[ theNodeNbr1 ].SetNodePos( theRowOrColNbr, theColOrRow2 );
  505.         mNodesArray[ theNodeNbr2 ].SetNodePos( theRowOrColNbr, theColOrRow1 );
  506.     }
  507.     
  508.     return true;
  509. }
  510.  
  511. // ---------------------------------------------------------------------------
  512. //        • SmallMutate
  513. //
  514. //          Called by:    CGraphDrawing::Mutate
  515. // ---------------------------------------------------------------------------
  516. //      One of the mutation variations. 
  517. //        Similar to SingleMutate, but with the possibility of a swap.
  518.  
  519. void
  520. CGraphNodes::SmallMutate()
  521. {
  522.     Int16        theMoverNbr, theOtherNbr,
  523.                 theNewNodeX, theNewNodeY,
  524.                 theFromX, theFromY;
  525.     CNodePtr    theOtherNode = nil;
  526.     Boolean        theDone = false;
  527.  
  528.     theMoverNbr    = RangedRdm( 1, mNodeCount );    // This one will move!
  529.  
  530.     while (! theDone ) {
  531.     
  532.         theNewNodeX    = RangedRdm( 1, mGridSize);
  533.         theNewNodeY    = RangedRdm( 1, mGridSize);
  534.     
  535.         // Test if the square is free. 
  536.         // If it is, move there, if not, swap places...
  537.         
  538.         if (! ( theOtherNode = NodeInSquare( theNewNodeX, theNewNodeY )) ) {
  539.             SetNodePos( theMoverNbr, theNewNodeX, theNewNodeY);
  540.             theDone = true;
  541.         } else {    // The square we picked is occupied by "theOtherNode"...
  542.     
  543.             // If we are unlucky enough to pick the square our
  544.             // "original" node is in, then we'll start over...
  545.             
  546.             theOtherNode -> GetNodeNbr( theOtherNbr );
  547.             if ( theMoverNbr != theOtherNbr ) {
  548.                 mNodesArray[ theMoverNbr ].GetNodePos( theFromX, theFromY );
  549.                 
  550.                 SetNodePos( theMoverNbr, theNewNodeX, theNewNodeY);
  551.                 SetNodePos( theOtherNbr, theFromX,    theFromY);
  552.                 
  553.                 theDone = true;
  554.             }
  555.         }
  556.     }
  557. }
  558.  
  559. // ---------------------------------------------------------------------------
  560. //        • LargeContMutate
  561. //
  562. //          Called by:    CGraphDrawing::Mutate
  563. // ---------------------------------------------------------------------------
  564. //      One of the mutation variations. 
  565.  
  566. Boolean
  567. CGraphNodes::LargeContMutate()
  568. {
  569.     Rect    theR1, theR2;            // rects 1 and 2
  570.     Int16    theW, theH;                // width and height
  571.     Boolean    theMovedSomething = false;
  572.  
  573.     // We need two rects with equal size
  574.     // First we'll deside the width of the rect.
  575.     // We'll restrict both width and height of the rect to half-a-grid.
  576.     
  577.     theW = RangedRdm( 1, mGridSize / 2 );
  578.     theH = RangedRdm( 1, mGridSize / 2 );
  579.     
  580.     // Now we know the size. Next we'll determine the places
  581.     // of our two equal sized rects. Lots of random ahead...
  582.  
  583.     theR1.left     = RangedRdm( 1, mGridSize - theW + 1 );
  584.     theR1.right     = theR1.left + theW - 1;
  585.     theR2.left     = RangedRdm( 1, mGridSize - theW + 1 );
  586.     theR2.right     = theR2.left + theW - 1;
  587.  
  588.     // So, we didn't restrict the horizontal placement in any
  589.     // way. Next we'll check if we got some overlapping and
  590.     // make sure the rects won't intersect...
  591.  
  592.     if ( ( theR2.left >= theR1.left && theR2.left <= theR1.right ) ||
  593.          ( theR2.right >= theR1.left && theR2.right <= theR1.right ) ) {
  594.  
  595.          // Yep, they overlap horizontally. We'll play it safe
  596.          // and position rect 1 high enough so that rect 2 can
  597.          // be placed under it.
  598.           
  599.         theR1.top     = RangedRdm( 1, mGridSize - ( 2*theH ) + 1 );
  600.         theR1.bottom = theR1.top  + theH - 1;
  601.         theR2.top     = RangedRdm( theR1.bottom + 1, mGridSize - theH + 1 );
  602.         theR2.bottom = theR2.top  + theH - 1;
  603.     }
  604.     else {    // No horizontal overlapping. 
  605.             // Vertical placement is unrestricted!
  606.             
  607.         theR1.top     = RangedRdm( 1, mGridSize - theH + 1 );
  608.         theR1.bottom = theR1.top  + theH - 1;
  609.         theR2.top     = RangedRdm( 1, mGridSize - theH + 1 );
  610.         theR2.bottom = theR2.top  + theH - 1;
  611.     }
  612.     
  613.     Int16    theX, theY, theDeltaX, theDeltaY;
  614.     
  615.     theDeltaX = theR2.left - theR1.left;
  616.     theDeltaY = theR2.top  - theR1.top;
  617.  
  618.     NodeVector::iterator    theIter = mNodesArray.begin() + 1;
  619.     
  620.     while ( theIter != mNodesArray.end() ) {
  621.         theIter -> GetNodePos( theX, theY );
  622.         
  623.         if ( MyPtInRect( theX, theY, &theR1 )) { 
  624.             theIter -> SetNodePos( theX + theDeltaX, theY + theDeltaY );
  625.             theMovedSomething = true; 
  626.         } 
  627.         else if ( MyPtInRect( theX, theY, &theR2 )) {
  628.             theIter -> SetNodePos( theX - theDeltaX, theY - theDeltaY );
  629.             theMovedSomething = true; 
  630.         }
  631.         
  632.         ++theIter;
  633.     }
  634.  
  635.     return theMovedSomething;
  636. }
  637.  
  638. // ---------------------------------------------------------------------------
  639. //        • InvertRow
  640. //
  641. //          Called by:    CGraphDrawing::Mutate
  642. // ---------------------------------------------------------------------------
  643. //      One of the mutation variations.
  644. //        Note: returns false only if 
  645. //                - the grid has 2N+1 columns AND 
  646. //                - we select a row with exactly one node AND 
  647. //                - the only node is in column N+1.
  648. //        In other words, returns usually true... 
  649.  
  650. Boolean
  651. CGraphNodes::InvertRow()
  652. {
  653.     return InvertPartRow( true );
  654. }
  655.  
  656. // ---------------------------------------------------------------------------
  657. //        • InvertPartRow
  658. //
  659. //          Called by:    CGraphDrawing::Mutate
  660. //                        CGraphNodes::InvertRow
  661. // ---------------------------------------------------------------------------
  662. //      One of the mutation variations.
  663. //        Also used by InvertRow 
  664.  
  665. Boolean
  666. CGraphNodes::InvertPartRow( Boolean inInvertWholeRow )
  667. {
  668.     Int16        theRowNbr, theColMin, theColMax;
  669.     Boolean        theMovedSomething = false;
  670.  
  671.     // Let's pick a row with at least one node so we at least
  672.     // have a *chance* of changing something (doing inversions
  673.     // on an empty row would be sort of useless, right? :-).
  674.     
  675.     theRowNbr = GetRdmRowOrColWithNode( true );
  676.  
  677.     // Variables theColMin and theColMax define the part 
  678.     // of the row that we'll invert.
  679.  
  680.     if ( inInvertWholeRow ) {
  681.         theColMin = 1;
  682.         theColMax = mGridSize;
  683.     } else {
  684.         theColMin = RangedRdm( 1, mGridSize - 1 );
  685.         theColMax = RangedRdm( theColMin + 1, mGridSize );
  686.     }
  687.  
  688.     Int16    theX, theY, theNewX;
  689.     
  690.     // We now go through the array and change some node positions...
  691.  
  692.     NodeVector::iterator    theIter = mNodesArray.begin() + 1;
  693.     
  694.     while ( theIter != mNodesArray.end() ) {
  695.         theIter -> GetNodePos( theX, theY );
  696.         if ( theY == theRowNbr && ( inInvertWholeRow || 
  697.              (theX >= theColMin && theX <= theColMax) ) ) {
  698.                 theNewX = theColMax - theX + theColMin;
  699.                 theIter -> SetNodePos( theNewX, theY );
  700.                 theMovedSomething = true; 
  701.         }
  702.         ++theIter;
  703.     }
  704.  
  705.     return theMovedSomething;
  706. }
  707.  
  708. // ---------------------------------------------------------------------------
  709. //        • InvertCol
  710. //
  711. //          Called by:    CGraphDrawing::Mutate
  712. // ---------------------------------------------------------------------------
  713. //      One of the mutation variations.
  714. //        Note: returns false only if 
  715. //                - the grid has 2N+1 rows AND 
  716. //                - we select a column with exactly one node AND 
  717. //                - the only node is in row N+1.
  718. //        In other words, returns usually true... 
  719.  
  720. Boolean
  721. CGraphNodes::InvertCol()
  722. {
  723.     return InvertPartCol( true );
  724. }
  725.  
  726. // ---------------------------------------------------------------------------
  727. //        • InvertPartCol
  728. //
  729. //          Called by:    CGraphDrawing::Mutate
  730. //                        CGraphNodes::InvertCol
  731. // ---------------------------------------------------------------------------
  732. //      One of the mutation variations.
  733. //        Also used by InvertCol
  734. //        For comments see the *very* similar InvertPartRow 
  735.  
  736. Boolean
  737. CGraphNodes::InvertPartCol( Boolean inInvertWholeCol )
  738. {
  739.     Int16        theColNbr, theRowMin, theRowMax;
  740.     Boolean        theMovedSomething = false;
  741.  
  742.     theColNbr = GetRdmRowOrColWithNode( false );
  743.  
  744.     if ( inInvertWholeCol ) {
  745.         theRowMin = 1;
  746.         theRowMax = mGridSize;
  747.     } else {
  748.         theRowMin = RangedRdm( 1, mGridSize - 1 );
  749.         theRowMax = RangedRdm( theRowMin + 1, mGridSize );
  750.     }
  751.  
  752.     Int16    theX, theY, theNewY;
  753.  
  754.     NodeVector::iterator    theIter = mNodesArray.begin() + 1;
  755.     
  756.     while ( theIter != mNodesArray.end() ) {
  757.         theIter -> GetNodePos( theX, theY );
  758.         if ( theX == theColNbr && ( inInvertWholeCol || 
  759.              (theY >= theRowMin && theY <= theRowMax) ) ) {
  760.                 theNewY = theRowMax - theY + theRowMin;
  761.                 theIter -> SetNodePos( theX, theNewY );
  762.                 theMovedSomething = true; 
  763.         }
  764.         ++theIter;
  765.     }
  766.  
  767.     return theMovedSomething;
  768. }
  769.  
  770. // ---------------------------------------------------------------------------
  771. //        • ThreeNodeCrossover
  772. //
  773. //          Called by:    CGraphDrawing::ThreeNodeCrossover
  774. // ---------------------------------------------------------------------------
  775.  
  776. Boolean
  777. CGraphNodes::ThreeNodeCrossover( 
  778.     Int16 inNbr1,    Int16 inNbr2,    Int16 inNbr3,
  779.     Point &inTo1,    Point &inTo2,    Point &inTo3 )
  780. {
  781.     Boolean    theEarthMoved = false;
  782.     
  783.     if (! NodeInSquare(  inTo1.h, inTo1.v ) ) {
  784.         SetNodePos( inNbr1, inTo1.h, inTo1.v );
  785.         theEarthMoved = true;
  786.     }
  787.     
  788.     if (! NodeInSquare(  inTo2.h, inTo2.v ) ) {
  789.         SetNodePos( inNbr2, inTo2.h, inTo2.v );
  790.         theEarthMoved = true;
  791.     }
  792.     
  793.     if ( inNbr3 && (! NodeInSquare( inTo3.h, inTo3.v )) ) {
  794.         SetNodePos( inNbr3, inTo3.h, inTo3.v );
  795.         theEarthMoved = true;
  796.     }
  797.  
  798.     return theEarthMoved;
  799. }
  800.  
  801. // ---------------------------------------------------------------------------
  802. //        • RectCrossover
  803. //
  804. //          Called by:    CGraphDrawing::RectCrossover
  805. // ---------------------------------------------------------------------------
  806.  
  807. void
  808. CGraphNodes::RectCrossover( 
  809.     const Rect             &inSourceRect,
  810.     const Rect            &inDestRect, 
  811.     const CGraphNodes    &inBaseNodes,
  812.     const CGraphNodes    &inRectNodes )
  813. {
  814.     Int16    theNbr, theX, theY, theAddCount = 0;
  815.     
  816.     Int16    theXoffset    = inDestRect.left - inSourceRect.left;
  817.     Int16    theYoffset    = inDestRect.top - inSourceRect.top;
  818.  
  819.     ClearAll();    // We'll want to start with a clear table
  820.  
  821.     // There are four (4) ways a node can get placed 
  822.     // in the graph in this crossover operation:
  823.     //
  824.     //  #1 - If the node is inside the "source rect" in inRectNodes,
  825.     //       it takes the equalent position also in the new graph,
  826.     //         but in the "destination rect"...
  827.  
  828.     for ( theNbr = 1; theNbr <= mNodeCount; ++theNbr ) {
  829.         inRectNodes.mNodesArray[ theNbr ].GetNodePos( theX, theY );
  830.         if ( MyPtInRect( theX, theY, &inSourceRect ) ) {
  831.             SetNode( theNbr, theX + theXoffset, theY + theYoffset);    // #1
  832.             ++theAddCount;
  833.         }
  834.     }
  835.     
  836.     //  #2 - If node nbr X didn't get placed in phase #1 and the
  837.     //       position of X is outside the "destination rect" in 
  838.     //       inBaseNodes, put it on the same position in the new graph
  839.     
  840.     for ( theNbr = 1; theNbr <= mNodeCount; ++theNbr ) {
  841.         inBaseNodes.mNodesArray[ theNbr ].GetNodePos( theX, theY );
  842.         if ( (! (mNodesArray[ theNbr ].GetNodeNbr()) ) &&
  843.              (! MyPtInRect( theX, theY, &inDestRect )) ) {
  844.             SetNode( theNbr, theX, theY );                // #2
  845.             ++theAddCount;
  846.         }
  847.     }
  848.     
  849.     if ( theAddCount == mNodeCount ) return;    // All nodes placed?
  850.  
  851.     //  #3 - If node X still hasn't got placed and the square in
  852.     //       which X is in inRectNodes is still empty, put X in this
  853.     //         same place in the new graph. Note that if this happens,
  854.     //         then the node X is an "extra crosser" outside of the
  855.     //         actual crossover rect (= inSourceRect) !
  856.     
  857.     for ( theNbr = 1; theNbr <= mNodeCount; ++theNbr ) {
  858.         inRectNodes.mNodesArray[ theNbr ].GetNodePos( theX, theY );
  859.         if ( (! (mNodesArray[ theNbr ].GetNodeNbr()) ) &&
  860.              (! NodeInSquare( theX, theY )) ) {
  861.             SetNode( theNbr, theX, theY );                // #3
  862.             ++theAddCount;
  863.         }
  864.     }
  865.  
  866.     if ( theAddCount == mNodeCount ) return;    // All nodes placed?
  867.              
  868.     //  #4 - The final stage for the nodes that have MAJOR TROUBLE
  869.     //         finding a place in the new graph... In this phase we
  870.     //       select the new place by random, but naturally still
  871.     //         check that the place is free for our node to land into...
  872.     
  873.     for ( theNbr = 1; theNbr <= mNodeCount; ++theNbr ) {
  874.         if (! (mNodesArray[ theNbr ].GetNodeNbr()) ) {
  875.             while (1) {
  876.                 theX = RangedRdm( 1, mGridSize );
  877.                 theY = RangedRdm( 1, mGridSize );
  878.                 if (! NodeInSquare( theX, theY )) {
  879.                     SetNode( theNbr, theX, theY );
  880.                     ++theAddCount;
  881.                     break;
  882.                 }
  883.             }
  884.             
  885.             if ( theAddCount == mNodeCount ) return;    // Done yet?
  886.         }
  887.     }
  888. }
  889.  
  890. // ---------------------------------------------------------------------------
  891. //        • GetRdmRowOrColWithNode    (PRIVATE)
  892. //
  893. //          Called by:    CGraphNodes::SwapRows
  894. //                        CGraphNodes::SwapCols
  895. //                        CGraphNodes::InvertPartRow
  896. //                        CGraphNodes::InvertPartCol
  897. // ---------------------------------------------------------------------------
  898. //  We want a random row (or column) with at least one node. What do we do?
  899. //  Well, we take a random node from the array and return its row or column.
  900. //  Note that the number of nodes on a particular row/column determines also
  901. //  the probability of it getting selected! In other words, for example a
  902. //  row with 5 nodes has 5 times as big a chance of getting selected as a row
  903. //  with just one node. This means, that the selection is biased (= not
  904. //  purely random), but on the other hand this method is faster than picking
  905. //  random rows/columns until we find one with at least one node...
  906.  
  907. Int16
  908. CGraphNodes::GetRdmRowOrColWithNode( Boolean inRowWanted ) const
  909. {
  910.     Int16     theNodeNbr, theRow, theCol;
  911.     
  912.     theNodeNbr = RangedRdm( 1, mNodeCount );
  913.     mNodesArray[ theNodeNbr ].GetNodePos( theCol, theRow);
  914.  
  915.     return ( inRowWanted ) ? theRow : theCol;
  916. }
  917.  
  918. // ---------------------------------------------------------------------------
  919. //        • GetRdmRowOrColWithException    (PRIVATE)
  920. //
  921. //          Called by:    CGraphNodes::SwapRows
  922. //                        CGraphNodes::SwapCols
  923. // ---------------------------------------------------------------------------
  924.  
  925. Int16
  926. CGraphNodes::GetRdmRowOrColWithException( Int16 inNotThis ) const
  927. {
  928.     Int16    theNbr;
  929.     
  930.     do    {
  931.         theNbr = RangedRdm( 1, mGridSize );
  932.     } while ( theNbr == inNotThis );
  933.     
  934.     return theNbr;
  935. }
  936.  
  937. // ---------------------------------------------------------------------------
  938. //        • GetRdmRowOrColWithAtLeast2Nodes    (PRIVATE)
  939. //
  940. //          Called by:    CGraphNodes::SwapInRowOrCol
  941. // ---------------------------------------------------------------------------
  942.  
  943. Int16
  944. CGraphNodes::GetRdmRowOrColWithAtLeast2Nodes( Boolean inRowWanted ) const
  945. {
  946.     Int16                theFirst, theRowOrCol,
  947.                         theNodeNbr,
  948.                         theCol, theRow;
  949.     Boolean                theLoopComplete = false;
  950.  
  951.     vector<bool, allocator<bool> >    theMarkerArray( mGridSize + 1, false );
  952.     
  953.     theNodeNbr = theFirst = RangedRdm( 1, mNodeCount);
  954.     
  955.     do {
  956.         mNodesArray[ theNodeNbr ].GetNodePos( theCol, theRow );
  957.         theRowOrCol = ( inRowWanted ) ? theRow : theCol;
  958.     
  959.         if ( theMarkerArray[ theRowOrCol ] )            // Is this 2nd?
  960.             return theRowOrCol;
  961.         else    
  962.             theMarkerArray[ theRowOrCol ] = true;        // Chalk up one!
  963.  
  964.         ++theNodeNbr;                        // Advance to the next node
  965.         if ( theNodeNbr > mNodeCount )        // Possibly jump to the
  966.             theNodeNbr = 1;                    // beginning of the array
  967.             
  968.         theLoopComplete = ( theNodeNbr == theFirst );    // Gone around?
  969.         
  970.     } while ( ! theLoopComplete );
  971.     
  972.     return 0;    // A row/col with at least two nodes couldn't be found...
  973. }
  974.  
  975. // ---------------------------------------------------------------------------
  976. //        • GetRdmTwoFromRowOrCol    (PRIVATE)
  977. //
  978. //          Called by:    CGraphNodes::SwapInRowOrCol
  979. // ---------------------------------------------------------------------------
  980.  
  981. void
  982. CGraphNodes::GetRdmTwoFromRowOrCol( 
  983.     Boolean inColsWanted,
  984.     Int16    inFixedRowOrCol,
  985.     Int16    &outNodeNbr1, Int16    &outNodeNbr2,
  986.     Int16     &outRC1,       Int16 &outRC2 ) const
  987. {
  988.     Int16    theNodeNbr, theFirst,
  989.             theCol, theRow,
  990.             theComparator, theHunted;
  991.     Boolean    theLoopComplete = false;
  992.  
  993.     theNodeNbr = theFirst = RangedRdm( 1, mNodeCount );
  994.  
  995.     do {    
  996.         mNodesArray[ theNodeNbr ].GetNodePos( theCol, theRow );
  997.     
  998.         theComparator    = ( inColsWanted ) ? theRow : theCol;
  999.         theHunted         = ( inColsWanted ) ? theCol : theRow;
  1000.         
  1001.         if ( inFixedRowOrCol == theComparator ) {
  1002.             if (! outRC1) {
  1003.                 outRC1 = theHunted;            // First one found
  1004.                 outNodeNbr1 = theNodeNbr;
  1005.             } else {
  1006.                 outRC2 = theHunted;            // Second one found
  1007.                 outNodeNbr2 = theNodeNbr;
  1008.                 return;                        // We are done...
  1009.             }
  1010.         }
  1011.         
  1012.         ++theNodeNbr;                        // Advance to the next node
  1013.         if ( theNodeNbr > mNodeCount )        // Possibly jump to the
  1014.             theNodeNbr = 1;                    // beginning of the array
  1015.             
  1016.         theLoopComplete = ( theNodeNbr == theFirst );    // Gone around?
  1017.  
  1018.     } while ( ! theLoopComplete );
  1019. }
  1020.  
  1021. // ---------------------------------------------------------------------------
  1022. //        • DrawAll
  1023. //
  1024. //          Called by:    CGraphDrawing::DrawNodes
  1025. // ---------------------------------------------------------------------------
  1026.  
  1027. void
  1028. CGraphNodes::DrawAll( const Rect &inOneOneRect, Int16 inSquareSize) const
  1029. {
  1030.     NodeVector::const_iterator    theIter = mNodesArray.begin() + 1;
  1031.     
  1032.     while ( theIter != mNodesArray.end() ) {
  1033.         theIter -> Draw( inOneOneRect, inSquareSize);
  1034.         ++theIter;
  1035.     }
  1036. }
  1037.  
  1038. // ---------------------------------------------------------------------------
  1039. //        • operator=
  1040. //
  1041. //          Called by:    CGraphDrawing::BestCopy
  1042. // ---------------------------------------------------------------------------
  1043.  
  1044. CGraphNodes & CGraphNodes::operator=( const CGraphNodes & inGN )
  1045. {
  1046.     mNodeCount        = inGN.mNodeCount;
  1047.     mGridSize        = inGN.mGridSize;
  1048.  
  1049.     mNodesArray        = inGN.mNodesArray;
  1050.     
  1051.     return *this;
  1052. }
  1053.  
  1054. // ---------------------------------------------------------------------------
  1055. //        • BruteForceClosestPairs
  1056. //
  1057. //          Called by:    CGraphDrawing::Evaluate
  1058. // ---------------------------------------------------------------------------
  1059.  
  1060. void
  1061. CGraphNodes::BruteForceClosestPairs( CFitness &inFitness ) const
  1062. {
  1063.     Int16        theDex1, theDex2, theDist; 
  1064.     Int32        theMin = max_Int32,
  1065.                 theMinDistSum = 0L;
  1066.     CNodePtr    theNode;
  1067.     
  1068.     vector<UInt16, allocator<UInt16> > theDists( mNodeCount + 1, max_Int16 );
  1069.     
  1070.     for ( theDex1 = 1; theDex1 <= mNodeCount - 1; theDex1++ ) {
  1071.         theNode = (CNodePtr) &mNodesArray[ theDex1 ];
  1072.         
  1073.         for ( theDex2 = theDex1 + 1; theDex2 <= mNodeCount; theDex2++ ) {
  1074.             theDist    = theNode -> DistanceTo( mNodesArray[ theDex2 ] );
  1075.  
  1076.             if ( theDist < theMin ) 
  1077.                 theMin = theDist;
  1078.  
  1079.             if ( theDist < theDists[ theDex1 ] )
  1080.                 theDists[ theDex1 ] = theDist;
  1081.             if ( theDist < theDists[ theDex2 ] )
  1082.                 theDists[ theDex2 ] = theDist;
  1083.         }
  1084.     }
  1085.     
  1086.     for ( theDex1 = 1; theDex1 <= mNodeCount; theDex1++ )
  1087.         theMinDistSum += theDists[ theDex1 ];
  1088.  
  1089.     inFitness.SetMinDistance( theMin, theMinDistSum, mNodeCount, mGridSize );
  1090. }
  1091.