/*  Copyright (C) 2008--2010 Joshua Judson Rosen <rozzin@geekspace.com>.

    This program is free software: you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    version 3 as published by the Free Software Foundation.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; see the file COPYING. If not, see
    <http://www.gnu.org/licenses/> or write to:

        The Free Software Foundation, inc.
        51 Franklin Street, Fifth Floor
        Boston, MA 02110-1301
        USA
*/

#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <glib/grand.h>
#include <glib/gmem.h>
#include "random.h"

void
virand_set_seed_string (GRand *state, const char *seed, size_t seed_length)
{
  size_t overflow = (seed_length % 4);
  size_t delta = 4 - overflow;  /* always pad; 4-0 makes null strings usable. */
  size_t seed4_length = seed_length + delta;
  char *seed4 = g_malloc (seed4_length);

  memcpy (seed4, seed, seed_length);
  memset (seed4+seed_length, 0, delta);

  g_rand_set_seed_array (state, (guint32 *) seed4, (seed_length+delta)/4);

  g_free (seed4);
}

double
virand_range_biased (GRand *state, double base, double limit, double bias_expt)
{
  double range = limit - base;

  return base + (range * pow (g_rand_double (state), bias_expt));
}

gboolean
virand_prob (GRand *state, double probability)
{
  return g_rand_double (state) < probability;
}

gboolean
virand_prob_reduced (GRand *state, double probability, int level)
{
  int nsteps = 6;

  /* probability decreases linearly with as level increases,
     by 1 step each level, down to a minimum of 1/nsteps
     of the specified value: */

  probability *= fmax (nsteps-level, 1) / nsteps;

  return virand_prob (state, probability);
}

double
virand_rational (GRand *state, int low, int high, int denominator)
{
  return round (g_rand_double_range (state, low, high)) / denominator;
}

