package squidpony.squidmath; import squidpony.StringKit; import java.io.Serializable; /** * A UUID-like identifier; not compatible with Java's standard UUID but will work on GWT. * <br> * Meant to be used as an identity type for things like SpatialMap, especially when no special game-specific logic is * needed for identities. * Created by Tommy Ettinger on 4/30/2016. */ public class SquidID implements Serializable, Comparable<SquidID> { private static final long serialVersionUID = 8946534790126874460L; private static LongPeriodRNG rng = new LongPeriodRNG(); public final long low, high; /** * Constructs a new random SquidID. If you want different random IDs with every run, the defaults should be fine. * If you want stable IDs to be generated, use SquidID.stabilize(), but be careful about collisions! */ public SquidID() { low = rng.nextLong(); high = rng.nextLong(); } /** * Constructs a fixed SquidID with the given low and high 64-bit longs. * @param low the least-significant bits of the ID * @param high the most-significant bits of the ID */ public SquidID(long low, long high) { this.low = low; this.high = high; } /** * Gets a new random SquidID, the same as calling the no-argument constructor. * The name is for compatibility with Java's standard UUID class. * @return a newly-constructed random SquidID. */ public static SquidID randomUUID() { return new SquidID(); } /** * Makes the IDs generated after calling this repeatable, with the same IDs generated in order after this is called. * This class uses a random number generator with a random seed by default to produce IDs, and properties of the * LongPeriodRNG this uses make it incredibly unlikely that IDs will repeat even if the game was run for the rest * of your natural lifespan. For the purposes of tests, you may want stable SquidID values to be generated, the same * for every startup of the program, generating the same IDs in order. This will change the seed used internally to * a constant (large) seed the first time it is called, and it should only be called at or near the start of your * program, no more than once. If an ID is requested immediately after calling this method, and then this method is * called again, the next ID to be generated will be identical to the previous one generated (a collision). There * may be reasons you want this during testing, so there isn't any check for multiple calls to this method. If IDs * can persist between runs of the game (i.e. saved in a file), using this is generally a bad idea, and the default * random IDs should more than suffice. * <br> * You can "undo" the effects of this method with randomize(), changing the seed to a new random value. * <br> * Because IDs aren't likely to have gameplay significance, this uses one seed, the opening paragraph of The * Wonderful Wizard of Oz, by Frank L. Baum, which is in the public domain. Changing the seed is unlikely to change * the likelihood of collisions, which should be less likely than a tornado transporting you to Oz, as long as this * method is called at most once per program run. */ public static void stabilize() { rng.reseed( "Dorothy lived in the midst of the great Kansas prairies, with Uncle Henry, who was a "+ "farmer, and Aunt Em, who was the farmer's wife. Their house was small, for the "+ "lumber to build it had to be carried by wagon many miles. There were four walls, "+ "a floor and a roof, which made one room; and this room contained a rusty looking "+ "cookstove, a cupboard for the dishes, a table, three or four chairs, and the beds."+ " Uncle Henry and Aunt Em had a big bed in one corner, and Dorothy a little bed in "+ "another corner. There was no garret at all, and no cellar—except a small hole dug "+ "in the ground, called a cyclone cellar, where the family could go in case one of "+ "those great whirlwinds arose, mighty enough to crush any building in its path. It "+ "was reached by a trap door in the middle of the floor, from which a ladder led "+ "down into the small, dark hole."); } /** * Makes the IDs generated after calling this non-repeatable, with a random 1024-bit seed. * This class uses a random number generator with a random seed by default to produce IDs, and properties of the * LongPeriodRNG this uses make it incredibly unlikely that IDs will repeat even if the game was run for the rest * of your natural lifespan. However, if you call stabilize(), generate some IDs, call stabilize() again, and * generate some more IDs, the first, second, third, etc. IDs generated after each call will be identical -- hardly * the unique ID you usually want. You can "undo" the effects of stabilize by calling this method, making the seed * a new random value. This does not affect the constructor that takes two longs to produce an exact ID, nor will * it change any IDs. */ public static void randomize() { rng.reseed(); } /** * Gets the least-significant bits, also accessible by the field low. * The name is for compatibility with Java's standard UUID class. * @return the least-significant bits as a long */ public long getLeastSignificantBits() { return low; } /** * Gets the most-significant bits, also accessible by the field high. * The name is for compatibility with Java's standard UUID class. * @return the most-significant bits as a long */ public long getMostSignificantBits() { return high; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; SquidID squidID = (SquidID) o; if (low != squidID.low) return false; return high == squidID.high; } @Override public int hashCode() { return (int) (31 * (low ^ (low >>> 32)) + (high ^ (high >>> 32))); } @Override public String toString() { return StringKit.hex(high) + '-' + StringKit.hex(low); } @Override public int compareTo(SquidID o) { if(o == null) return 1; long diff = high - o.high; if(diff == 0) diff = low - o.low; return diff > 0 ? 1 : diff < 0 ? -1 : 0; } }