001package squidpony.squidmath;
002
003/**
004 * An interface to indicate a {@link RandomnessSource} that is intentionally flawed to create output patterns where a
005 * truly random sequence would have none. All FlawedRandomness implementations are static inner classes inside this
006 * interface, hopefully to avoid confusion with ones that are meant for general use. This implements {@link IFlawed} as
007 * well, to mark that it isn't for general-purpose use.
008 * <br>
009 * Created by Tommy Ettinger on 11/10/2019.
010 */
011public interface FlawedRandomness extends RandomnessSource, IFlawed {
012    /**
013     * A flawed randomness source that depends almost entirely on its starting state for any random-seeming results in
014     * its output. Simply outputs a number that starts with the initial seed and increases by {@code 0x1111111111111111}
015     * each time, or {@code 1229782938247303441}.
016     */
017    class BigCounter implements FlawedRandomness, StatefulRandomness
018    {
019        public long state;
020
021        public BigCounter()
022        {
023            this((long) ((Math.random() - 0.5) * 0x10000000000000L)
024                    ^ (long) (((Math.random() - 0.5) * 2.0) * 0x8000000000000000L));
025        }
026        public BigCounter(long state) {
027            this.state = state;
028        }
029
030        @Override
031        public long getState() {
032            return state;
033        }
034
035        @Override
036        public void setState(long state) {
037            this.state = state;
038        }
039
040        @Override
041        public int next(int bits) {
042            return (int)((state += 0x1111111111111111L) >>> 64 - bits);
043        }
044
045        @Override
046        public long nextLong() {
047            return (state += 0x1111111111111111L);
048        }
049
050        @Override
051        public BigCounter copy() {
052            return new BigCounter(state);
053        }
054    }
055
056    /**
057     * A flawed randomness source that adds a rotation of its state, to its state, every generation. The rotation amount
058     * is also determined by state. This one's probably pretty bad; I don't really know how bad it will be to a human
059     * observer, but it also depends on what cycle it starts in. The state probably shouldn't ever be 0, since this
060     * will only produce 0 after its state becomes 0. Of course, this is flawed, so it can become 0 in the course of
061     * normal generation.
062     */
063    class AddRotate implements FlawedRandomness, StatefulRandomness
064    {
065        public long state;
066
067        public AddRotate()
068        {
069            this((long) ((Math.random() - 0.5) * 0x10000000000000L)
070                    ^ (long) (((Math.random() - 0.5) * 2.0) * 0x8000000000000000L));
071        }
072        public AddRotate(long state) {
073            this.state = state == 0 ? 1 : state;
074        }
075
076        @Override
077        public long getState() {
078            return state;
079        }
080
081        @Override
082        public void setState(long state) {
083            this.state = state == 0 ? 1 : state;
084        }
085
086        @Override
087        public int next(int bits) {
088            return (int)((state += (state << state | state >>> -state)) >>> 64 - bits);
089        }
090
091        @Override
092        public long nextLong() {
093            return (state += (state << state | state >>> -state));
094        }
095
096        @Override
097        public AddRotate copy() {
098            return new AddRotate(state);
099        }
100    }
101}