public Individual mutate()
        {
            /*
             * randomly choose a node and swap it with randomly generated tree with max depth of 3
             * (not a full tree)
             */
            int        randNum;
            Individual mutatedIndividual = new Individual(this);
            const int  MIN            = 2;
            Node       mutateNode     = null;
            Node       mutateNodeSwap = null;

            randNum    = rnd.Next(this.getStrategyRoot().countNodes() - MIN + 1) + MIN;
            mutateNode = mutatedIndividual.getStrategyRoot().getNode(mutatedIndividual.getStrategyRoot(), randNum - 1);

            if (mutateNode.GetType() == typeof(Terminal))
            {
                // if the selected node is a terminal,
                // set it to another random terminal
                ((Terminal)mutateNode).setRandTerminal();
            }
            else
            {
                // if the selected node is a function,
                // generate a random tree (not full) of max depth of 3 and swap the nodes

                // need to research other sizes of random generated mutation tree
                mutateNodeSwap = Node.generateFullTree(3, board, this);
                mutatedIndividual.getStrategyRoot().swapNodes(mutateNode, mutateNodeSwap);
            }
            return(mutatedIndividual);
        }
        public Individual[] crossover(Individual otherIndividual)
        {
            /*
             * crossover function
             * clone both parent (the clones will be the new children after the crossover operation)
             * randomly choose a node from each cloned parent
             * swap the nodes
             */
            int       randNum;
            const int MIN = 2;

            Individual[] children = new Individual[2];
            children[0] = new Individual(this);
            children[1] = new Individual(otherIndividual);
            // Node objects to temporary hold the returned references
            Node swap1 = null;
            Node swap2 = null;

            // randomize a number ranging from 2....nodesAmount of first parent

            randNum = rnd.Next(children[0].getStrategyRoot().countNodes() - MIN + 1) + MIN;
            // paint the selected nodes at the original first parent
            this.getStrategyRoot().getNode(this.getStrategyRoot(), randNum).paintNode(Color.Red);
            // get the first random node reference
            swap1 = children[0].getStrategyRoot().getNode(children[0].getStrategyRoot(), randNum);
            // randomize a number ranging from 2....nodesAmount of second parent
            randNum = rnd.Next(children[1].getStrategyRoot().countNodes() - MIN + 1) + MIN;
            // paint the selected nodes at the original second parent
            otherIndividual.getStrategyRoot().getNode(otherIndividual.getStrategyRoot(), randNum).paintNode(Color.Red);
            // get the second random node reference
            swap2 = children[1].getStrategyRoot().getNode(children[1].getStrategyRoot(), randNum);

            // paint the swapped nodes
            swap1.paintNode(Color.Green);
            swap2.paintNode(Color.Green);

            // make the reference swaps
            //		System.out.println("Swapping " + swap1.TreeStr() + " with " + swap2.TreeStr() + " node #" + temp);
            children[0].getStrategyRoot().swapNodes(swap1, swap2);
            //		System.out.println("Swapping " + swap2.TreeStr() + " with " + swap1.TreeStr() + " node #" + randNum);
            children[1].getStrategyRoot().swapNodes(swap2, swap1);
            return(children);
        }
        public Individual crossover2(Individual otherIndividual)
        {
            /*
             * crossover function
             * clone both parent (the clones will be the new children after the crossover operation)
             * randomly choose a node from each cloned parent
             * swap the nodes
             */
            int       randNum;
            const int MIN = 2;
            // Node objects to temporary hold the returned references
            Node swap1 = null;
            Node swap2 = null;

            // randomize a number ranging from 2....nodesAmount of first parent
            randNum = rnd.Next(this.getStrategyRoot().countNodes() - MIN + 1) + MIN;
            // paint the selected nodes at the original first parent
            this.getStrategyRoot().getNode(this.getStrategyRoot(), randNum).paintNode(Color.Red);
            // get the first random node reference
            swap1 = this.getStrategyRoot().getNode(this.getStrategyRoot(), randNum);
            // randomize a number ranging from 2....nodesAmount of second parent
            randNum = rnd.Next(otherIndividual.getStrategyRoot().countNodes() - MIN + 1) + MIN;
            // paint the selected nodes at the original second parent
            otherIndividual.getStrategyRoot().getNode(otherIndividual.getStrategyRoot(), randNum).paintNode(Color.Red);
            // get the second random node reference
            swap2 = otherIndividual.getStrategyRoot().getNode(otherIndividual.getStrategyRoot(), randNum);

            // paint the swapped nodes
            swap1.paintNode(Color.Green);
            swap2.paintNode(Color.Green);

            // make the reference swaps
            this.getStrategyRoot().swapNodes(swap1, swap2.copy(swap2));

            // combine the parents name to create a new name
            this.setPlayerName(otherIndividual.getPlayerName());
            return(this);
        }