/// <summary>
        /// Calculates a range for a target beta.
        /// </summary>
        ///
        /// <param name="theta"> The theta. </param>
        ///
        /// <returns>
        /// A two-element  array with min and max values of ratings.
        /// </returns>
        private double[] calcTargetBetas(double theta)
        {
            double[] randNums = new double[2];

            for (int index = 0; index < randNums.Length; index++)
            {
                double rndNum;
                do
                {
                    SimpleRNG.SetSeedFromRandom();
                    rndNum = SimpleRNG.GetNormal(TARGET_DISTR_MEAN, TARGET_DISTR_SD);
                } while (rndNum <= TARGET_LOWER_LIMIT || rndNum >= TARGET_UPPER_LIMIT || rndNum == 1 || rndNum == 0); // [SC][2016.03.14] || randomNum == 1 || randomNum == 0
                randNums[index] = rndNum;
            }

            Array.Sort(randNums);

            // [SC][2016.10.07] this is the old equation to calculate target beta
            // theta + Math.Log(randomNum / (1 - randomNum));

            double minBeta = theta + Math.Log((1 - randNums[1]) / randNums[1]); // [SC][2016.10.07] a modified version of the equation from the original data; better suits the data
            double maxBeta = theta + Math.Log((1 - randNums[0]) / randNums[0]);

            return(new double[] { minBeta, maxBeta });
        }
        //////////////////////////////////////////////////////////////////////////////////////
        ////// START: functions for calculating matching scenario
        #region functions for calculating matching scenario

        /// <summary>
        /// Calculates expected beta for target scenario. Returns ID of a scenario with beta closest to the target beta.
        /// If two more scenarios match then scenario that was least played is chosen.
        /// </summary>
        ///
        /// <exception cref="ArgumentException">    Thrown when one or more arguments
        ///                                         have unsupported or illegal values. </exception>
        ///
        /// <param name="gameID">   Identifier for the game. </param>
        /// <param name="playerID"> Identifier for the player. </param>
        ///
        /// <returns>
        /// A string.
        /// </returns>
        internal string TargetScenarioID(string gameID, string playerID)   // [SC][2016.03.14] CalculateTargetScenarioID => TargetScenarioID
        // [SC] get player rating.
        // [2016.11.14] modified
        {
            double playerRating = asset.PlayerRating(ADAPTER_TYPE, gameID, playerID); // [ASSET]

            // [SC] get IDs of available scenarios
            List <string> scenarioIDList = asset.AllScenariosIDs(ADAPTER_TYPE, gameID); // [ASSET]

            if (scenarioIDList.Count == 0)
            {
                throw new System.ArgumentException("No scenarios found for adaptation " + ADAPTER_TYPE + " in game " + gameID);
            }

            // [SC] calculate min and max possible ratings for candidate scenarios
            double[] minMaxRatings = calcTargetBetas(playerRating); // [SC][2016.12.07] modified

            // [SC] info for the scenarios within the min/max rating range and with the lowest play count
            List <string> inScenarioID   = new List <string>();
            double        inMinPlayCount = 0;

            // [SC] info for the closest scenarios outside of the min/max rating range and the lowest play count
            List <string> outScenarioID   = new List <string>();
            double        outMinPlayCount = 0;
            double        outMinDistance  = 0;

            // [SC] iterate through the list of all scenarios
            foreach (string scenarioID in scenarioIDList)
            {
                if (String.IsNullOrEmpty(scenarioID))
                {
                    throw new System.ArgumentException("Null scenario ID found for adaptation " + ADAPTER_TYPE + " in game " + gameID);
                }

                // [2016.11.14] modified
                double scenarioRating    = asset.ScenarioRating(ADAPTER_TYPE, gameID, scenarioID);    // [ASSET]
                double scenarioPlayCount = asset.ScenarioPlayCount(ADAPTER_TYPE, gameID, scenarioID); // [ASSET]

                // [SC] the scenario rating is within min/max rating range
                if (scenarioRating >= minMaxRatings[0] && scenarioRating <= minMaxRatings[1])
                {
                    if (inScenarioID.Count == 0 || scenarioPlayCount < inMinPlayCount)
                    {
                        inScenarioID.Clear();
                        inScenarioID.Add(scenarioID);
                        inMinPlayCount = scenarioPlayCount;
                    }
                    else if (scenarioPlayCount == inMinPlayCount)
                    {
                        inScenarioID.Add(scenarioID);
                    }
                }
                else   // [SC] the scenario rating is outside of the min/max rating range
                {
                    double distance = Math.Min(Math.Abs(scenarioRating - minMaxRatings[0]), Math.Abs(scenarioRating - minMaxRatings[1]));
                    if (outScenarioID.Count == 0 || distance < outMinDistance)
                    {
                        outScenarioID.Clear();
                        outScenarioID.Add(scenarioID);
                        outMinDistance  = distance;
                        outMinPlayCount = scenarioPlayCount;
                    }
                    else if (distance == outMinDistance && scenarioPlayCount < outMinPlayCount)
                    {
                        outScenarioID.Clear();
                        outScenarioID.Add(scenarioID);
                        outMinPlayCount = scenarioPlayCount;
                    }
                    else if (distance == outMinDistance && scenarioPlayCount == outMinPlayCount)
                    {
                        outScenarioID.Add(scenarioID);
                    }
                }
            }

            if (inScenarioID.Count() > 0)
            {
                return(inScenarioID[SimpleRNG.Next(inScenarioID.Count())]);
            }

            return(outScenarioID[SimpleRNG.Next(outScenarioID.Count())]);
        }