/// <summary>
        /// Get the next sample value from the gaussian distribution.
        /// </summary>
        public double NextSample()
        {
            for (; ;)
            {
                // Select box at random.
                byte   u    = _rng.NextByte();
                int    i    = u & 0x7F;
                double sign = ((u & 0x80) == 0) ? -1.0 : 1.0;

                // Generate uniform random value with range [0,0xffffffff].
                uint u2 = _rng.NextUInt();

                // Special case for the base segment.
                if (0 == i)
                {
                    if (u2 < _xComp[0])
                    {   // Generated x is within R0.
                        return(u2 * __UIntToU * _A_Div_Y0 * sign);
                    }
                    // Generated x is in the tail of the distribution.
                    return(SampleTail() * sign);
                }

                // All other segments.
                if (u2 < _xComp[i])
                {   // Generated x is within the rectangle.
                    return(u2 * __UIntToU * _x[i] * sign);
                }

                // Generated x is outside of the rectangle.
                // Generate a random y coordinate and test if our (x,y) is within the distribution curve.
                // This execution path is relatively slow/expensive (makes a call to Math.Exp()) but relatively rarely executed,
                // although more often than the 'tail' path (above).
                double x = u2 * __UIntToU * _x[i];
                if (_y[i - 1] + ((_y[i] - _y[i - 1]) * _rng.NextDouble()) < GaussianPdfDenorm(x))
                {
                    return(x * sign);
                }
            }
        }
        private void SpawnPlants()
        {
            var plantAmount  = _plantInfos.CountPlants();
            var plantsInCube = 0;

            foreach (var kvp in plantAmount)
            {
                var currentPlantType = kvp.Key;
                var currentAmount    = kvp.Value;

                var rule = _zone.Configuration.PlantRules.GetPlantRule(currentPlantType);

                if (rule.HasBlockingState)
                {
                    plantsInCube += currentAmount;
                }
            }

            var tilesInCube = _area.Ground;

            var fertilityFactor = _zone.Configuration.Fertility / 100.0;

            var availablePlaces = (int)(tilesInCube * fertilityFactor);

            availablePlaces -= plantsInCube;

            var cubeFertilityState = plantsInCube / (double)tilesInCube;

            //zone fertility check
            if (cubeFertilityState > fertilityFactor)
            {
                //ok, cube is fulfilling the fertility condition
                return;
            }

            for (var i = 0; i < tilesInCube; i++)
            {
                var x = FastRandom.NextInt(_area.Width - 1);
                var y = FastRandom.NextInt(_area.Height - 1);

                var globalX = x + _area.X1;
                var globalY = y + _area.Y1;

                var plantInfo = GetPlantInfo(x, y);
                var blockInfo = GetBlockInfo(x, y);

                var plantType = plantInfo.type;

                if (plantType != 0 || blockInfo.Flags != BlockingFlags.Undefined)
                {
                    continue;
                }

                //per tile random chance
                if (FastRandom.NextByte() >= plantInfo.spawn)
                {
                    continue;
                }

                var newPlantRule = GetNewPlantRule(globalX, globalY);

                if (newPlantRule == null)
                {
                    plantInfo.Clear();
                    blockInfo.Height = 0;
                    blockInfo.Plant  = false;

                    SetPlantInfo(x, y, plantInfo);
                    SetBlockInfo(x, y, blockInfo);
                    continue;
                }

                //is there a max amount defined for the current type?
                if (newPlantRule.MaxAmount > 0)
                {
                    //have we planted enough?
                    var amount = plantAmount.GetOrDefault(newPlantRule.Type);
                    if (amount > newPlantRule.MaxAmount)
                    {
                        continue;
                    }
                }

                if (!CheckKillDistance(newPlantRule, x, y, this))
                {
                    plantInfo.Clear();
                    blockInfo.Plant  = false;
                    blockInfo.Height = 0;

                    SetPlantInfo(x, y, plantInfo);
                    SetBlockInfo(x, y, blockInfo);
                    continue;
                }

                plantInfo.type     = newPlantRule.Type;
                plantInfo.state    = 0;
                plantInfo.material = 0;                                    //no material at state0
                plantInfo.health   = newPlantRule.Health[plantInfo.state]; //set health

                blockInfo.Height = newPlantRule.GetBlockingHeight(plantInfo.state);

                if (blockInfo.Height > 0)
                {
                    blockInfo.Plant = true;
                }

                SetPlantInfo(x, y, plantInfo);
                SetBlockInfo(x, y, blockInfo);

                if (--availablePlaces <= 0)
                {
                    return;
                }
            }
        }