001/*
002 * Trident - A Multithreaded Server Alternative
003 * Copyright 2014 The TridentSDK Team
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *    http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package net.tridentsdk.world.gen;
018
019import net.tridentsdk.util.FastRandom;
020
021import javax.annotation.concurrent.ThreadSafe;
022
023/**
024 * Used to generate random values for world generators
025 *
026 * @author The TridentSDK Team
027 */
028@ThreadSafe
029public class GeneratorRandom {
030    private final long seed;
031    private volatile long next;
032
033    /**
034     * Creates a new generator random using a random seed
035     */
036    public GeneratorRandom() {
037        this(FastRandom.random());
038    }
039
040    /**
041     * Creates a new seeded generator random
042     *
043     * @param seed the seed
044     */
045    public GeneratorRandom(long seed) {
046        this.seed = seed;
047        this.next = seed;
048    }
049
050    // non-atomic bit ops, nice.
051    private long next() {
052        next ^= (next << 21);
053        next ^= (next >>> 35);
054        next ^= (next << 4);
055        return next;
056    }
057
058    /**
059     * Forks the random using a new random seed generated from this random
060     *
061     * @return the new generator random
062     */
063    public GeneratorRandom fork() {
064        return new GeneratorRandom(next());
065    }
066
067    /**
068     * Forks the random using the provided sed
069     *
070     * @param seed the seed to use
071     * @return the new generator random
072     */
073    public GeneratorRandom fork(long seed) {
074        return new GeneratorRandom(seed);
075    }
076
077    /**
078     * Obtains the next long between 0 and the upper limit (inclusive)
079     *
080     * @param end the upper bound
081     * @return a random long
082     */
083    public long under(long end) {
084        long random = next();
085        return Math.abs(random % end);
086    }
087
088    /**
089     * Scales the next random long between the given min and max values
090     *
091     * <p>Helps smooth the random distribution curve</p>
092     *
093     * @param end the upper random bound
094     * @param min the minimum
095     * @param max the maximum
096     * @return the scaled random
097     */
098    public long scaleUnder(long end, long min, long max) {
099        return (long) (((double) (max - min)) * ((under(end) + 1) / 2)) + min;
100    }
101
102    /**
103     * Obtains the seed used to generate the random longs
104     *
105     * @return the seed
106     */
107    public long seed() {
108        return this.seed;
109    }
110}