Parcourir la source

Remove stuff that I don't use, to weightwatcher RNG

smelc il y a 6 ans
Parent
commit
49ed3ae6dd

+ 3 - 72
squidlib-util/src/main/java/squidpony/squidgrid/Radius.java

@@ -1,14 +1,12 @@
 package squidpony.squidgrid;
 
-import squidpony.squidmath.Coord;
-import squidpony.squidmath.Coord3D;
-import squidpony.squidmath.OrderedSet;
-import squidpony.squidmath.RNG;
-
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
 
+import squidpony.squidmath.Coord;
+import squidpony.squidmath.OrderedSet;
+
 /**
  * Basic radius strategy implementations likely to be used for roguelikes.
  *
@@ -122,73 +120,6 @@ public enum Radius {
         return radius(dx, dy, 0);
     }
 
-    public Coord onUnitShape(double distance, RNG rng) {
-        int x = 0, y = 0;
-        switch (this) {
-            case SQUARE:
-            case CUBE:
-                x = rng.between((int) -distance, (int) distance + 1);
-                y = rng.between((int) -distance, (int) distance + 1);
-                break;
-            case DIAMOND:
-            case OCTAHEDRON:
-                x = rng.between((int) -distance, (int) distance + 1);
-                y = rng.between((int) -distance, (int) distance + 1);
-                if (radius(x, y) > distance) {
-                    if (x > 0) {
-                        if (y > 0) {
-                            x = (int) (distance - x);
-                            y = (int) (distance - y);
-                        } else {
-                            x = (int) (distance - x);
-                            y = (int) (-distance - y);
-                        }
-                    } else {
-                        if (y > 0) {
-                            x = (int) (-distance - x);
-                            y = (int) (distance - y);
-                        } else {
-                            x = (int) (-distance - x);
-                            y = (int) (-distance - y);
-                        }
-                    }
-                }
-                break;
-            case CIRCLE:
-            case SPHERE:
-                double radius = distance * Math.sqrt(rng.between(0.0, 1.0));
-                double theta = rng.between(0, PI2);
-                x = (int) Math.round(Math.cos(theta) * radius);
-                y = (int) Math.round(Math.sin(theta) * radius);
-        }
-
-        return Coord.get(x, y);
-    }
-
-    public Coord3D onUnitShape3D(double distance, RNG rng) {
-        int x = 0, y = 0, z = 0;
-        switch (this) {
-            case SQUARE:
-            case DIAMOND:
-            case CIRCLE:
-                Coord p = onUnitShape(distance, rng);
-                return new Coord3D(p.x, p.y, 0);//2D strategies
-            case CUBE:
-                x = rng.between((int) -distance, (int) distance + 1);
-                y = rng.between((int) -distance, (int) distance + 1);
-                z = rng.between((int) -distance, (int) distance + 1);
-                break;
-            case OCTAHEDRON:
-            case SPHERE:
-                do {
-                    x = rng.between((int) -distance, (int) distance + 1);
-                    y = rng.between((int) -distance, (int) distance + 1);
-                    z = rng.between((int) -distance, (int) distance + 1);
-                } while (radius(x, y, z) > distance);
-        }
-
-        return new Coord3D(x, y, z);
-    }
     public double volume2D(double radiusLength)
     {
         switch (this) {

+ 0 - 430
squidlib-util/src/main/java/squidpony/squidgrid/Spill.java

@@ -1,430 +0,0 @@
-package squidpony.squidgrid;
-
-import squidpony.squidmath.*;
-
-import java.util.ArrayList;
-import java.util.Set;
-/**
- * A randomized flood-fill implementation that can be used for level generation (e.g. filling ponds and lakes), for
- * gas propagation, or for all sorts of fluid-dynamics-on-the-cheap.
- * Created by Tommy Ettinger on 4/7/2015.
- * 
- * @see Splash An alternative implementation with a lighter API
- */
-public class Spill {
-    /**
-     * The type of heuristic to use.
-     */
-    public enum Measurement {
-
-        /**
-         * The distance it takes when only the four primary directions can be
-         * moved in. The default.
-         */
-        MANHATTAN,
-        /**
-         * The distance it takes when diagonal movement costs the same as
-         * cardinal movement.
-         */
-        CHEBYSHEV,
-        /**
-         * The distance it takes as the crow flies.
-         */
-        EUCLIDEAN
-    }
-
-    /**
-     * This affects how distance is measured on diagonal directions vs. orthogonal directions. MANHATTAN should form a
-     * diamond shape on a featureless map, while CHEBYSHEV and EUCLIDEAN will form a square. If you only call
-     * Spill.start() once, you should strongly prefer MANHATTAN, even if the rest of the game uses another
-     * measurement, because CHEBYSHEV and EUCLIDEAN can produce odd, gap-filled flood-fills.  Any case where you have
-     * too many gaps can be corrected to varying extent by calling start() more than once with slowly increasing values.
-     * Because start() will extend from the existing area of the Spill, holes are likely to be filled after a few calls,
-     * but if the last call to start() tries to fill too many more cells than the previous one, it can cause holes on
-     * the periphery of the Spill area.
-     */
-    public Measurement measurement = Measurement.MANHATTAN;
-
-
-    /**
-     * Stores which parts of the map are accessible (with a value of true) and which are not (with a value of false,
-     * including both walls and unreachable sections of the map). Should not be changed unless the actual physical
-     * terrain has changed. You should call initialize() with a new map instead of changing this directly.
-     */
-    public boolean[][] physicalMap;
-    /**
-     * The cells that are filled by the Spill when it reaches its volume or limits will be true; others will be false.
-     */
-    public boolean[][] spillMap;
-
-    /**
-     * The list of points that the Spill will randomly fill, starting with what is passed to start(), in order of when
-     * they are reached.
-     */
-    public ArrayList<Coord> spreadPattern;
-    /**
-     * Height of the map. Exciting stuff. Don't change this, instead call initialize().
-     */
-    public int height;
-    /**
-     * Width of the map. Exciting stuff. Don't change this, instead call initialize().
-     */
-    public int width;
-    /**
-     * The amount of cells filled by this Spill, which may be less than the volume passed to start() if the boundaries
-     * are reached on all sides and the Spill has no more room to fill.
-     */
-    public int filled = 0;
-    private OrderedSet<Coord> fresh;
-    /**
-     * The RNG used to decide which one of multiple equally-short paths to take.
-     */
-    public StatefulRNG rng;
-    /**
-     * The LightRNG used as a RandomnessSource for the RNG this object uses. Can have its state read and set.
-     */
-    public LightRNG lrng;
-
-    private boolean initialized = false;
-    /**
-     * Construct a Spill without a level to actually scan. If you use this constructor, you must call an
-     * initialize() method before using this class.
-     */
-    public Spill() {
-        lrng = new LightRNG();
-        rng = new StatefulRNG(lrng);
-
-        fresh = new OrderedSet<>();
-    }
-    /**
-     * Construct a Spill without a level to actually scan. This constructor allows you to specify an RNG, but the actual
-     * RandomnessSource the RNG that this object uses will not be identical to the one passed as random (64 bits will
-     * be requested from the passed RNG, and that will be used to seed this class' RNG).
-     *
-     * If you use this constructor, you must call an  initialize() method before using this class.
-     */
-    public Spill(RNG random) {
-        lrng = new LightRNG(random.nextLong());
-        rng = new StatefulRNG(lrng);
-
-        fresh = new OrderedSet<>();
-    }
-
-    /**
-     * Construct a Spill without a level to actually scan. This constructor allows you to specify a RandomnessSource
-     * in the form of a LightRNG, which will be referenced in this class (if the state of random changes because this
-     * object needed a random number, the state change will be reflected in the code that passed random to here).
-     *
-     * If you use this constructor, you must call an  initialize() method before using this class.
-     */
-    public Spill(LightRNG random) {
-        lrng = random;
-        rng = new StatefulRNG(lrng);
-
-        fresh = new OrderedSet<>();
-    }
-
-    /**
-     * Used to construct a Spill from the output of another.
-     * @param level
-     */
-    public Spill(final boolean[][] level) {
-        lrng = new LightRNG();
-        rng = new StatefulRNG(lrng);
-
-        initialize(level);
-    }
-    /**
-     * Used to construct a Spill from the output of another, specifying a distance calculation.
-     * @param level
-     * @param measurement
-     */
-    public Spill(final boolean[][] level, Measurement measurement) {
-        lrng = new LightRNG();
-        rng = new StatefulRNG(lrng);
-
-        this.measurement = measurement;
-
-        initialize(level);
-    }
-
-    /**
-     * Constructor meant to take a char[][] returned by DungeonGen.generate(), or any other
-     * char[][] where '#' means a wall and anything else is a walkable tile. If you only have
-     * a map that uses box-drawing characters, use DungeonUtility.linesToHashes() to get a
-     * map that can be used here.
-     *
-     * @param level
-     */
-    public Spill(final char[][] level) {
-        lrng = new LightRNG();
-        rng = new StatefulRNG(lrng);
-
-        initialize(level);
-    }
-    /**
-     * Constructor meant to take a char[][] returned by DungeonGen.generate(), or any other
-     * char[][] where one char means a wall and anything else is a walkable tile. If you only have
-     * a map that uses box-drawing characters, use DungeonUtility.linesToHashes() to get a
-     * map that can be used here. You can specify the character used for walls.
-     *
-     * @param level
-     */
-    public Spill(final char[][] level, char alternateWall) {
-        lrng = new LightRNG();
-        rng = new StatefulRNG(lrng);
-
-        initialize(level, alternateWall);
-    }
-
-    /**
-     * Constructor meant to take a char[][] returned by DungeonGen.generate(), or any other
-     * char[][] where '#' means a wall and anything else is a walkable tile. If you only have
-     * a map that uses box-drawing characters, use DungeonUtility.linesToHashes() to get a
-     * map that can be used here. This constructor specifies a distance measurement.
-     *
-     * @param level
-     * @param measurement
-     */
-    public Spill(final char[][] level, Measurement measurement) {
-        lrng = new LightRNG();
-        rng = new StatefulRNG(lrng);
-        this.measurement = measurement;
-
-        initialize(level);
-    }
-    /**
-     * Constructor meant to take a char[][] returned by DungeonGen.generate(), or any other
-     * char[][] where '#' means a wall and anything else is a walkable tile. If you only have
-     * a map that uses box-drawing characters, use DungeonUtility.linesToHashes() to get a
-     * map that can be used here. This constructor specifies a distance measurement.
-     *
-     * This constructor allows you to specify an RNG, but the actual RandomnessSource the RNG that this object uses
-     * will not be identical to the one passed as random (64 bits will be requested from the passed RNG, and that will
-     * be used to seed this class' RNG).
-     *
-     * @param level
-     * @param measurement
-     */
-    public Spill(final char[][] level, Measurement measurement, RNG random) {
-        lrng = new LightRNG(random.nextLong());
-        rng = new StatefulRNG(lrng);
-        this.measurement = measurement;
-
-        initialize(level);
-    }
-    /**
-     * Constructor meant to take a char[][] returned by DungeonGen.generate(), or any other
-     * char[][] where '#' means a wall and anything else is a walkable tile. If you only have
-     * a map that uses box-drawing characters, use DungeonUtility.linesToHashes() to get a
-     * map that can be used here. This constructor specifies a distance measurement.
-     *
-     * This constructor allows you to specify a RandomnessSource in the form of a LightRNG, which will be referenced in
-     * this class (if the state of random changes because this object needed a random number, the state change will be
-     * reflected in the code that passed random to here).
-     * @param level
-     * @param measurement
-     */
-    public Spill(final char[][] level, Measurement measurement, LightRNG random) {
-        lrng = random;
-        rng = new StatefulRNG(lrng);
-        this.measurement = measurement;
-
-        initialize(level);
-    }
-
-    /**
-     * Used to initialize or re-initialize a Spill that needs a new PhysicalMap because it either wasn't given
-     * one when it was constructed, or because the contents of the terrain have changed permanently (not if a
-     * creature moved; for that you pass the positions of creatures that block paths to scan() or findPath() ).
-     * @param level
-     * @return
-     */
-    public Spill initialize(final boolean[][] level) {
-        fresh = new OrderedSet<>();
-        width = level.length;
-        height = level[0].length;
-        spillMap = new boolean[width][height];
-        physicalMap = new boolean[width][height];
-        for (int y = 0; y < height; y++) {
-            for (int x = 0; x < width; x++) {
-                spillMap[x][y] = level[x][y];
-                physicalMap[x][y] = level[x][y];
-            }
-        }
-        initialized = true;
-        return this;
-    }
-
-    /**
-     * Used to initialize or re-initialize a Spill that needs a new PhysicalMap because it either wasn't given
-     * one when it was constructed, or because the contents of the terrain have changed permanently (not if a
-     * creature moved; for that you pass the positions of creatures that block paths to scan() or findPath() ).
-     * @param level
-     * @return
-     */
-    public Spill initialize(final char[][] level) {
-        fresh = new OrderedSet<>();
-        width = level.length;
-        height = level[0].length;
-        spillMap = new boolean[width][height];
-        physicalMap = new boolean[width][height];
-        for (int y = 0; y < height; y++) {
-            for (int x = 0; x < width; x++) {
-                spillMap[x][y] = false;
-                physicalMap[x][y] = level[x][y] != '#';
-            }
-        }
-        initialized = true;
-        return this;
-    }
-
-    /**
-     * Used to initialize or re-initialize a Spill that needs a new PhysicalMap because it either wasn't given
-     * one when it was constructed, or because the contents of the terrain have changed permanently (not if a
-     * creature moved; for that you pass the positions of creatures that block paths to scan() or findPath() ). This
-     * initialize() method allows you to specify an alternate wall char other than the default character, '#' .
-     * @param level
-     * @param alternateWall
-     * @return
-     */
-    public Spill initialize(final char[][] level, char alternateWall) {
-        fresh = new OrderedSet<>();
-        width = level.length;
-        height = level[0].length;
-        spillMap = new boolean[width][height];
-        physicalMap = new boolean[width][height];
-        for (int y = 0; y < height; y++) {
-            for (int x = 0; x < width; x++) {
-                spillMap[x][y] = false;
-                physicalMap[x][y] = level[x][y] != alternateWall;
-            }
-        }
-        initialized = true;
-        return this;
-    }
-
-    /**
-     * Resets the spillMap to being empty.
-     */
-    public void resetMap() {
-        if(!initialized) return;
-        for (int y = 0; y < height; y++) {
-            for (int x = 0; x < width; x++) {
-                spillMap[x][y] = false;
-            }
-        }
-    }
-
-    /**
-     * Resets this Spill to a state with an empty spillMap and an empty spreadPattern.
-     */
-    public void reset() {
-        resetMap();
-        spreadPattern.clear();
-        fresh.clear();
-    }
-
-    /**
-     * Reverts a cell to an unfilled state (false in spillMap).
-     * @param x
-     * @param y
-     */
-    public void resetCell(int x, int y) {
-        if(!initialized) return;
-        spillMap[x][y] = false;
-    }
-
-    /**
-     * Reverts a cell to an unfilled state (false in spillMap).
-     * @param pt
-     */
-    public void resetCell(Coord pt) {
-        if(!initialized) return;
-        spillMap[pt.x][pt.y] = false;
-    }
-
-    protected void setFresh(int x, int y) {
-        if(!initialized) return;
-        fresh.add(Coord.get(x, y));
-    }
-
-    protected void setFresh(final Coord pt) {
-        if(!initialized) return;
-        fresh.add(pt);
-    }
-
-    /**
-     * Recalculate the spillMap and return the spreadPattern. The cell corresponding to entry will be true,
-     * the cells near that will be true if chosen at random from all passable cells adjacent to a
-     * filled (true) cell, and all other cells will be false. This takes a total number of cells to attempt
-     * to fill (the volume parameter), and will fill less if it has completely exhausted all passable cells.
-     * If the measurement this Spill uses is anything other than MANHATTAN, you can expect many gaps in the first
-     * filled area.  Subsequent calls to start() with the same entry and a higher volume will expand the area
-     * of the Spill, and are likely to fill any gaps after a few subsequent calls. Increasing the volume slowly
-     * is the best way to ensure that gaps only exist on the very edge if you use a non-MANHATTAN measurement.
-     *
-     * @param entry The first cell to spread from, which should really be passable.
-     * @param volume The total number of cells to attempt to fill, which must be non-negative.
-     * @param impassable A Set of Position keys representing the locations of moving obstacles to a
-     *                   path that cannot be moved through; this can be null if there are no such obstacles.
-     * @return An ArrayList of Points that this will enter, in order starting with entry at index 0, until it
-     * reaches its volume or fills its boundaries completely.
-     */
-    public ArrayList<Coord> start(Coord entry, int volume, Set<Coord> impassable) {
-        if(!initialized) return null;
-        if(impassable == null)
-            impassable = new OrderedSet<>();
-        if(!physicalMap[entry.x][entry.y] || impassable.contains(entry))
-            return null;
-        spreadPattern = new ArrayList<>(volume);
-        spillMap[entry.x][entry.y] = true;
-        Coord temp;
-        for(int x = 0; x < spillMap.length; x++)
-        {
-            for(int y = 0; y < spillMap[x].length; y++)
-            {
-                temp = Coord.get(x, y);
-                if(spillMap[x][y] && !impassable.contains(temp))
-                    fresh.add(temp);
-            }
-        }
-
-        Direction[] dirs = (measurement == Measurement.MANHATTAN) ? Direction.CARDINALS : Direction.OUTWARDS;
-        while (!fresh.isEmpty() && spreadPattern.size() < volume) {
-            Coord cell = fresh.randomItem(rng);//toArray(new Coord[fresh.size()])[rng.nextInt(fresh.size())];
-            spreadPattern.add(cell);
-            spillMap[cell.x][cell.y] = true;
-            for (int d = 0; d < dirs.length; d++) {
-                Coord adj = cell.translate(dirs[d].deltaX, dirs[d].deltaY);
-                double h = heuristic(dirs[d]);
-                if (physicalMap[adj.x][adj.y] && !spillMap[adj.x][adj.y] && !impassable.contains(adj) && rng.nextDouble() <= 1.0 / h) {
-                    setFresh(adj);
-                }
-            }
-            fresh.remove(cell);
-        }
-        filled = spreadPattern.size();
-        return spreadPattern;
-    }
-
-    private static final double root2 = Math.sqrt(2.0);
-    private double heuristic(Direction target) {
-        switch (measurement) {
-            case MANHATTAN:
-            case CHEBYSHEV:
-                return 1.0;
-            case EUCLIDEAN:
-                switch (target) {
-                    case DOWN_LEFT:
-                    case DOWN_RIGHT:
-                    case UP_LEFT:
-                    case UP_RIGHT:
-                        return root2;
-                    default:
-                        return  1.0;
-                }
-        }
-        return 1.0;
-    }
-}

