001 package fj.test; 002 003 import fj.F; 004 import fj.data.Option; 005 import static fj.data.Option.some; 006 007 import static java.lang.Math.max; 008 import static java.lang.Math.min; 009 import java.util.Random; 010 011 /** 012 * A random number generator. 013 * 014 * @version %build.number%<br> 015 * <ul> 016 * <li>$LastChangedRevision: 5 $</li> 017 * <li>$LastChangedDate: 2008-12-06 16:49:43 +1000 (Sat, 06 Dec 2008) $</li> 018 * <li>$LastChangedBy: tonymorris $</li> 019 * </ul> 020 */ 021 public final class Rand { 022 private final F<Option<Long>, F<Integer, F<Integer, Integer>>> f; 023 private final F<Option<Long>, F<Double, F<Double, Double>>> g; 024 025 private Rand(final F<Option<Long>, F<Integer, F<Integer, Integer>>> f, final F<Option<Long>, F<Double, F<Double, Double>>> g) { 026 this.f = f; 027 this.g = g; 028 } 029 030 /** 031 * Randomly chooses a value between the given range (inclusive). 032 * 033 * @param seed The seed to use for random generation. 034 * @param from The minimum value to choose. 035 * @param to The maximum value to choose. 036 * @return A random value in the given range. 037 */ 038 public int choose(final long seed, final int from, final int to) { 039 return f.f(some(seed)).f(from).f(to); 040 } 041 042 /** 043 * Randomly chooses a value between the given range (inclusive). 044 * 045 * @param from The minimum value to choose. 046 * @param to The maximum value to choose. 047 * @return A random value in the given range. 048 */ 049 public int choose(final int from, final int to) { 050 return f.f(Option.<Long>none()).f(from).f(to); 051 } 052 053 /** 054 * Randomly chooses a value between the given range (inclusive). 055 * 056 * @param seed The seed to use for random generation. 057 * @param from The minimum value to choose. 058 * @param to The maximum value to choose. 059 * @return A random value in the given range. 060 */ 061 public double choose(final long seed, final double from, final double to) { 062 return g.f(some(seed)).f(from).f(to); 063 } 064 065 /** 066 * Randomly chooses a value between the given range (inclusive). 067 * 068 * @param from The minimum value to choose. 069 * @param to The maximum value to choose. 070 * @return A random value in the given range. 071 */ 072 public double choose(final double from, final double to) { 073 return g.f(Option.<Long>none()).f(from).f(to); 074 } 075 076 /** 077 * Gives this random generator a new seed. 078 * 079 * @param seed The seed of the new random generator. 080 * @return A random generator with the given seed. 081 */ 082 public Rand reseed(final long seed) { 083 return new Rand(new F<Option<Long>, F<Integer, F<Integer, Integer>>>() { 084 public F<Integer, F<Integer, Integer>> f(final Option<Long> old) { 085 return new F<Integer, F<Integer, Integer>>() { 086 public F<Integer, Integer> f(final Integer from) { 087 return new F<Integer, Integer>() { 088 public Integer f(final Integer to) { 089 return f.f(some(seed)).f(from).f(to); 090 } 091 }; 092 } 093 }; 094 } 095 }, new F<Option<Long>, F<Double, F<Double, Double>>>() { 096 public F<Double, F<Double, Double>> f(final Option<Long> old) { 097 return new F<Double, F<Double, Double>>() { 098 public F<Double, Double> f(final Double from) { 099 return new F<Double, Double>() { 100 public Double f(final Double to) { 101 return g.f(some(seed)).f(from).f(to); 102 } 103 }; 104 } 105 }; 106 } 107 }); 108 } 109 110 /** 111 * Constructs a random generator from the given functions that supply a range to produce a 112 * result. 113 * 114 * @param f The integer random generator. 115 * @param g The floating-point random generator. 116 * @return A random generator from the given functions that supply a range to produce a result. 117 */ 118 public static Rand rand(final F<Option<Long>, F<Integer, F<Integer, Integer>>> f, final F<Option<Long>, F<Double, F<Double, Double>>> g) { 119 return new Rand(f, g); 120 } 121 122 123 private static final F<Long, Random> fr = new F<Long, Random>() { 124 public Random f(final Long x) { 125 return new Random(x); 126 } 127 }; 128 129 /** 130 * A standard random generator that uses {@link Random}. 131 */ 132 public static final Rand standard = new Rand(new F<Option<Long>, F<Integer, F<Integer, Integer>>>() { 133 public F<Integer, F<Integer, Integer>> f(final Option<Long> seed) { 134 return new F<Integer, F<Integer, Integer>>() { 135 public F<Integer, Integer> f(final Integer from) { 136 return new F<Integer, Integer>() { 137 public Integer f(final Integer to) { 138 final int f = min(from, to); 139 final int t = max(from, to); 140 return f + seed.map(fr).orSome(new Random()).nextInt(t - f + 1); 141 } 142 }; 143 } 144 }; 145 } 146 }, new F<Option<Long>, F<Double, F<Double, Double>>>() { 147 public F<Double, F<Double, Double>> f(final Option<Long> seed) { 148 return new F<Double, F<Double, Double>>() { 149 public F<Double, Double> f(final Double from) { 150 return new F<Double, Double>() { 151 public Double f(final Double to) { 152 final double f = min(from, to); 153 final double t = max(from, to); 154 return seed.map(fr).orSome(new Random()).nextDouble() * (t - f) + f; 155 } 156 }; 157 } 158 }; 159 } 160 }); 161 }