/********************************************************************************* * TotalCross Software Development Kit * * Copyright (C) 2001 Sean Luke <seanl@cs.umd.edu> * * Copyright (C) 2001-2012 SuperWaba Ltda. * * All Rights Reserved * * * * This library and virtual machine 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. * * * * This file is covered by the GNU LESSER GENERAL PUBLIC LICENSE VERSION 3.0 * * A copy of this license is located in file license.txt at the root of this * * SDK or can be downloaded here: * * http://www.gnu.org/licenses/lgpl-3.0.txt * * * *********************************************************************************/ package totalcross.util; /** This is a simple Linear Congruential Generator which produces random numbers in the range [0,2^31), derived from ran0 in Numerical Recipies. Note that ran0 isn't wonderfully random -- there are much better generators out there -- but it'll do the job, and it's fast and has low memory consumption. <p> Here's a sample of how to use the Random class: <pre> Random r = new Random(0x1234); // the use of the same key is sometimes desirable for (...) { int nextRandomInt = r.between(0,10); char nextRandomChar = r.between('a','z'); ... } </pre> */ public class Random { // Do NOT modify IA, IM, IQ, or IR // You are free to set ZERO_SEED_REPLACEMENT to any integer // greater than 0 (but NOT including 0!!) private static final int IA = 16807; private static final int IM = 2147483647; private static final int IQ = 127773; private static final int IR = 2836; private static final int ZERO_SEED_REPLACEMENT = 234123; // whatever private int seed; /** The only reasonable seeds are between 0 and 2^31 inclusive; if you're negative, it'll get the absolute value of it. */ public Random(int _seed) { // strip out the minus-sign if any seed = (_seed << 1) >>> 1; // if seed is 0, it's invalid, we need another seed if (seed==0) seed = ZERO_SEED_REPLACEMENT; } /** Randomizes based on the current timestamp */ public Random() { totalcross.sys.Time t = new totalcross.sys.Time(); // guich@300_30 seed = t.hour*60*60 + t.minute*60 + t.second + 100*t.millis; // hope this value never gets < 0 ! } /** Bits should be <= 31 */ protected int next(final int bits) { int k = seed/IQ; seed = IA*(seed-k*IQ)-IR*k; if (seed < 0) seed += IM; return seed >> (31-bits); } /** Returns a double floating-point value in the half-open range [0,1). */ public double nextDouble() { return next(24) / (double)(1 << 24); } /** Returns an integer in the range [0,n). * n must be > 0, else -1 is returned. * @see #between(char, char) * @see #between(int, int) */ public int nextInt(int n) { if (n<=0) return -1; int bits, val; do { bits = next(31); val = bits % n; } while(bits - val + (n-1) < 0); return val; } // guich@200b4_3 /** Returns a random character between the given region. * Eg: between('a', 'e') returns a random character between 'a' and 'e'. * @param s the start character in the range * @param e the ending character in the range */ public char between(char s, char e) { return (char)between((int)(s), (int)(e)); } // guich@200b4_3 /** Returns random integer in the given region. * Eg: rand(1, 10) returns a random integer in the range of 1 to 10, inclusive. * Note that if s == e, it will return in the range s and e+1. * @param s the start number in the range * @param e the ending number in the range */ public int between(int s, int e) { if (s > e) { int t = e; e = s; s = t; } else if (s == e) e++; return s + nextInt(e - s + 1); } }