+ 0 - 5
squidlib-util/src/main/java/squidpony/squidgrid/mapping/DungeonUtility.java

@@ -11,7 +11,6 @@ import squidpony.squidai.DijkstraMap;
 import squidpony.squidgrid.Direction;
 import squidpony.squidmath.Coord;
 import squidpony.squidmath.CoordPacker;
-import squidpony.squidmath.LightRNG;
 import squidpony.squidmath.PerlinNoise;
 import squidpony.squidmath.RNG;
 import squidpony.squidmath.StatefulRNG;
@@ -34,10 +33,6 @@ public class DungeonUtility {
 		this.rng = rng;
 	}
 
-	public DungeonUtility(RNG rng) {
-		this.rng = new StatefulRNG(new LightRNG(rng.nextLong()));
-	}
-
 	/**
 	 * The random number generator that will be used for all methods in this class
 	 * with a random component.

+ 0 - 4
squidlib-util/src/main/java/squidpony/squidgrid/package-info.java

@@ -1,4 +0,0 @@
-/**
- * Tools for working with data on a grid, including LOS and FOV; overlaps with geometry code in squidpony.squidmath .
- */
-package squidpony.squidgrid;

+ 0 - 196
squidlib-util/src/main/java/squidpony/squidmath/CoordPacker.java

