/// <summary> /// Returns the count of how many nodes there are in this tree /// And in the subtrees of this node /// </summary> /// <param name="ndNode">The root node</param> /// <returns> /// Returns the count of how many nodes there are in this tree /// And in the subtrees of this node /// </returns> public static int CountNodes(Node ndNode) { int nSum = 0; if (ndNode is FunctionNode) { FunctionNode fndNode = (FunctionNode)ndNode; foreach (Node ndSonNode in fndNode.m_arrSons) { nSum += CountNodes(ndSonNode); } } return(nSum + 1); }
static int nCurrentNodeNumber; // A helper variable /// <summary> /// Returns what is the depth, of the tree that a node contains. /// </summary> /// <param name="ndRoot">The root node</param> /// <returns>Returns what is the depth, of the tree that a node contains.</returns> public static int FindDepth(Node ndRoot) { int nDepth = 0; if (ndRoot is FunctionNode) { FunctionNode fncRoot = (FunctionNode)ndRoot; for (int nSonNum = 0; nSonNum != fncRoot.m_arrSons.Length; nSonNum++) { nDepth = Math.Max(nDepth, FindDepth(fncRoot.m_arrSons[nSonNum])); } } return(nDepth + 1); }
/// <summary> /// Exchanges two nodes, such that any other nodes that hold the same memory /// Will not be affected. /// </summary> /// <param name="ndNodeOne">Node one</param> /// <param name="ndNodeOneParent">Node one parent</param> /// <param name="ndProgramOneRootNode">The main root of node one</param> /// <param name="ndNodeTwo">Node two</param> /// <param name="ndNodeTwoParent">Node two parent</param> /// <param name="ndProgramTwoRootNode">The main root of node two</param> public static void ExchangeNodes(Node ndNodeOne, Node ndNodeOneParent, ref Node ndProgramOneRootNode, Node ndNodeTwo, Node ndNodeTwoParent, ref Node ndProgramTwoRootNode) { //node ndnodeoneclone = (node)ndnodeone.clone(); //node ndnodetwoclone = (node)ndnodetwo.clone(); //ndnodeone = ndnodetwoclone; //ndnodetwo = ndnodeoneclone; if (ndNodeOneParent == null) { ndProgramOneRootNode = ndNodeTwo; } else { FunctionNode fncNodeOneParent = (FunctionNode)ndNodeOneParent; // Find node one in node one parent sons and exchange it with node two for (int nSonIndexForParentOne = 0; nSonIndexForParentOne < fncNodeOneParent.m_arrSons.Length; nSonIndexForParentOne++) { if (fncNodeOneParent.m_arrSons[nSonIndexForParentOne] == ndNodeOne) { fncNodeOneParent.m_arrSons[nSonIndexForParentOne] = ndNodeTwo; } } } if (ndNodeTwoParent == null) { ndProgramTwoRootNode = ndNodeOne; } else { FunctionNode fncNodeTwoParent = (FunctionNode)ndNodeTwoParent; // Find node two in node two parent sons and exchange it with node one for (int nSonIndexForParentTwo = 0; nSonIndexForParentTwo < fncNodeTwoParent.m_arrSons.Length; nSonIndexForParentTwo++) { if (fncNodeTwoParent.m_arrSons[nSonIndexForParentTwo] == ndNodeTwo) { fncNodeTwoParent.m_arrSons[nSonIndexForParentTwo] = ndNodeOne; } } } }
/// <summary> /// Clones the function node recursively, The cloned version sits on a /// Different memory /// </summary> /// <returns>The clone of the function node</returns> public override object Clone() { FunctionNode fncNewNode = new FunctionNode(); // Copies the regular data members fncNewNode.m_funcFunction = this.m_funcFunction; fncNewNode.m_arrSons = new Node[this.m_arrSons.Length]; // Passes on all the sons and clones them too (This works recursively) for (int nSonNodeIndex = 0; nSonNodeIndex < this.m_arrSons.Length; nSonNodeIndex++) { fncNewNode.m_arrSons[nSonNodeIndex] = (Node)this.m_arrSons[nSonNodeIndex].Clone(); } return(fncNewNode); }
/// <summary> /// Creates a random node in the tree. The function is recursive, and /// Creates a random node. Which means, a random function or variable will /// Be selected . If a function is selected, then another nodes for the /// Function will be created. If a variable will be selected, then /// The tree will stop evolving at this branch. /// </summary> /// <param name="nCurrentDepth">The current tree depth</param> /// <returns>A random tree node</returns> private Node CreateRandomNode(int nCurrentDepth, BaseProgram baseProgOwner, ArrayList arrRandomableTypes) { TreeProgram progOwner = (TreeProgram)baseProgOwner; // The chosen index in all the types array, to choose some random thing, // Either variable of function, to insert as a node. int nChosenTypeIndex = GlobalRandom.m_rndRandom.Next(arrRandomableTypes.Count); object objChosenType = arrRandomableTypes[nChosenTypeIndex]; // If we are above the tree limit, choose randomly until we select a variable. bool fFoundLeaf = false; while ((nCurrentDepth > this.m_nMaxInitialTreeDepth) && (fFoundLeaf == false)) { nChosenTypeIndex = GlobalRandom.m_rndRandom.Next(arrRandomableTypes.Count); objChosenType = arrRandomableTypes[nChosenTypeIndex]; if (objChosenType is FunctionType) { if (((FunctionType)objChosenType).NumberOfArguments == 0) { fFoundLeaf = true; } } else // The type is variable { fFoundLeaf = true; } } // If we are below the initial tree limit, choose randomly until we select // A function. bool fFoundBranch = false; while ((nCurrentDepth < this.m_nMinInitialTreeDepth) && (fFoundBranch == false)) { nChosenTypeIndex = GlobalRandom.m_rndRandom.Next(arrRandomableTypes.Count); objChosenType = arrRandomableTypes[nChosenTypeIndex]; if (objChosenType is FunctionType) { if (((FunctionType)objChosenType).NumberOfArguments > 0) { fFoundBranch = true; } } } // If the object chosen is a variable, create a new VariableNode if (objChosenType is Variable) { Variable vlVariable = (Variable)objChosenType; return(new VariableNode(vlVariable, progOwner)); } // If the object chosen is a value, create a new ValueNode else if (objChosenType is Value) { Value vlValue = (Value)objChosenType; return(new ValueNode(vlValue)); } // If the object chosen is a RandomMacro, create a new ValueNode which // Will be randomized. else if (objChosenType is RandomMacro) { return(new ValueNode(((RandomMacro)objChosenType).ReturnValue())); } // If the object chosen is a function, then create a function and also // Create trees for that function. else if (objChosenType is Function) { FunctionNode fncNewNode = new FunctionNode(); Function funcChosenFunction = (Function)objChosenType; fncNewNode.m_funcFunction = funcChosenFunction; fncNewNode.m_arrSons = new Node[funcChosenFunction.NumberOfArguments]; for (int nSonIndex = 0; nSonIndex < fncNewNode.m_arrSons.Length; nSonIndex++) { fncNewNode.m_arrSons[nSonIndex] = CreateRandomNode(nCurrentDepth + 1, progOwner, arrRandomableTypes); } return(fncNewNode); } // We will never normally reach here. return(null); }
/// <summary> /// The function draws a program nodes using a Graphics object. /// </summary> /// <param name="grpGraphics"> /// The graphics object used to draw the program< /// /param> /// <param name="nWidth">The width of the wanted drawing</param> /// <param name="nHeight">The height of the wanted drawing</param> /// <param name="frmParentForm">The parent Form</param> public void Draw(Graphics grpGraphics, int nWidth, int nHeight, Form frmParentForm) { const float NODE_PERCENT_SIZE = 0.1F; const int BITMAP_OF_NODE_SIZE = 400; float NODE_PIXEL_SIZE = NODE_PERCENT_SIZE * nWidth; Color NODE_COLOR = Color.Green; Color BACKGROUND_COLOR = Color.White; Color LINE_COLOR = Color.Black; Bitmap bmpPicture = new Bitmap(nWidth, nHeight); Graphics cGraphicsOnPicture = Graphics.FromImage(bmpPicture); Brush brBrush = new SolidBrush(NODE_COLOR); List <List <Node> > lstNodeLayers = new List <List <Node> >(); List <List <Rectangle> > lstNodeBoxLayers = new List <List <Rectangle> >(); List <Node> lstFirstLayer = new List <Node>(); List <Node> lstSecondLayer = new List <Node>(); lstFirstLayer.Add(this.m_arrRoots[0]); while ((lstFirstLayer.Count != 0) || (lstSecondLayer.Count != 0)) { foreach (Node ndNodeInLayer in lstFirstLayer) { if (ndNodeInLayer is FunctionNode) { FunctionNode fncNode = (FunctionNode)ndNodeInLayer; lstSecondLayer.AddRange(fncNode.m_arrSons); } } if (lstFirstLayer.Count > 0) { lstNodeLayers.Add(lstFirstLayer.GetRange(0, lstFirstLayer.Count)); } lstFirstLayer.Clear(); foreach (Node ndNodeInLayer in lstSecondLayer) { if (ndNodeInLayer is FunctionNode) { FunctionNode fncNode = (FunctionNode)ndNodeInLayer; lstFirstLayer.AddRange(fncNode.m_arrSons); } } if (lstSecondLayer.Count > 0) { lstNodeLayers.Add(lstSecondLayer.GetRange(0, lstSecondLayer.Count)); } lstSecondLayer.Clear(); } cGraphicsOnPicture.Clear(Color.White); int nNodeHeightSize = nHeight / (lstNodeLayers.Count * 2); int nStartingY = 0; Bitmap bmpOfNode = new Bitmap(BITMAP_OF_NODE_SIZE, BITMAP_OF_NODE_SIZE); Graphics grpGraphicsOfNode = Graphics.FromImage(bmpOfNode); foreach (List <Node> lstLayer in lstNodeLayers) { int nNodeWidthSize = nWidth / (lstLayer.Count * 3); int nNodeSize = Math.Min(nNodeWidthSize, nNodeHeightSize); int nStartingX = (nWidth / 2) - (nNodeSize * lstLayer.Count); List <Rectangle> lstRectLayer = new List <Rectangle>(); foreach (Node ndNode in lstLayer) { Rectangle rctDrawingRectangle = new Rectangle(nStartingX, nStartingY, nNodeSize, nNodeSize); grpGraphicsOfNode.Clear(Color.White); grpGraphicsOfNode.FillEllipse(brBrush, new Rectangle(0, 0, bmpOfNode.Width, bmpOfNode.Height)); TreeProgram.DrawStringInWholeImage(bmpOfNode, ndNode.GetName(this)); lstRectLayer.Add(rctDrawingRectangle); cGraphicsOnPicture.DrawImage(bmpOfNode, rctDrawingRectangle); nStartingX += nNodeWidthSize * 2; } lstNodeBoxLayers.Add(lstRectLayer.GetRange(0, lstRectLayer.Count)); lstRectLayer.Clear(); nStartingY += nNodeHeightSize * 2; } int nLayerIndex = 0; foreach (List <Rectangle> lstRectsLayer in lstNodeBoxLayers) { int nNodeIndex = 0; foreach (Rectangle rctRectOfNode in lstRectsLayer) { int nFatherCenterX = (rctRectOfNode.Left + rctRectOfNode.Right) / 2; int nFatherCenterY = (rctRectOfNode.Top + rctRectOfNode.Bottom) / 2; int nFatherIndex = nNodeIndex; Node ndFatherNode = lstNodeLayers[nLayerIndex][nFatherIndex]; // Go through all the sons and draw the lines to them if (ndFatherNode is FunctionNode) { FunctionNode fncFatherNode = (FunctionNode)ndFatherNode; foreach (Node ndSonNode in fncFatherNode.m_arrSons) { int nSonIndex = lstNodeLayers[nLayerIndex + 1].FindIndex( delegate(Node ndNode) { if (ndNode == ndSonNode) { return(true); } else { return(false); } } ); Rectangle rctRectSonNode = lstNodeBoxLayers[nLayerIndex + 1][nSonIndex]; int nSonCenterX = (rctRectSonNode.Left + rctRectSonNode.Right) / 2; int nSonCenterY = (rctRectSonNode.Top + rctRectSonNode.Bottom) / 2; cGraphicsOnPicture.DrawLine(new Pen(LINE_COLOR), nFatherCenterX, nFatherCenterY, nSonCenterX, nSonCenterY); } } nNodeIndex++; } nLayerIndex++; } grpGraphics.DrawImageUnscaled(bmpPicture, 0, 0); bmpPicture.Dispose(); cGraphicsOnPicture.Dispose(); }