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}