@@ -3479,115 +3479,6 @@ public class CoordPacker {
 		return vla.toArray();
 	}
 
-	/**
-	 * Given a packed array encoding a larger area, a packed array encoding one or
-	 * more points inside bounds, an RNG, and a volume in cells, expands a random
-	 * cell in start in a random Manhattan (diamond) direction equal, then continues
-	 * to expand from random cells in start or the expanded area until it has filled
-	 * volume cells, limiting any expansion to within bounds and returning the final
-	 * expanded (limited) packed data. Notably, if a small area is not present
-	 * within bounds, then the spill will move around the "hole" similarly to
-	 * DijkstraMap's behavior; essentially, it needs to expand around the hole to
-	 * get to the other side, and this takes more steps of expansion than crossing
-	 * straight over. <br>
-	 * Could also be given a name like randomizedFlood(), but spill() is used by the
-	 * Spill class that does this too. <br>
-	 * Returns a new packed short[] and does not modify bounds or start.
-	 * 
-	 * @param bounds
-	 *            packed data representing the maximum extent of the region to
-	 *            random-flood-fill; often floors
-	 * @param start
-	 *            a packed array that encodes position(s) that the random-flood will
-	 *            spread outward from
-	 * @param volume
-	 *            the total number of cells to try to fill
-	 * @param rng
-	 *            used to generate random numbers for the flooding
-	 * @return a packed array that encodes "on" for cells that are "on" in bounds
-	 *         and are within expansion Manhattan distance from a Coord in start
-	 */
-	public static short[] spill(short[] bounds, short[] start, int volume, RNG rng) {
-		if (bounds == null || bounds.length <= 1) {
-			return ALL_WALL;
-		}
-		int boundSize = count(bounds);
-		ShortVLA vla = new ShortVLA(256);
-		ShortSet ss = new ShortSet(boundSize), edge = new ShortSet(boundSize), quickBounds = new ShortSet(boundSize);
-		boolean on = false, justAdded;
-		int idx = 0;
-		short x, y, dist;
-		for (int p = 0; p < bounds.length; p++, on = !on) {
-			if (on) {
-				for (int i = idx; i < idx + (bounds[p] & 0xffff); i++) {
-					quickBounds.add((short) i);
-				}
-			}
-			idx += bounds[p] & 0xffff;
-		}
-		short[] s2 = allPackedHilbert(start);
-		int ct = s2.length;
-		ss.addAll(s2);
-		vla.addAll(s2);
-		edge.addAll(allPackedHilbert(intersectPacked(bounds, fringe(start, 1, 256, 256, false))));
-		ss.addAll(edge);
-		if (edge.size <= 0) {
-			if (!intersects(bounds, start))
-				return ALL_WALL;
-
-			short[] cpy = new short[start.length];
-			System.arraycopy(start, 0, cpy, 0, start.length);
-			return cpy;
-		}
-		int[] xOffsets = new int[] { 0, 1, 0, -1 }, yOffsets = new int[] { 1, 0, -1, 0 };
-		for (int v = ct; v < volume; v++) {
-			short s = rng.getRandomElement(edge);
-
-			edge.remove(s);
-			vla.add(s);
-			int i = s & 0xffff;
-			x = hilbertX[i];
-			y = hilbertY[i];
-
-			for (int d = 0; d < 4; d++) {
-				int j = Math.min(255, Math.max(0, x + xOffsets[d]));
-				int k = Math.min(255, Math.max(0, y + yOffsets[d]));
-				dist = hilbertDistances[j + (k << 8)];
-				if (quickBounds.contains(dist)) {
-					if (ss.add(dist)) {
-						edge.add(dist);
-					}
-				}
-			}
-
-			if (edge.size <= 0)
-				break;
-		}
-
-		int[] indices = vla.asInts();
-		if (indices.length < 1)
-			return ALL_WALL;
-		Arrays.sort(indices);
-
-		vla.clear();
-		int current, past = indices[0], skip = 0;
-
-		vla.add((short) indices[0]);
-		for (int i = 1; i < indices.length; i++) {
-			current = indices[i];
-			if (current - past > 1) {
-				vla.add((short) (skip + 1));
-				skip = 0;
-				vla.add((short) (current - past - 1));
-			} else if (current != past)
-				skip++;
-			past = current;
-		}
-		vla.add((short) (skip + 1));
-
-		return vla.toArray();
-	}
-
 	private static void modifiedShadowFOV(int expansion, int viewerX, int viewerY, Radius metric, ShortSet bounds,
 			ShortSet storedSet, ShortVLA vla) {
 		if (expansion < 1)
@@ -5037,46 +4928,6 @@ public class CoordPacker {
 		return viable;
 	}
 
-	/**
-	 * Gets a random subset of positions that are "on" in the given packed array,
-	 * without unpacking it, and returns them as a Coord[]. Random numbers are
-	 * generated by the rng parameter.
-	 * 
-	 * @param packed
-	 *            a short[] returned by pack() or one of the sub-arrays in what is
-	 *            returned by packMulti(); must not be null (this method does not
-	 *            check).
-	 * @param fraction
-	 *            the likelihood to return one of the "on" cells, from 0.0 to 1.0
-	 * @param rng
-	 *            the random number generator used to decide random factors.
-	 * @return a Coord[], ordered by distance along the Hilbert Curve, corresponding
-	 *         to a random section of "on" cells in packed that has a random length
-	 *         approximately equal to the count of all "on" cells in packed times
-	 *         fraction.
-	 */
-	public static Coord[] randomSample(short[] packed, double fraction, RNG rng) {
-		int counted = count(packed);
-		ShortVLA vla = new ShortVLA((int) (counted * fraction) + 1);
-		boolean on = false;
-		int idx = 0;
-		for (int p = 0; p < packed.length; p++, on = !on) {
-			if (on) {
-				for (int i = idx; i < idx + (packed[p] & 0xffff); i++) {
-					if (rng.nextDouble() < fraction)
-						vla.add((short) i);
-				}
-			}
-			idx += packed[p] & 0xffff;
-		}
-		int[] distances = vla.asInts();
-		Coord[] cs = new Coord[distances.length];
-		for (int i = 0; i < distances.length; i++) {
-			cs[i] = Coord.get(hilbertX[distances[i]], hilbertY[distances[i]]);
-		}
-		return cs;
-	}
-
 	/**
 	 * Gets a single randomly chosen position that is "on" in the given packed
 	 * array, without unpacking it, and returns it as a Coord or returns null of the
@@ -5113,53 +4964,6 @@ public class CoordPacker {
 
 	}
 
-	/**
-	 * Gets a fixed number of randomly chosen positions that are "on" in the given
-	 * packed array, without unpacking it, and returns a List of Coord with a count
-	 * equal to size (or less if there aren't enough "on" cells). Random numbers are
-	 * generated by the rng parameter. This orders the returned array in the order
-	 * the Hilbert Curve takes, and you may want to call RNG.shuffle() with it as a
-	 * parameter to randomize the order.
-	 *
-	 * @param packed
-	 *            a short[] returned by pack() or one of the sub-arrays in what is
-	 *            returned by packMulti(); must not be null (this method does not
-	 *            check).
-	 * @param size
-	 *            the desired size of the List to return; may be smaller if there
-	 *            aren't enough elements
-	 * @param rng
-	 *            the random number generator used to decide random factors.
-	 * @return a List of Coords, ordered by distance along the Hilbert Curve,
-	 *         corresponding to randomly "on" cells in packed, with a length equal
-	 *         to the smaller of size and the count of all "on" cells in packed
-	 */
-	public static ArrayList<Coord> randomPortion(short[] packed, int size, RNG rng) {
-		int counted = count(packed);
-		ArrayList<Coord> coords = new ArrayList<>(Math.min(counted, size));
-		if (counted == 0 || size == 0)
-			return coords;
-		int[] data = rng.randomRange(0, counted, Math.min(counted, size));
-		Arrays.sort(data);
-		int r = data[0];
-		int c = 0, idx = 0;
-		boolean on = false;
-		for (int i = 0, ri = 0; i < packed.length; on = !on, idx += packed[i] & 0xffff, i++) {
-			if (on) {
-				while (c + (packed[i] & 0xffff) > r) {
-					int n = idx + r - c;
-					coords.add(Coord.get(hilbertX[n], hilbertY[n]));
-					if (++ri < data.length)
-						r = data[ri];
-					else
-						return coords;
-				}
-				c += packed[i] & 0xffff;
-			}
-		}
-		return coords;
-	}
-
 	/**
 	 * Takes multiple pieces of packed data as short[], encoded by pack() or another
 	 * similar method of this class, and generates a 2D int array with the specified

+ 0 - 32
squidlib-util/src/main/java/squidpony/squidmath/GreasedRegion.java

@@ -1904,38 +1904,6 @@ public class GreasedRegion implements Serializable {
 		return new Coord(-1, -1);
 	}
 
-	public Coord[] randomPortion(RNG rng, int size) {
-		int ct = 0, idx = 0, run = 0;
-		for (int i = 0; i < width * ySections; i++) {
-			ct += Long.bitCount(data[i]);
-		}
-		if (ct <= 0 || size <= 0)
-			return new Coord[0];
-		if (ct <= size)
-			return asCoords();
-		Coord[] points = new Coord[size];
-		int[] order = rng.randomOrdering(ct);
-		Arrays.sort(order, 0, size);
-		long t, w;
-		ALL: for (int x = 0; x < width; x++) {
-			for (int s = 0; s < ySections; s++) {
-				if ((t = data[x * ySections + s]) != 0) {
-					w = Long.lowestOneBit(t);
-					while (w != 0) {
-						if (run++ == order[idx]) {
-							points[idx++] = Coord.get(x, (s << 6) | Long.numberOfTrailingZeros(w));
-							if (idx >= size)
-								break ALL;
-						}
-						t ^= w;
-						w = Long.lowestOneBit(t);
-					}
-				}
-			}
-		}
-		return points;
-	}
-
 	/**
 	 * Generates a 2D int array from an array or vararg of GreasedRegions, starting
 	 * at all 0 and adding 1 to the int at a position once for every GreasedRegion

+ 0 - 355
squidlib-util/src/main/java/squidpony/squidmath/PoissonDisk.java

@@ -1,355 +0,0 @@
-package squidpony.squidmath;
-
-import squidpony.squidgrid.Radius;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-
-/**
- * This provides a Uniform Poisson Disk Sampling technique that can be used to generate random points that have a
- * uniform minimum distance between each other. Due to Coord in SquidLib using ints and most Poisson Disk algorithms
- * using floating-point numbers, some imprecision is to be expected from rounding to the nearest integers x and y.
- *
- * The algorithm is from the "Fast Poisson Disk Sampling in Arbitrary Dimensions" paper by Robert Bridson
- * http://www.cs.ubc.ca/~rbridson/docs/bridson-siggraph07-poissondisk.pdf
- *
- * Adapted from C# by Renaud Bedard, which was adapted from Java source by Herman Tulleken
- * http://theinstructionlimit.com/fast-uniform-poisson-disk-sampling-in-c
- * Created by Tommy Ettinger on 10/20/2015.
- */
-public class PoissonDisk {
-    private static final float rootTwo = (float) Math.sqrt(2),
-            pi = (float) Math.PI, pi2 = pi * 2f, halfPi = pi * 0.5f;
-    
-    private static final int defaultPointsPlaced = 10;
-    private static final Radius disk = Radius.CIRCLE;
-
-    private PoissonDisk() {
-    }
-
-    /**
-     * Get a list of Coords, each randomly positioned around the given center out to the given radius (measured with
-     * Euclidean distance, so a true circle), but with the given minimum distance from any other Coord in the list.
-     * The parameters maxX and maxY should typically correspond to the width and height of the map; no points will have
-     * positions with x equal to or greater than maxX and the same for y and maxY; similarly, no points will have
-     * negative x or y.
-     * @param center the center of the circle to spray Coords into
-     * @param radius the radius of the circle to spray Coords into
-     * @param minimumDistance the minimum distance between Coords, in Euclidean distance as a float.
-     * @param maxX one more than the highest x that can be assigned; typically an array length
-     * @param maxY one more than the highest y that can be assigned; typically an array length
-     * @return an ArrayList of Coord that satisfy the minimum distance; the length of the array can vary
-     */
-    public static ArrayList<Coord> sampleCircle(Coord center, float radius, float minimumDistance,
-                                                int maxX, int maxY)
-    {
-        return sampleCircle(center, radius, minimumDistance, maxX, maxY, defaultPointsPlaced, new StatefulRNG());
-    }
-
-    /**
-     * Get a list of Coords, each randomly positioned around the given center out to the given radius (measured with
-     * Euclidean distance, so a true circle), but with the given minimum distance from any other Coord in the list.
-     * The parameters maxX and maxY should typically correspond to the width and height of the map; no points will have
-     * positions with x equal to or greater than maxX and the same for y and maxY; similarly, no points will have
-     * negative x or y.
-     * @param center the center of the circle to spray Coords into
-     * @param radius the radius of the circle to spray Coords into
-     * @param minimumDistance the minimum distance between Coords, in Euclidean distance as a float.
-     * @param maxX one more than the highest x that can be assigned; typically an array length
-     * @param maxY one more than the highest y that can be assigned; typically an array length
-     * @param pointsPerIteration with small radii, this can be around 5; with larger ones, 30 is reasonable
-     * @param rng an RNG to use for all random sampling.
-     * @return an ArrayList of Coord that satisfy the minimum distance; the length of the array can vary
-     */
-    public static ArrayList<Coord> sampleCircle(Coord center, float radius, float minimumDistance,
-                                                int maxX, int maxY, int pointsPerIteration, RNG rng)
-    {
-        int radius2 = Math.round(radius);
-        return sample(center.translate(-radius2, -radius2), center.translate(radius2, radius2), radius, minimumDistance, maxX, maxY, pointsPerIteration, rng);
-    }
-
-    /**
-     * Get a list of Coords, each randomly positioned within the rectangle between the given minPosition and
-     * maxPosition, but with the given minimum distance from any other Coord in the list.
-     * The parameters maxX and maxY should typically correspond to the width and height of the map; no points will have
-     * positions with x equal to or greater than maxX and the same for y and maxY; similarly, no points will have
-     * negative x or y.
-     * @param minPosition the Coord with the lowest x and lowest y to be used as a corner for the bounding box
-     * @param maxPosition the Coord with the highest x and highest y to be used as a corner for the bounding box
-     * @param minimumDistance the minimum distance between Coords, in Euclidean distance as a float.
-     * @param maxX one more than the highest x that can be assigned; typically an array length
-     * @param maxY one more than the highest y that can be assigned; typically an array length
-     * @return an ArrayList of Coord that satisfy the minimum distance; the length of the array can vary
-     */
-    public static ArrayList<Coord> sampleRectangle(Coord minPosition, Coord maxPosition, float minimumDistance,
-                                                   int maxX, int maxY)
-    {
-        return sampleRectangle(minPosition, maxPosition, minimumDistance, maxX, maxY, defaultPointsPlaced, new StatefulRNG());
-    }
-
-    /**
-     * Get a list of Coords, each randomly positioned within the rectangle between the given minPosition and
-     * maxPosition, but with the given minimum distance from any other Coord in the list.
-     * The parameters maxX and maxY should typically correspond to the width and height of the map; no points will have
-     * positions with x equal to or greater than maxX and the same for y and maxY; similarly, no points will have
-     * negative x or y.
-     * @param minPosition the Coord with the lowest x and lowest y to be used as a corner for the bounding box
-     * @param maxPosition the Coord with the highest x and highest y to be used as a corner for the bounding box
-     * @param minimumDistance the minimum distance between Coords, in Euclidean distance as a float.
-     * @param maxX one more than the highest x that can be assigned; typically an array length
-     * @param maxY one more than the highest y that can be assigned; typically an array length
-     * @param pointsPerIteration with small areas, this can be around 5; with larger ones, 30 is reasonable
-     * @param rng an RNG to use for all random sampling.
-     * @return an ArrayList of Coord that satisfy the minimum distance; the length of the array can vary
-     */
-    public static ArrayList<Coord> sampleRectangle(Coord minPosition, Coord maxPosition, float minimumDistance,
-                                                   int maxX, int maxY, int pointsPerIteration, RNG rng)
-    {
-        return sample(minPosition, maxPosition, 0f, minimumDistance, maxX, maxY, pointsPerIteration, rng);
-    }
-
-    private static ArrayList<Coord> sample(Coord minPosition, Coord maxPosition, float rejectionDistance,
-                                           float minimumDistance, int maxX, int maxY, int pointsPerIteration, RNG rng)
-    {
-
-        Coord center = minPosition.average(maxPosition);
-        Coord dimensions = maxPosition.subtract(minPosition);
-        float cellSize = Math.max(minimumDistance / rootTwo, 0.25f);
-        int gridWidth = (int)(dimensions.x / cellSize) + 1;
-        int gridHeight = (int)(dimensions.y / cellSize) + 1;
-        Coord[][] grid = new Coord[gridWidth][gridHeight];
-        ArrayList<Coord> activePoints = new ArrayList<>();
-        OrderedSet<Coord> points = new OrderedSet<>(128);
-
-        //add first point
-        boolean added = false;
-        while (!added)
-        {
-            float d = rng.nextFloat();
-            int xr = Math.round(minPosition.x + dimensions.x * d);
-
-            d = rng.nextFloat();
-            int yr = Math.round(minPosition.y + dimensions.y * d);
-
-            if (rejectionDistance > 0 && disk.radius(center.x, center.y, xr, yr) > rejectionDistance)
-                continue;
-            added = true;
-            Coord p = Coord.get(Math.min(xr, maxX - 1), Math.min(yr, maxY - 1));
-            Coord index = p.subtract(minPosition).divide(cellSize);
-
-            grid[index.x][index.y] = p;
-
-            activePoints.add(p);
-            points.add(p);
-        }
-        //end add first point
-
-        while (activePoints.size() != 0)
-        {
-            int listIndex = rng.nextInt(activePoints.size());
-
-            Coord point = activePoints.get(listIndex);
-            boolean found = false;
-
-            for (int k = 0; k < pointsPerIteration; k++)
-            {
-                //add next point
-                //get random point around
-                float d = rng.nextFloat();
-                float radius = minimumDistance + minimumDistance * d;
-                d = rng.nextFloat();
-                float angle = pi2 * d;
-
-                float newX = radius * (float)Math.sin(angle);
-                float newY = radius * (float)Math.cos(angle);
-                Coord q = point.translateCapped(Math.round(newX), Math.round(newY), maxX, maxY);
-                //end get random point around
-
-                if (q.x >= minPosition.x && q.x <= maxPosition.x &&
-                        q.y >= minPosition.y && q.y <= maxPosition.y &&
-                        (rejectionDistance <= 0 || disk.radius(center.x, center.y, q.x, q.y) <= rejectionDistance))
-                {
-                    Coord qIndex = q.subtract(minPosition).divide((int)Math.ceil(cellSize));
-                    boolean tooClose = false;
-
-                    for (int i = Math.max(0, qIndex.x - 2); i < Math.min(gridWidth, qIndex.x + 3) && !tooClose; i++) {
-                        for (int j = Math.max(0, qIndex.y - 2); j < Math.min(gridHeight, qIndex.y + 3); j++) {
-                            if (grid[i][j] != null && disk.radius(grid[i][j], q) < minimumDistance) {
-                                tooClose = true;
-                                break;
-                            }
-                        }
-                    }
-                    if (!tooClose)
-                    {
-                        found = true;
-                        activePoints.add(q);
-                        points.add(q);
-                        grid[qIndex.x][qIndex.y] = q;
-                    }
-                }
-                //end add next point
-            }
-
-            if (!found)
-            {
-                activePoints.remove(listIndex);
-            }
-        }
-        activePoints = new ArrayList<>(points);
-        return activePoints;
-    }
-
-    public static ArrayList<Coord> sampleMap(char[][] map,
-                                             float minimumDistance, RNG rng, Character... blocking)
-    {
-        return sampleMap(Coord.get(1, 1), Coord.get(map.length - 2, map[0].length - 2),
-                map, minimumDistance, rng, blocking);
-    }
-
-    public static ArrayList<Coord> sampleMap(Coord minPosition, Coord maxPosition, char[][] map,
-                                             float minimumDistance, RNG rng, Character... blocking) {
-        int width = map.length;
-        int height = map[0].length;
-        HashSet<Character> blocked = new HashSet<>();
-        Collections.addAll(blocked, blocking);
-        boolean restricted = false;
-        if (blocked.size() > 0) {
-            restricted = true;
-        }
-        Coord dimensions = maxPosition.subtract(minPosition);
-        float cellSize = Math.max(minimumDistance / rootTwo, 1f);
-        int gridWidth = (int) (dimensions.x / cellSize) + 1;
-        int gridHeight = (int) (dimensions.y / cellSize) + 1;
-        Coord[][] grid = new Coord[gridWidth][gridHeight];
-        ArrayList<Coord> activePoints = new ArrayList<>();
-        OrderedSet<Coord> points = new OrderedSet<>(128);
-
-        //add first point
-
-        Coord p = randomUnblockedTile(minPosition, maxPosition, map, rng, blocked);
-        if (p == null)
-            return activePoints;
-        Coord index = p.subtract(minPosition).divide(cellSize);
-
-        grid[index.x][index.y] = p;
-
-        activePoints.add(p);
-        points.add(p);
-
-        //end add first point
-
-        while (activePoints.size() != 0) {
-            int listIndex = rng.nextInt(activePoints.size());
-
-            Coord point = activePoints.get(listIndex);
-            boolean found = false;
-
-            for (int k = 0; k < 20; k++) {
-                //add next point
-                //get random point around
-                float d = rng.nextFloat();
-                float radius = minimumDistance + minimumDistance * d;
-                d = rng.nextFloat();
-                float angle = pi2 * d;
-
-                float newX = radius * (float) Math.sin(angle);
-                float newY = radius * (float) Math.cos(angle);
-                Coord q = point.translateCapped(Math.round(newX), Math.round(newY), width, height);
-                int frustration = 0;
-                while(blocked.contains(map[q.x][q.y]) && frustration < 8)
-                {
-                    d = rng.nextFloat();
-                    angle = pi2 * d;
-                    newX = radius * (float) Math.sin(angle);
-                    newY = radius * (float) Math.cos(angle);
-                    q = point.translateCapped(Math.round(newX), Math.round(newY), width, height);
-                    frustration++;
-                }
-
-                //end get random point around
-
-                if (q.x >= minPosition.x && q.x <= maxPosition.x &&
-                        q.y >= minPosition.y && q.y <= maxPosition.y) {
-                    Coord qIndex = q.subtract(minPosition).divide((int) Math.ceil(cellSize));
-                    boolean tooClose = false;
-
-                    for (int i = Math.max(0, qIndex.x - 2); i < Math.min(gridWidth, qIndex.x + 3) && !tooClose; i++) {
-                        for (int j = Math.max(0, qIndex.y - 2); j < Math.min(gridHeight, qIndex.y + 3); j++) {
-                            if (grid[i][j] != null && disk.radius(grid[i][j], q) < minimumDistance) {
-                                tooClose = true;
-                                break;
-                            }
-                        }
-                    }
-                    if (!tooClose) {
-                        found = true;
-                        activePoints.add(q);
-                        if(!blocked.contains(map[q.x][q.y]))
-                            points.add(q);
-                        grid[qIndex.x][qIndex.y] = q;
-                    }
-                }
-                //end add next point
-            }
-
-            if (!found)
-                activePoints.remove(listIndex);
-        }
-        activePoints = new ArrayList<>(points);
-        return activePoints;
-    }
-    /**
-     * Finds a random Coord where the x and y match up to a [x][y] location on map that has any value not in blocking.
-     * Uses the given RNG for pseudo-random number generation.
-     * @param minPosition the Coord with the lowest x and lowest y to be used as a corner for the bounding box
-     * @param maxPosition the Coord with the highest x and highest y to be used as a corner for the bounding box
-     * @param map a dungeon map or something, x then y
-     * @param rng a RNG to generate random choices
-     * @param blocked a Set of Characters that block a tile from being chosen
-     * @return a Coord that corresponds to a map element equal to tile, or null if tile cannot be found or if map is too small.
-     */
-    public static Coord randomUnblockedTile(Coord minPosition, Coord maxPosition, char[][] map, RNG rng, HashSet<Character> blocked)
-    {
-        int width = map.length;
-        int height = map[0].length;
-        if(width < 3 || height < 3)
-            return null;
-        if(blocked.size() == 0) {
-            return Coord.get(rng.between(minPosition.x, maxPosition.x), rng.between(minPosition.y, maxPosition.y));
-        }
-
-        int x = rng.between(minPosition.x, maxPosition.x), y = rng.between(minPosition.y, maxPosition.y);
-        for(int i = 0; i < (width + height) / 4; i++)
-        {
-            if(!blocked.contains(map[x][y]))
-            {
-                return Coord.get(x, y);
-            }
-            else
-            {
-                x = rng.between(minPosition.x, maxPosition.x);
-                y = rng.between(minPosition.y, maxPosition.y);
-            }
-        }
-        x = 1;
-        y = 1;
-        if(!blocked.contains(map[x][y]))
-            return Coord.get(x, y);
-
-        while(blocked.contains(map[x][y]))
-        {
-            x += 1;
-            if(x >= width - 1)
-            {
-                x = 1;
-                y += 1;
-            }
-            if(y >= height - 1)
-                return null;
-        }
-        return Coord.get(x, y);
-    }
-
-}

+ 0 - 636
squidlib-util/src/main/java/squidpony/squidmath/RandomBias.java

@@ -1,636 +0,0 @@
-package squidpony.squidmath;
-
-import java.io.Serializable;
-import java.util.Map;
-
-/**
- * A class that wraps an RNG and allows different String keys to be associated with biases toward low or high results
- * when a method is called that gets a number from the wrapped RNG. With this, you could make a category of "blessed" or
- * "cursed" biases that, instead of using a uniform distribution that produces all numbers approximately with equal
- * likelihood (with doubles between 0.0 and 1.0 averaging at 0.5), have different averages, like 0.7 for blessed or 0.3
- * for cursed, when generating between 0.0 and 1.0. You could also use this to favor or disfavor the player for "easy
- * mode" or "hard mode" categories of play.
- * <br>
- * The API allows you to associate an alternative average with a kind as a String, like "blessed to-hit" or "hard mode
- * enemy damage", if you expect to use that number more than once and might want to tweak any averages by changing one
- * number at a later point. You can also give an average as a double in place of a kind as a String, which avoids a
- * HashMap lookup and lets you give flexibly-adjusted numbers, but does need more effort to change many values
- * throughout a codebase if averages aren't all generated by a formula. You can also set the distribution in the
- * constructor or by changing the public distribution field; you can use constants in this class, TRIANGULAR,
- * EXPONENTIAL, TRUNCATED, SOFT_TRIANGULAR, and EXP_TRI (the average of EXPONENTIAL and TRIANGULAR), for different
- * choices, with the default being EXP_TRI. Each one of these has different behavior regarding a preference toward
- * extreme values; TRIANGULAR almost never produces very high or very low values, EXPONENTIAL frequently produces the
- * highest or lowest values for high or low expected averages, respectively, TRUNCATED will simply never generate values
- * that are too far from the average (otherwise it's uniform), SOFT_TRIANGULAR will produce a rounded version of
- * TRIANGULAR's distribution with less of an angular peak and more frequent high and low values, and EXP_TRI will have
- * something like a curve shape that may "collide" slightly with the upper bound if the average is high enough.
- * <br>
- * Credit for the technique used for the exponential modification to distributions goes to user pjs on StackOverflow,
- * http://stackoverflow.com/a/17796997 .
- * Credit should also be given to user vydd of the LispGames community, who made a visualization of the distribution
- * changing as the expected average changed (at the time, the typical behavior of an exponential distribution looked
- * like a bug, and the visualization showed that it was correct behavior). Derrick Creamer noticed how strange the
- * exponential distribution would seem to most players, and that led to adding the simple triangular distribution.
- * Created by Tommy Ettinger on 3/20/2016.
- */
-public class RandomBias implements Serializable {
-    private OrderedMap<String, Double> biases;
-    public RNG rng;
-    public int distribution = EXP_TRI;
-
-    /**
-     * A constant for a distribution that linearly increases in probability from a 0.0 chance of 0.0. to a 0.3333...
-     * chance of getting the expected average, then linearly decreases until it reaches a 0.0 chance of 1.0. Doesn't
-     * really support expected averages below 1/3 or above 2/3, due to how the triangular distribution works.
-     */
-    public static final int TRIANGULAR = 0,
-    /**
-     * A constant for a distribution that, for all values other than 0.5, will strongly favor either high or low
-     * results to push the odds in favor of a high or low expected average. This is probably not what most players
-     * expect, since it leads to massively more critical hits or failures if min or max results are counted as such.
-     */
-    EXPONENTIAL = 1,
-    /**
-     * Not like the other distributions; this is a constant for a distribution that simply truncates a random number's
-     * possible range to less than 1.0, and adjusts the minimum or maximum value so that the average is the desired one.
-     * This is a uniform random number generator, unlike the others which have a bias toward certain values; it simply
-     * cannot generate values outside a certain range, and the values within the range it generates are all equally
-     * likely. The range gets smaller the closer the expected average is to 0.0 or 1.0, with an expected average of 0.4
-     * producing values between 0.0 and 0.8, and an expected average of 0.9 producing values of 0.8 to 1.0 (in all
-     * cases, this is exclusive on the upper bound).
-     */
-    TRUNCATED = 2,
-    /**
-     * A constant for a distribution that averages two random floats, each with a triangular distribution (the same as
-     * what using the TRIANGULAR constant would produce, but the distribution becomes more curved when multiple random
-     * "dice rolls" are involved), to soften the point of the triangle and make very high or very low values appear
-     * somewhat more frequently, while the expected average appears less frequently. This should not be used to generate
-     * very large numbers, since the floats this uses lose precision after 24 bits, or about 16 million. It should
-     * produce very reasonable results for common values in games, like 0 to 100 or 0 to 20. Doesn't really support
-     * expected averages below 1/3 or above 2/3, due to how the triangular distribution works.
-     */
-    SOFT_TRIANGULAR = 3,
-    /**
-     * A constant for a distribution that averages two random floats, one with a triangular distribution (the same as
-     * what using the TRIANGULAR constant would produce), and one with an exponential distribution (the same as what
-     * using the EXPONENTIAL constant would produce) to soften the point of the triangle and make very high or very low
-     * values appear much more frequently, while the expected average appears somewhat less frequently. This should not
-     * be used to generate very large numbers, since the floats this uses lose precision after 24 bits, or about 16
-     * million. It should produce very reasonable results for common values in games, like 0 to 100 or 0 to 20. Has
-     * limited support for expected averages below 1/3 or above 2/3; unlike TRIANGULAR or SOFT_TRIANGULAR, expected
-     * averages outside that range will still affect the generated average due to the EXPONENTIAL distribution
-     * contributing half of the correction needed to match the expected average. An expected average of 5/6 will produce
-     * an approximate average with this of 3/4, as opposed to 2/3 (for pure TRIANGULAR) or 5/6 (for EXPONENTIAL).
-     */
-    EXP_TRI = 4,
-    /**
-     * "Bathtub-shaped" or "U-shaped" distribution (technically the arcsine distribution) that is significantly more
-     * likely to produce results at either extreme than it is to generate them in the center. The extremes in this case
-     * are the same as the truncated distribution, so not all values are possible unless the expected average is 0.5.
-     */
-    BATHTUB_TRUNCATED = 5;
-
-    private static final int softRange = 1 << 24;
-
-    private static final long serialVersionUID = 4245874924013134958L;
-
-    public RandomBias()
-    {
-        biases = new OrderedMap<>(32);
-        rng = new RNG();
-    }
-    public RandomBias(RNG rng)
-    {
-        this.rng = rng;
-        biases = new OrderedMap<>(32);
-    }
-    public RandomBias(RNG rng, Map<String, Double> mapping)
-    {
-        this(rng, mapping, EXP_TRI);
-    }
-    public RandomBias(RNG rng, Map<String, Double> mapping, int distribution) {
-        this.rng = rng;
-        this.distribution = distribution;
-        if (mapping == null) {
-            biases = new OrderedMap<>(32);
-        } else {
-            biases = new OrderedMap<>(mapping.size());
-            double exp;
-            for (Map.Entry<String, Double> kv : mapping.entrySet()) {
-                exp = kv.getValue();
-                if (exp <= 0) exp = 0.001;
-                if (exp >= 1) exp = 0.999;
-                biases.put(kv.getKey(), exp);
-            }
-        }
-    }
-
-    /**
-     * Adds a kind of bias that can be used to change the average of random numbers generated when specified with that
-     * kind.
-     * @param kind a String that will be used as a key in a Map; can be given later on to bias results using this key
-     * @param expectedAverage above 0.0 and below 1.0, with 0.5 as the normal average but other values are more useful.
-     * @return this for chaining
-     */
-    public RandomBias putBias(String kind, double expectedAverage)
-    {
-        if(expectedAverage <= 0) expectedAverage = 0.001;
-        if(expectedAverage >= 1) expectedAverage = 0.999;
-        biases.put(kind, expectedAverage);
-        return this;
-    }
-    /**
-     * Adds a number of kinds of bias that can be used to change the average of random numbers generated when specified
-     * with one of those kinds.
-     * @param mapping should have String keys that can be used later, and double values greater than 0 but less than 1.
-     * @return this for chaining
-     */
-    public RandomBias putBiases(Map<String, Double> mapping)
-    {
-        double exp;
-        for(Map.Entry<String, Double> kv : mapping.entrySet())
-        {
-            exp = kv.getValue();
-            if(exp <= 0) exp = 0.001;
-            if(exp >= 1) exp = 0.999;
-            biases.put(kv.getKey(), exp);
-        }
-        return this;
-    }
-
-    private double quantile(double expected)
-    {
-        switch (distribution)
-        {
-            case EXPONENTIAL: return exponentialQuantile(expected);
-            case TRUNCATED: return truncatedQuantile(expected);
-            case TRIANGULAR: return triangularQuantile(expected);
-            case SOFT_TRIANGULAR: return softQuantile(expected);
-            case BATHTUB_TRUNCATED: return bathtubTruncatedQuantile(expected);
-            default: return mixQuantile(expected);
-        }
-    }
-
-    private double triangularQuantile(double expected)
-    {
-        expected = Math.max(0.001, Math.min(0.999, expected * 3.0 - 1.0));
-        double p = rng.nextDouble();
-        if(p < expected)
-            return Math.sqrt(expected * p);
-        if(p > expected)
-            return 1 - Math.sqrt((1 - expected) * (1 - p));
-        return expected;
-    }
-    private double truncatedQuantile(double expected)
-    {
-        if(expected >= 0.5)
-            return rng.nextDouble() * (1.0 - expected) * 2 + expected - (1.0 - expected);
-        return rng.nextDouble() * expected * 2;
-    }
-    private double bathtubQuantile(double expected)
-    {
-        expected = Math.sin(expected * Math.PI * 0.5);
-        return expected * expected;
-    }
-    private double bathtubTruncatedQuantile(double expected)
-    {
-        if(expected >= 0.5)
-            return bathtubQuantile(rng.nextDouble()) * (1.0 - expected) * 2 + expected - (1.0 - expected);
-        return bathtubQuantile(rng.nextDouble()) * expected * 2;
-    }
-    private double exponentialQuantile(double expected)
-    {
-        return 0.9999999999999999 - Math.pow( rng.nextDouble(), 1.0 / (1.0 - expected) - 1.0);
-    }
-    private static float longToFloat(long n)
-    {
-        return n * 1.0f / softRange;
-    }
-    private double softQuantile(double expected)
-    {
-        expected = Math.max(0.001, Math.min(0.999, expected * 3.0 - 1.0));
-        long pair = rng.nextLong();
-        float left = longToFloat(pair >>> 40), right = longToFloat((pair >>> 16) & 0xFFFFFFL);
-        double v;
-
-        if(left < expected)
-            v = Math.sqrt(expected * left);
-        else if(left > expected)
-            v = 1 - Math.sqrt((1 - expected) * (1 - left));
-        else
-            v = expected;
-        if(right < expected)
-            return (v + Math.sqrt(expected * right)) * 0.5;
-        if(right > expected)
-            return (v + 1 - Math.sqrt((1 - expected) * (1 - right))) * 0.5;
-        return expected;
-    }
-    private double mixQuantile(double expected)
-    {
-        double d2 = Math.max(0.001, Math.min(0.999, expected * 3.0 - 1.0)), v;
-        long pair = rng.nextLong();
-        float left = longToFloat(pair >>> 40), right = longToFloat((pair >>> 16) & 0xFFFFFFL);
-
-        if(left < d2)
-            v = Math.sqrt(d2 * left);
-        else if(left > d2)
-            v = 1 - Math.sqrt((1 - d2) * (1 - left));
-        else
-            v = d2;
-        return (Math.pow( right, 1.0 / expected - 1.0) + v) * 0.5;
-    }
-    /**
-     * Looks up the given kind in the Map of biases this stores, and generates a random number using this object's RNG.
-     * If the kind is in the Map, this adjusts the generated number so it matches a distribution that would have the
-     * expected average the kind was associated with. The returned number will be a positive long in either case, but
-     * not all long values are possible if this is biased, in part because of generating a double, which has less
-     * precision than long, and in part because some numbers need to be more common than others. If the kind is not in
-     * the map, this generates a positive long, using 63 bits instead of RNG's normal 64 bits since it never generates
-     * negative numbers.
-     * @param kind the kind of bias to look up
-     * @return a random 63-bit positive long, potentially influenced by the bias associated with kind, if present
-     */
-    public long biasedLong(String kind)
-    {
-        Double d = biases.get(kind);
-        if(d == null)
-            return rng.nextLong() >>> 1;
-        return (long)(quantile(d) * Long.MAX_VALUE);
-    }
-
-    /**
-     * Looks up the given kind in the Map of biases this stores, and generates a random number using this object's RNG.
-     * If the kind is in the Map, this adjusts the generated number so it matches a distribution that would have the
-     * expected average the kind was associated with. The returned number will be a long between 0 and bound (exclusive
-     * on bound), where bound can be negative (and this behavior is allowed even though RNG normally returns 0 for all
-     * negative bounds). If the kind is not in the map, this generates a long between 0 and bound (exclusive on bound),
-     * even if bound is negative.
-     * @param kind the kind of bias to look up
-     * @param bound the outer bound, exclusive; can be negative
-     * @return a random long between 0 and bound, potentially influenced by the bias associated with kind, if present
-     */
-    public long biasedLong(String kind, long bound)
-    {
-        boolean n = bound < 0;
-        Double d = biases.get(kind);
-        if(d == null)
-            return n ? rng.nextLong(-bound) * -1 : rng.nextLong(bound);
-        return (long)(quantile(d) * bound);
-    }
-
-    /**
-     * Looks up the given kind in the Map of biases this stores, and generates a random number using this object's RNG.
-     * If the kind is in the Map, this adjusts the generated number so it matches a distribution that would have the
-     * expected average the kind was associated with. The returned number will be a double between 0.0 and 1.0
-     * (exclusive on 1.0). If the kind is not in the map, this generates a double using RNG and no further changes.
-     * @param kind the kind of bias to look up
-     * @return a random double between 0.0 and 1.0, potentially influenced by the bias associated with kind, if present
-     */
-    public double biasedDouble(String kind)
-    {
-        Double d = biases.get(kind);
-        if(d == null)
-            return rng.nextDouble();
-        return quantile(d);
-    }
-
-    /**
-     * Looks up the given kind in the Map of biases this stores, and generates a random number using this object's RNG.
-     * If the kind is in the Map, this adjusts the generated number so it matches a distribution that would have the
-     * expected average the kind was associated with. The returned number will be a double between 0 and bound (exclusive
-     * on bound), where bound can be negative (the same as RNG). If the kind is not in the map, this doesn't adjust the
-     * average, and acts exactly like RNG.
-     * @param kind the kind of bias to look up
-     * @param bound the outer bound, exclusive; can be negative
-     * @return a random double between 0 and bound, potentially influenced by the bias associated with kind, if present
-     */
-    public double biasedDouble(String kind, double bound)
-    {
-        Double d = biases.get(kind);
-        if(d == null)
-            return rng.nextDouble(bound);
-        return quantile(d) * bound;
-    }
-
-    /**
-     * Looks up the given kind in the Map of biases this stores, and generates a random number using this object's RNG.
-     * If the kind is in the Map, this adjusts the generated number so it matches a distribution that would have the
-     * expected average the kind was associated with. The returned number will be a positive int in either case. If the
-     * kind is not in the map, this generates a positive int, using 31 bits instead of RNG's normal 32 bits since it
-     * never generates negative numbers.
-     * @param kind the kind of bias to look up
-     * @return a random 31-bit positive int, potentially influenced by the bias associated with kind, if present
-     */
-    public int biasedInt(String kind)
-    {
-        Double d = biases.get(kind);
-        if(d == null)
-            return rng.nextInt() >>> 1;
-        return (int)(quantile(d) * Integer.MAX_VALUE);
-    }
-
-    /**
-     * Looks up the given kind in the Map of biases this stores, and generates a random number using this object's RNG.
-     * If the kind is in the Map, this adjusts the generated number so it matches a distribution that would have the
-     * expected average the kind was associated with. The returned number will be an int between 0 and bound (exclusive
-     * on bound), where bound can be negative (and this behavior is allowed even though RNG normally returns 0 for all
-     * negative bounds). If the kind is not in the map, this generates an int between 0 and bound (exclusive on bound),
-     * even if bound is negative.
-     * @param kind the kind of bias to look up
-     * @param bound the outer bound, exclusive; can be negative
-     * @return a random int between 0 and bound, potentially influenced by the bias associated with kind, if present
-     */
-    public int biasedInt(String kind, int bound)
-    {
-        boolean n = bound < 0;
-        Double d = biases.get(kind);
-        if(d == null)
-            return n ? rng.nextInt(-bound) * -1 : rng.nextInt(bound);
-        return (int)(quantile(d) * bound);
-    }
-
-    /**
-     * Looks up the given kind in the Map of biases this stores, and generates a random number using this object's RNG.
-     * If the kind is in the Map, this adjusts the generated number so it matches a distribution that would have the
-     * expected average the kind was associated with. The returned number will be a float between 0.0 and 1.0
-     * (exclusive on 1.0). If the kind is not in the map, this generates a float using RNG and no further changes.
-     * @param kind the kind of bias to look up
-     * @return a random float between 0.0 and 1.0, potentially influenced by the bias associated with kind, if present
-     */
-    public float biasedFloat(String kind)
-    {
-        Double d = biases.get(kind);
-        if(d == null)
-            return rng.nextFloat();
-        return (float) quantile(d);
-    }
-
-    /**
-     * Looks up the given kind in the Map of biases this stores, and generates a random number using this object's RNG.
-     * If the kind is in the Map, this adjusts the generated number so it matches a distribution that would have the
-     * expected average the kind was associated with. The returned number will be a float between 0 and bound (exclusive
-     * on bound), where bound can be negative. If the kind is not in the map, this doesn't adjust the average.
-     * @param kind the kind of bias to look up
-     * @param bound the outer bound, exclusive; can be negative
-     * @return a random double between 0 and bound, potentially influenced by the bias associated with kind, if present
-     */
-    public float biasedFloat(String kind, float bound)
-    {
-        Double d = biases.get(kind);
-        if(d == null)
-            return rng.nextFloat() * bound;
-        return (float)(quantile(d) * bound);
-    }
-
-    /**
-     * Looks up the given kind in the Map of biases this stores, and generates a random number using this object's RNG.
-     * If the kind is in the Map, this adjusts the generated number so it matches a distribution that would have the
-     * expected average the kind was associated with. The returned boolean will be true if the random number (between
-     * 0.0 and 1.0, exclusive upper) is greater than or equal to 0.5. If the kind is not in the map, this generates a
-     * boolean using RNG and no further changes.
-     * @param kind the kind of bias to look up
-     * @return a random float between 0.0 and 1.0, potentially influenced by the bias associated with kind, if present
-     */
-    public boolean biasedBoolean(String kind)
-    {
-        Double d = biases.get(kind);
-        if(d == null)
-            return rng.nextBoolean();
-        return quantile(d) >= 0.5;
-    }
-    /**
-     * Looks up the given kind in the Map of biases this stores, and generates a random number using this object's RNG.
-     * If the kind is in the Map, this adjusts the generated number so it matches a distribution that would have the
-     * expected average the kind was associated with. The returned number will be an int between min and max (exclusive
-     * on max), where min and/or max can be negative, and the difference between the two can be either positive or
-     * negative. If the kind is not in the map, this doesn't adjust the average.
-     * @param kind the kind of bias to look up
-     * @param min the inner bound, inclusive; can be negative
-     * @param max the outer bound, exclusive; can be negative
-     * @return a random int between min and max, potentially influenced by the bias associated with kind, if present
-     */
-    public int biasedBetween(String kind, int min, int max)
-    {
-        return biasedInt(kind, max - min) + min;
-    }
-
-    /**
-     * Looks up the given kind in the Map of biases this stores, and generates a random number using this object's RNG.
-     * If the kind is in the Map, this adjusts the generated number so it matches a distribution that would have the
-     * expected average the kind was associated with. The returned number will be a long between min and max (exclusive
-     * on max), where min and/or max can be negative, and the difference between the two can be either positive or
-     * negative. If the kind is not in the map, this doesn't adjust the average.
-     * @param kind the kind of bias to look up
-     * @param min the inner bound, inclusive; can be negative
-     * @param max the outer bound, exclusive; can be negative
-     * @return a random long between min and max, potentially influenced by the bias associated with kind, if present
-     */
-    public long biasedBetween(String kind, long min, long max)
-    {
-        return biasedLong(kind, max - min) + min;
-    }
-
-    /**
-     * Looks up the given kind in the Map of biases this stores, and generates a random number using this object's RNG.
-     * If the kind is in the Map, this adjusts the generated number so it matches a distribution that would have the
-     * expected average the kind was associated with. The returned number will be a double between min and max
-     * (exclusive on max), where min and/or max can be negative, and the difference between the two can be either
-     * positive or negative. If the kind is not in the map, this doesn't adjust the average.
-     * @param kind the kind of bias to look up
-     * @param min the inner bound, inclusive; can be negative
-     * @param max the outer bound, exclusive; can be negative
-     * @return a random double between min and max, potentially influenced by the bias associated with kind, if present
-     */
-    public double biasedBetween(String kind, double min, double max)
-    {
-        return biasedDouble(kind, max - min) + min;
-    }
-
-
-    /**
-     * Generates a random number using this object's RNG and adjusts the generated number so it matches a distribution
-     * that would have the given expected average. The returned number will be a positive long in either case, but
-     * not all long values are possible if this is biased, in part because of generating a double, which has less
-     * precision than long, and in part because some numbers need to be more common than others.
-     * @param expectedAverage the desired average if the minimum value was 0.0 and the exclusive max was 1.0
-     * @return a random 63-bit positive long, potentially influenced by the bias associated with kind, if present
-     */
-    public long biasedLong(double expectedAverage)
-    {
-        if(expectedAverage <= 0) expectedAverage = 0.001;
-        if(expectedAverage >= 1) expectedAverage = 0.999;
-        return (long)(quantile(expectedAverage) * Long.MAX_VALUE);
-    }
-
-    /**
-     * Generates a random number using this object's RNG and adjusts the generated number so it matches a distribution
-     * that would have the given expected average. The returned number will be a long between 0 and bound (exclusive
-     * on bound), where bound can be negative (and this behavior is allowed even though RNG normally returns 0 for all
-     * negative bounds).
-     * @param expectedAverage the desired average if the minimum value was 0.0 and the exclusive max was 1.0
-     * @param bound the outer bound, exclusive; can be negative
-     * @return a random long between 0 and bound, potentially influenced by the bias associated with kind, if present
-     */
-    public long biasedLong(double expectedAverage, long bound)
-    {
-        if(expectedAverage <= 0) expectedAverage = 0.001;
-        if(expectedAverage >= 1) expectedAverage = 0.999;
-        return (long)(quantile(expectedAverage) * bound);
-    }
-
-    /**
-     * Generates a random number using this object's RNG and adjusts the generated number so it matches a distribution
-     * that would have the given expected average. The returned number will be a double between 0.0 and 1.0 (exclusive
-     * on 1.0).
-     * @param expectedAverage the desired average
-     * @return a random double between 0.0 and 1.0, potentially influenced by the bias associated with kind, if present
-     */
-    public double biasedDouble(double expectedAverage)
-    {
-        if(expectedAverage <= 0) expectedAverage = 0.001;
-        if(expectedAverage >= 1) expectedAverage = 0.999;
-        return quantile(expectedAverage);
-    }
-
-    /**
-     * Generates a random number using this object's RNG and adjusts the generated number so it matches a distribution
-     * that would have the given expected average. The returned number will be a double between 0 and bound (exclusive
-     * on bound), where bound can be negative (the same as RNG).
-     * @param expectedAverage the desired average
-     * @param bound the outer bound, exclusive; can be negative
-     * @return a random double between 0 and bound, potentially influenced by the bias associated with kind, if present
-     */
-    public double biasedDouble(double expectedAverage, double bound)
-    {
-        if(expectedAverage <= 0) expectedAverage = 0.001;
-        if(expectedAverage >= 1) expectedAverage = 0.999;
-        return quantile(expectedAverage) * bound;
-    }
-
-    /**
-     * Generates a random number using this object's RNG and adjusts the generated number so it matches a distribution
-     * that would have the given expected average. The returned number will be a positive int from 0 to (2 to the 31)-1
-     * in either case.
-     * @param expectedAverage the desired average if the minimum value was 0.0 and the exclusive max was 1.0
-     * @return a random 31-bit positive int, potentially influenced by the bias associated with kind, if present
-     */
-    public int biasedInt(double expectedAverage)
-    {
-        if(expectedAverage <= 0) expectedAverage = 0.001;
-        if(expectedAverage >= 1) expectedAverage = 0.999;
-        return (int)(quantile(expectedAverage) * Integer.MAX_VALUE);
-    }
-
-    /**
-     * Generates a random number using this object's RNG and adjusts the generated number so it matches a distribution
-     * that would have the given expected average. The returned number will be an int between 0 and bound (exclusive
-     * on bound), where bound can be negative (and this behavior is allowed even though RNG normally returns 0 for all
-     * negative bounds).
-     * @param expectedAverage the desired average if the minimum value was 0.0 and the exclusive max was 1.0
-     * @param bound the outer bound, exclusive; can be negative
-     * @return a random int between 0 and bound, potentially influenced by the bias associated with kind, if present
-     */
-    public int biasedInt(double expectedAverage, int bound)
-    {
-        if(expectedAverage <= 0) expectedAverage = 0.001;
-        if(expectedAverage >= 1) expectedAverage = 0.999;
-        return (int)(quantile(expectedAverage) * bound);
-    }
-
-    /**
-     * Generates a random number using this object's RNG and adjusts the generated number so it matches a distribution
-     * that would have the given expected average. The returned number will be a float between 0.0f and 1.0f (exclusive
-     * on 1.0f).
-     * @param expectedAverage the desired average
-     * @return a random float between 0.0 and 1.0, potentially influenced by the bias associated with kind, if present
-     */
-    public float biasedFloat(double expectedAverage)
-    {
-        if(expectedAverage <= 0) expectedAverage = 0.001;
-        if(expectedAverage >= 1) expectedAverage = 0.999;
-        return (float) quantile(expectedAverage);
-    }
-
-    /**
-     * Generates a random number using this object's RNG and adjusts the generated number so it matches a distribution
-     * that would have the given expected average. The returned number will be a float between 0f and bound (exclusive
-     * on bound), where bound can be negative.
-     * @param expectedAverage the desired average if the minimum value was 0.0 and the exclusive max was 1.0
-     * @param bound the outer bound, exclusive; can be negative
-     * @return a random double between 0 and bound, potentially influenced by the bias associated with kind, if present
-     */
-    public float biasedFloat(double expectedAverage, float bound)
-    {
-        if(expectedAverage <= 0) expectedAverage = 0.001;
-        if(expectedAverage >= 1) expectedAverage = 0.999;
-        return (float)(quantile(expectedAverage) * bound);
-    }
-
-    /**
-     * Generates a random number using this object's RNG and adjusts the generated number so it matches a distribution
-     * that would have the given expected average. The returned boolean will be true if the random number (between 0.0
-     * and 1.0, exclusive upper) is greater than or equal to 0.5.
-     * @param expectedAverage the desired probability of a true result, between 0.0 and 1.0
-     * @return a random float between 0.0 and 1.0, potentially influenced by the bias associated with kind, if present
-     */
-    public boolean biasedBoolean(double expectedAverage)
-    {
-        if(expectedAverage <= 0) expectedAverage = 0.001;
-        if(expectedAverage >= 1) expectedAverage = 0.999;
-        return quantile(expectedAverage) >= 0.5;
-    }
-    /**
-     * Generates a random number using this object's RNG and adjusts the generated number so it matches a distribution
-     * that would have the given expected average. The returned number will be an int between min and max (exclusive
-     * on max), where min and/or max can be negative, and the difference between the two can be either positive or
-     * negative.
-     * @param expectedAverage the desired average if the minimum value was 0.0 and the exclusive max was 1.0
-     * @param min the inner bound, inclusive; can be negative
-     * @param max the outer bound, exclusive; can be negative
-     * @return a random int between min and max, potentially influenced by the bias associated with kind, if present
-     */
-    public int biasedBetween(double expectedAverage, int min, int max)
-    {
-        return biasedInt(expectedAverage, max - min) + min;
-    }
-
-    /**
-     * Generates a random number using this object's RNG and adjusts the generated number so it matches a distribution
-     * that would have the given expected average. The returned number will be a long between min and max (exclusive
-     * on max), where min and/or max can be negative, and the difference between the two can be either positive or
-     * negative.
-     * @param expectedAverage the desired average if the minimum value was 0.0 and the exclusive max was 1.0
-     * @param min the inner bound, inclusive; can be negative
-     * @param max the outer bound, exclusive; can be negative
-     * @return a random long between min and max, potentially influenced by the bias associated with kind, if present
-     */
-    public long biasedBetween(double expectedAverage, long min, long max)
-    {
-        return biasedLong(expectedAverage, max - min) + min;
-    }
-
-    /**
-     * Generates a random number using this object's RNG and adjusts the generated number so it matches a distribution
-     * that would have the given expected average. The returned number will be a double between min and max (exclusive
-     * on max), where min and/or max can be negative, and the difference between the two can be either positive or
-     * negative.
-     * @param expectedAverage the desired average if the minimum value was 0.0 and the exclusive max was 1.0
-     * @param min the inner bound, inclusive; can be negative
-     * @param max the outer bound, exclusive; can be negative
-     * @return a random double between min and max, potentially influenced by the bias associated with kind, if present
-     */
-    public double biasedBetween(double expectedAverage, double min, double max)
-    {
-        return biasedDouble(expectedAverage, max - min) + min;
-    }
-
-    @Override
-    public String toString() {
-        return "RandomBias{" +
-                "biases=" + biases +
-                ", rng=" + rng +
-                ", distribution=" + distribution +
-                '}';
-    }
-
-}