001package squidpony.squidmath;
002
003import squidpony.annotation.Beta;
004
005/**
006 * An interface for point hashes that are statistically biased, as well as a holder for inner classes that implement
007 * this. The point hashes here are mostly chosen because they are aesthetically interesting, at least on some of their
008 * output bits.
009 * <br>
010 * Don't count on this class giving reliable output; it is marked Beta and will remain so. If you want to ensure a
011 * particular behavior of a FlawedPointHash can be replicated, copy the implementation into your own code.
012 * <br>
013 * Created by Tommy Ettinger on 4/14/2020.
014 */
015@Beta
016public interface FlawedPointHash extends IPointHash, IFlawed {
017    /**
018     * Produces hashes that show strong bias on one axis (usually the later axes matter more) and have nice-looking
019     * patterns of dots. Better patterns are present in the higher bits.
020     */
021    class RugHash extends IPointHash.LongImpl implements FlawedPointHash {
022        public RugHash() {
023        }
024
025        public RugHash(long state) {
026            super(state);
027        }
028
029        public long getState() {
030            return state;
031        }
032
033        public static int hashLongs(long x, long y, long s) {
034            x = (x + 0x9E3779B97F4A7C15L ^ x) * (s + y);
035            y = (y + 0x9E3779B97F4A7C15L ^ y) * (x + s);
036            s = (s + 0x9E3779B97F4A7C15L ^ s) * (y + x);
037            return (int) (s >>> 32);
038        }
039
040        public static int hashLongs(long x, long y, long z, long s) {
041            x = (x + 0x9E3779B97F4A7C15L ^ x) * (s + z);
042            y = (y + 0x9E3779B97F4A7C15L ^ y) * (x + s);
043            z = (z + 0x9E3779B97F4A7C15L ^ z) * (y + x);
044            s = (s + 0x9E3779B97F4A7C15L ^ s) * (z + y);
045            return (int) (s >>> 32);
046        }
047
048        public static int hashLongs(long x, long y, long z, long w, long s) {
049            x = (x + 0x9E3779B97F4A7C15L ^ x) * (s + w);
050            y = (y + 0x9E3779B97F4A7C15L ^ y) * (x + s);
051            z = (z + 0x9E3779B97F4A7C15L ^ z) * (y + x);
052            w = (w + 0x9E3779B97F4A7C15L ^ w) * (z + y);
053            s = (s + 0x9E3779B97F4A7C15L ^ s) * (w + z);
054            return (int) (s >>> 32);
055        }
056
057        public static int hashLongs(long x, long y, long z, long w, long u, long v, long s) {
058            x = (x + 0x9E3779B97F4A7C15L ^ x) * (s + v);
059            y = (y + 0x9E3779B97F4A7C15L ^ y) * (x + s);
060            z = (z + 0x9E3779B97F4A7C15L ^ z) * (y + x);
061            w = (w + 0x9E3779B97F4A7C15L ^ w) * (z + y);
062            u = (u + 0x9E3779B97F4A7C15L ^ u) * (w + z);
063            v = (v + 0x9E3779B97F4A7C15L ^ v) * (u + w);
064            s = (s + 0x9E3779B97F4A7C15L ^ s) * (v + u);
065            return (int) (s >>> 32);
066        }
067
068        @Override
069        public int hashWithState(int x, int y, int state) {
070            return hashLongs(x, y, state);
071        }
072
073        @Override
074        public int hashWithState(int x, int y, int z, int state) {
075            return hashLongs(x, y, z, state);
076        }
077
078        @Override
079        public int hashWithState(int x, int y, int z, int w, int state) {
080            return hashLongs(x, y, z, w, state);
081        }
082
083        @Override
084        public int hashWithState(int x, int y, int z, int w, int u, int v, int state) {
085            return hashLongs(x, y, z, w, u, v, state);
086        }
087    }
088
089    /**
090     * Extremely flawed if you're using this as a point hash, but meant to be aesthetically interesting, this produces
091     * different symmetrical patterns in squares, as if on a quilt.
092     */
093    class QuiltHash extends IPointHash.LongImpl implements FlawedPointHash {
094        private int size = 6;
095        private long mask = (1L << size) - 1L;
096        public QuiltHash() {
097        }
098
099        public QuiltHash(long state) {
100            super(state);
101        }
102
103        public QuiltHash(long state, int size) {
104            super(state);
105            setSize(size);
106        }
107
108        public long getState() {
109            return state;
110        }
111
112        public int getSize() {
113            return 1 << size;
114        }
115
116        public void setSize(int size) {
117            this.size = 32 - Integer.numberOfLeadingZeros(Math.max(1, size));
118            mask = (1L << this.size) - 1L;
119        }
120
121        public long hashLongs(long x, long y, long s) {
122            s ^= (x >> size) * 0xC13FA9A902A6328FL;
123            s ^= (y >> size) * 0x91E10DA5C79E7B1DL;
124            x *= x;
125            y *= y;
126            x = x >>> 1 & mask;
127            y = y >>> 1 & mask;
128            long t;
129            if (x < y) {
130                t = x;
131                x = y;
132                y = t;
133            }
134            x = (x + 0x9E3779B97F4A7C15L ^ x) * (s + y);
135            y = (y + 0x9E3779B97F4A7C15L ^ y) * (x + s);
136            s = (s + 0x9E3779B97F4A7C15L ^ s) * (y + x);
137            return s;
138        }
139
140        public long hashLongs(long x, long y, long z, long s) {
141            return hashLongs(x, hashLongs(y, z, s), s);
142//            s ^= (x >> size) * 0xD1B54A32D192ED03L;
143//            s ^= (y >> size) * 0xABC98388FB8FAC03L;
144//            s ^= (z >> size) * 0x8CB92BA72F3D8DD7L;
145//            x *= x;
146//            y *= y;
147//            z *= z;
148//            x &= mask;
149//            y &= mask;
150//            z &= mask;
151//            long t;
152//            if (x < y && z < y) {
153//                t = x;
154//                x = y;
155//                y = t;
156//            }
157//            else if(x < y && y < z){
158//                t = x;
159//                x = z;
160//                z = t;
161//            }
162//            else if(y < x && x < z){
163//                t = y;
164//                y = z;
165//                z = t;
166//            }
167//            else if(y < x && z < x){
168//                t = y;
169//                y = z;
170//                z = t;
171//            }
172//
173//            x = (x + 0x9E3779B97F4A7C15L ^ x) * (s + z);
174//            y = (y + 0x9E3779B97F4A7C15L ^ y) * (x + s);
175//            z = (z + 0x9E3779B97F4A7C15L ^ z) * (y + x);
176//            s = (s + 0x9E3779B97F4A7C15L ^ s) * (z + y);
177//            return (int) (s >>> 32);
178        }
179
180        public long hashLongs(long x, long y, long z, long w, long s) {
181            return hashLongs(x, hashLongs(y, hashLongs(z, w, s), s), s);
182        }
183
184        public long hashLongs(long x, long y, long z, long w, long u, long v, long s) {
185            return hashLongs(x, hashLongs(y, hashLongs(z, hashLongs(w, hashLongs(u, v, s), s), s), s), s);
186        }
187
188        @Override
189        public int hashWithState(int x, int y, int state) {
190            return (int)(hashLongs(x, y, state) >>> 32);
191        }
192
193        @Override
194        public int hashWithState(int x, int y, int z, int state) {
195            return (int)(hashLongs(x, y, z, state) >>> 32);
196        }
197
198        @Override
199        public int hashWithState(int x, int y, int z, int w, int state) {
200            return (int)(hashLongs(x, y, z, w, state) >>> 32);
201        }
202
203        @Override
204        public int hashWithState(int x, int y, int z, int w, int u, int v, int state) {
205            return (int)(hashLongs(x, y, z, w, u, v, state) >>> 32);
206        }
207    }
208
209    /**
210     * Very similar to {@link QuiltHash}, but this doesn't change the pattern in different large squares, and instead
211     * repeats a square or cube of symmetric and patterned results over and over (so it can be tiled).
212     */
213    class CubeHash extends IPointHash.LongImpl implements FlawedPointHash {
214        private int size = 6;
215        private long mask = (1L << size) - 1L;
216        public CubeHash() {
217        }
218
219        public CubeHash(long state) {
220            super(state);
221        }
222
223        public CubeHash(long state, int size) {
224            super(state);
225            setSize(size);
226        }
227
228        public long getState() {
229            return state;
230        }
231
232        public int getSize() {
233            return 1 << size;
234        }
235
236        public void setSize(int size) {
237            this.size = 32 - Integer.numberOfLeadingZeros(Math.max(1, size));
238            mask = (1L << this.size) - 1L;
239        }
240
241        public long hashLongs(long x, long y, long s) {
242            x &= mask;
243            y &= mask;
244            x *= x * 0xC13FA9A902A6328FL;
245            y *= y * 0x91E10DA5C79E7B1DL;
246            x &= mask;
247            y &= mask;
248            long t;
249            if (x < y) {
250                t = x;
251                x = y;
252                y = t;
253            }
254            x = (x + 0x9E3779B97F4A7C15L ^ x) * (s + y);
255            y = (y + 0x9E3779B97F4A7C15L ^ y) * (x + s);
256            s = (s + 0x9E3779B97F4A7C15L ^ s) * (y + x);
257            return s;
258        }
259
260        public long hashLongs(long x, long y, long z, long s) {
261            x &= mask;
262            y &= mask;
263            z &= mask;
264//            s ^= (x) * 0xD1B54A32D192ED03L;
265//            s ^= (y) * 0xABC98388FB8FAC03L;
266//            s ^= (z) * 0x8CB92BA72F3D8DD7L;
267            x *= x * 0xD1B54A32D192ED03L;
268            y *= y * 0xABC98388FB8FAC03L;
269            z *= z * 0x8CB92BA72F3D8DD7L;
270            x = x & mask;
271            y = y & mask;
272            z = z & mask;
273            long t;
274            if (x < y) {
275                t = x;
276                x = y;
277                y = t;
278            }
279            if(x < z){
280                t = x;
281                x = z;
282                z = t;
283            }
284            if(y < z){
285                t = y;
286                y = z;
287                z = t;
288            }
289            x = (x + 0x9E3779B97F4A7C15L ^ x) * (s + z);
290            y = (y + 0x9E3779B97F4A7C15L ^ y) * (x + s);
291            z = (z + 0x9E3779B97F4A7C15L ^ z) * (y + x);
292            s = (s + 0x9E3779B97F4A7C15L ^ s) * (z + y);
293            return s;
294        }
295
296        public long hashLongs(long x, long y, long z, long w, long s) {
297            return hashLongs(x, hashLongs(y, hashLongs(z, w, s), s), s);
298        }
299
300        public long hashLongs(long x, long y, long z, long w, long u, long v, long s) {
301            return hashLongs(x, hashLongs(y, hashLongs(z, hashLongs(w, hashLongs(u, v, s), s), s), s), s);
302        }
303
304        @Override
305        public int hashWithState(int x, int y, int state) {
306            return (int)(hashLongs(x, y, state) >>> 32);
307        }
308
309        @Override
310        public int hashWithState(int x, int y, int z, int state) {
311            return (int)(hashLongs(x, y, z, state) >>> 32);
312        }
313
314        @Override
315        public int hashWithState(int x, int y, int z, int w, int state) {
316            return (int)(hashLongs(x, y, z, w, state) >>> 32);
317        }
318
319        @Override
320        public int hashWithState(int x, int y, int z, int w, int u, int v, int state) {
321            return (int)(hashLongs(x, y, z, w, u, v, state) >>> 32);
322        }
323    }
324
325    /**
326     * FNV32a is OK as a hash for bytes when used in some hash tables, but it has major issues on its low-order bits
327     * when used as a point hash (the high bits aren't much better). Unfortunately, it is not aesthetically pleasing as
328     * a point hash. Some usages might be able to use it to apply a grimy, glitchy effect.
329     */
330    class FNVHash extends IntImpl implements FlawedPointHash {
331
332        public FNVHash() {
333            super();
334        }
335
336        public FNVHash(int state) {
337            super(state);
338        }
339
340        public int getState() {
341            return state;
342        }
343        @Override
344        public int hashWithState(int x, int y, int state) {
345            return ((state ^ 0x811c9dc5 ^ x) * 0x1000193 ^ y) * 0x1000193;
346        }
347
348        @Override
349        public int hashWithState(int x, int y, int z, int state) {
350            return (((state ^ 0x811c9dc5 ^ x) * 0x1000193 ^ y) * 0x1000193 ^ z) * 0x1000193;
351        }
352
353        @Override
354        public int hashWithState(int x, int y, int z, int w, int state) {
355            return ((((state ^ 0x811c9dc5 ^ x) * 0x1000193 ^ y) * 0x1000193 ^ z) * 0x1000193 ^ w) * 0x1000193;
356        }
357
358        @Override
359        public int hashWithState(int x, int y, int z, int w, int u, int v, int state) {
360            return ((((((state ^ 0x811c9dc5 ^ x) * 0x1000193 ^ y) * 0x1000193 ^ z) * 0x1000193
361                    ^ w) * 0x1000193 ^ u) * 0x1000193 ^ v) * 0x1000193;
362        }
363    }
364}