/// <summary>
        /// Finds the optimal solution2.
        /// This is my second attempt at writing a hill climbing algorithm. We should try and maximize the output first,
        /// then begin out ascent.
        /// Algorithm:
        ///		1. Find the most optimal known solution. (if we had more data, find its weighted average)
        ///		2. Apply this solution to the current P1 challenger in the ANN model.
        ///		3. If this guy doesn't win begin adjustment of values, by climbing only 1% each time.
        ///		4. Iterate through all combinations if we don't increaase in over all value, else increase that one axis.
        /// </summary>
        /// <param name="toleranceAmount">The tolerance amount.</param>
        public void FindOptimalSolution2(double toleranceAmount = 0.04)
        {
            // Get maximum known score and apply it to the new data set, If old data set is used.
            string maxPlayerVal = @"
                SELECT GameId, p1Wood, p1Food, p1Gold, p1Stone, p1Builders,
	                p2Wood, p2Food, p2Gold, p2Stone, p2Builders, 
                    (p1WoodHighest + p1FoodHighest + p1GoldHighest + p1StoneHighest) AS EconScoreP1,
                    (p2WoodHighest + p2FoodHighest + p2GoldHighest + p2StoneHighest) AS EconScoreP2
                FROM aoenn.ai_neural_network_feed
                WHERE (p2WoodHighest + p2FoodHighest + p2GoldHighest + p2StoneHighest)  = 
                (
	                SELECT MAX(p2WoodHighest + p2FoodHighest + p2GoldHighest + p2StoneHighest) AS EconScoreP2
	                FROM aoenn.ai_neural_network_feed
                );            
            ";

            double[] p1Input = null;
            int      econScoreP1;

            double[] p2Input = null;
            int      econScoreP2;

            // read sql and assign values.
            StreamUtilities.ReadSql((MySqlDataReader reader) =>
            {
                if (reader.Read())
                {
                    p1Input = new double[]
                    {
                        Convert.ToDouble(reader["p1Wood"]),
                        Convert.ToDouble(reader["p1Food"]),
                        Convert.ToDouble(reader["p1Gold"]),
                        Convert.ToDouble(reader["p1Stone"]),
                        Convert.ToDouble(reader["p1Builders"])
                    };

                    p2Input = new double[]
                    {
                        Convert.ToDouble(reader["p2Wood"]),
                        Convert.ToDouble(reader["p2Food"]),
                        Convert.ToDouble(reader["p2Gold"]),
                        Convert.ToDouble(reader["p2Stone"]),
                        Convert.ToDouble(reader["p2Builders"])
                    };

                    econScoreP1 = Convert.ToInt32(reader["EconScoreP1"]);
                    econScoreP2 = Convert.ToInt32(reader["EconScoreP2"]);
                }
            }, maxPlayerVal);

            double[] p1CurrentInputContext = new double[5];
            for (int i = 0; i < 5; i++)
            {
                p1CurrentInputContext[i] = _inputData[i];
            }

            // Seek second p1 input and find max of that, calculate the delta odds.
            double[] p1AndP2Input  = p1CurrentInputContext.Concat(p2Input).ToArray();
            double[] p1AndP2Output = _nueralNetwork.Run(p1AndP2Input);

            _logger.Error("Network Input Attempt: " + FormatDataIntoString(p1AndP2Input));

            // This is the predicted output of the aggregate, i.e. MAX or best outcome for p2.
            // this result is vital to being hill climbing!
            _logger.Error("Network Output Recieved: " + FormatDataIntoString(p1AndP2Output));

            int minIndex = 0;

            //find min index
            for (int i = 1; i < 4; i++)
            {
                if (p1AndP2Output[4 + minIndex] > p1AndP2Output[4 + minIndex])
                {
                    minIndex = i;
                }
            }

            //outputs split
            double[] p1Output =
            {
                p1AndP2Output[0], p1AndP2Output[1], p1AndP2Output[2], p1AndP2Output[3]
            };

            double[] p2Output =
            {
                p1AndP2Output[4], p1AndP2Output[5], p1AndP2Output[6], p1AndP2Output[7]
            };

            //input split
            double[] p1InputModified =
            {
                p1AndP2Input[0], p1AndP2Input[1], p1AndP2Input[2], p1AndP2Input[3], p1AndP2Input[4]
            };

            double[] p2InputModified =
            {
                p1AndP2Input[5], p1AndP2Input[6], p1AndP2Input[7], p1AndP2Input[8], p1AndP2Input[9]
            };

            //set climbing variables.
            bool   climbing   = true;
            double climbRate  = toleranceAmount / 4;
            int    climbIndex = minIndex;
            double climbedSum = SumVector(p2Output);
            int    maxAttemps = 10000;
            int    attemps    = 0;

            //some general sense of climbing.
            while (climbing && attemps < maxAttemps)
            {
                climbIndex = (climbIndex + 1) % 5;
                if (climbIndex == minIndex)
                {
                    climbIndex = (climbIndex + 1) % 5;
                }

                p2InputModified[minIndex]   += climbRate;
                p2InputModified[climbIndex] -= climbRate;

                double[] p1AndP2OutputPrime = _nueralNetwork.Run(p1InputModified.Concat(p2InputModified).ToArray());
                double   currentAttempt     = SumVector(new double[] {
                    p1AndP2OutputPrime[4], p1AndP2OutputPrime[5], p1AndP2OutputPrime[6], p1AndP2OutputPrime[7]
                });

                _logger.Error("Network Input Attempt: " + FormatDataIntoString(p1InputModified.Concat(p2InputModified).ToArray()));
                _logger.Error("Network Output Recieved: " + FormatDataIntoString(p1AndP2OutputPrime));

                if (currentAttempt < climbedSum)
                {
                    // climbing = false;
                    p2InputModified[minIndex]   -= climbRate;
                    p2InputModified[climbIndex] += climbRate;
                }

                // find new min index if next climb index is min index
                if ((climbIndex + 1) % 5 == minIndex)
                {
                    for (int i = 1; i < 5; i++)
                    {
                        if (p1AndP2OutputPrime[4 + minIndex] > p1AndP2OutputPrime[4 + minIndex])
                        {
                            minIndex = i;
                        }
                    }
                }


                attemps++;
            }

            // Write out to an output.
            double[] p1AndP2OutputFinal = _nueralNetwork.Run(p1InputModified.Concat(p2InputModified).ToArray());
            _logger.Error("Network Input Attempt: " + FormatDataIntoString(p1InputModified.Concat(p2InputModified).ToArray()));
            _logger.Error("Network Output Recieved: " + FormatDataIntoString(p1AndP2OutputFinal));
        }