001package squidpony.squidmath; 002 003import squidpony.squidgrid.Direction; 004 005import java.io.Serializable; 006 007/** 008 * A 2D coordinate with (constant) x and y fields. Coord objects are immutable; a single pool of Coord values, with 009 * x and y each ranging from -3 to 255, is shared by all users of Coord. This pool helps reduce pressure on the 010 * garbage collector when many Coord values would have been created for some purpose and quickly discarded; instead 011 * of creating a new Coord with a constructor, you use the static method {@link #get(int, int)}, which retrieves an 012 * already-existing Coord from the pool if possible, and always returns a usable Coord. 013 * <br> 014 * The Coord class is a fundamental part of SquidLib; any class that uses positions on a grid makes use of it here. 015 * It finds usage naturally in classes throughout {@link squidpony.squidgrid}, with {@link squidpony.squidgrid.zone} 016 * providing an abstraction around groups of Coord and {@link squidpony.squidgrid.iterator} providing various ways to 017 * iterate through the Coords that make up a larger shape. In this package, {@link squidpony.squidmath}, a few classes 018 * should be pointed out. {@link CoordPacker} is a class with all static methods that provides various ways to compress 019 * the memory usage of regions made of many Coord values (and can be constructed in other ways but still provide Coords 020 * later), but since Coords don't use much memory anyway, the real use of the class is for manipulating the shapes and 021 * sizes of the regions those Coords are part of. {@link GreasedRegion} has similar functionality to CoordPacker, but 022 * where CoordPacker is purely static, taking and returning regions as encoded, usually-low-memory-cost arrays of 023 * {@code short} that it considers immutable, a GreasedRegion is a mutable object that allows the same region-altering 024 * techniques to be applied in-place in a way that is relatively (very) low-time-cost. If deciding between the two, 025 * GreasedRegion should usually be preferred, and CoordPacker cannot actually be used when storing regions in larger 026 * than a 256x256 space (usually when the Coord pool has been expanded; see below); GreasedRegion can store potentially 027 * large positions. 028 * <br> 029 * More on the Coord pool used by this class: Coords can't always be retrieved from the pool; Coord.get constructs a 030 * new Coord if one of x or y is unusually large (greater than 255) or too negative (below -3). The upper limit of 255 031 * is not a hard rule; you can increase the limit on the pool by calling {@link #expandPoolTo(int, int)} or 032 * {@link #expandPool(int, int)}, which cause more memory to be spent initially on storing Coords but can save memory 033 * or ease GC pressure over the long term by preventing duplicate Coords from being created many times. The pool can 034 * never shrink because allowing that would cause completely unpredictable results if existing Coords were in use, or 035 * could easily cause crashes on Android after resuming an application that had previously shrunken the pool due to 036 * platform quirks. Long story short, you should only expand the pool size when your game needs a larger set of 2D 037 * points it will commonly use, and in most cases you shouldn't need to change it at all. 038 * 039 * Created by Tommy Ettinger on 8/12/2015. 040 */ 041public class Coord implements Serializable { 042 private static final long serialVersionUID = 300L; 043 044 /** The x-coordinate. */ 045 public final int x; 046 047 /** The y-coordinate (the ordinate) */ 048 public final int y; 049 050 protected Coord() 051 { 052 this(0, 0); 053 } 054 protected Coord(final int x, final int y) 055 { 056 this.x = x; 057 this.y = y; 058 } 059 public static Coord get(final int x, final int y) 060 { 061 if(x >= -3 && y >= -3 && x < POOL.length - 3 && y < POOL[x + 3].length - 3) 062 return POOL[x + 3][y + 3]; 063 else return new Coord(x, y); 064 } 065 066 /** 067 * Gets the angle in degrees to go between two Coords. 068 * When only x is different and {@code to.x} is greater than {@code from.x}, this returns 0. 069 * When only y is different and {@code to.y} is greater than {@code from.y}, this returns 90. 070 * When only x is different and {@code to.x} is less than {@code from.x}, this returns 180. 071 * When only y is different and {@code to.y} is less than {@code from.y}, this returns 270. 072 * In cases between these, the angle is between those values; it cannot be 360 but it can be very close. This never 073 * returns a negative angle. Keep in mind, "up" depends on how your code orients the y-axis, and SquidLib generally 074 * defaults to positive y going toward the bottom of the screen, like how later lines in a paragraph are further 075 * down on the page. 076 * <br> 077 * As a compatibility note, before SquidLib 3.0.0 stable, this used an odd rotation of the normal degrees where 0 078 * degrees were used when {@code to.y} was greater than {@code from.y} and x was equal. Because that typically runs 079 * counter to expectations from actual math, the behavior was changed. 080 * @param from the starting Coord to measure from 081 * @param to the ending Coord to measure to 082 * @return The degree from {@code from} to {@code to}; 0 is up 083 */ 084 public static double degrees(final Coord from, final Coord to) { 085 return NumberTools.atan2_(to.y - from.y, to.x - from.x) * 360.0; 086 } 087 088 /** 089 * Provided for compatibility with earlier code that used the AWT Point API. 090 * @return this Coord, without changes 091 */ 092 public Coord getLocation() 093 { 094 return this; 095 } 096 097 /** 098 * Takes this Coord, adds x to its x and y to its y, and returns the Coord at that position. 099 * @param x the amount of x distance to move 100 * @param y the amount of y distance to move 101 * @return a Coord (usually cached and not a new instance) that has been moved the specified distance 102 */ 103 public Coord translate(final int x, final int y) 104 { 105 return get(this.x + x, this.y + y); 106 } 107 /** 108 * Takes this Coord, adds x to its x and y to its y, limiting x from 0 to width and limiting y from 0 to height, 109 * and returns the Coord at that position. 110 * @param x the amount of x distance to move 111 * @param y the amount of y distance to move 112 * @param width one higher than the maximum x value this can use; typically the length of an array 113 * @param height one higher than the maximum y value this can use; typically the length of an array 114 * @return a Coord (usually cached and not a new instance) that has been moved the specified distance 115 */ 116 public Coord translateCapped(final int x, final int y, final int width, final int height) 117 { 118 return get(Math.min(Math.max(0, this.x + x), width - 1), Math.min(Math.max(0, this.y + y), height - 1)); 119 } 120 121 /** 122 * Separately combines the x and y positions of this Coord and other, producing a different Coord as their "sum." 123 * @param other another Coord 124 * @return a Coord (usually cached and not a new instance) with {@code x = this.x + other.x; y = this.y + other.y} 125 */ 126 public Coord add(final Coord other) 127 { 128 return get(x + other.x, y + other.y); 129 } 130 131 /** 132 * Separately adds the x and y positions of this Coord to operand, producing a different Coord as their 133 * "sum." 134 * @param operand a value to add each of x and y to 135 * @return a Coord (usually cached and not a new instance) with {@code x = this.x + operand; y = this.y + operand} 136 */ 137 public Coord add(final int operand) 138 { 139 return get(x + operand, y + operand); 140 } 141 142 /** 143 * Separately adds the x and y positions of this Coord to operand, rounding to the nearest int for each of x 144 * and y and producing a different Coord as their "sum." 145 * @param operand a value to add each of x and y to 146 * @return a Coord (usually cached and not a new instance) with {@code x = this.x + operand; y = this.y + 147 * operand}, with both x and y rounded accordingly 148 */ 149 public Coord add(final double operand) 150 { 151 return get((int)Math.round(x + operand), (int)Math.round(y + operand)); 152 } 153 154 /** 155 * Separately subtracts the x and y positions of other from this Coord, producing a different Coord as their 156 * "difference." 157 * @param other another Coord 158 * @return a Coord (usually cached and not a new instance) with {@code x = this.x - other.x; y = this.y - other.y} 159 */ 160 public Coord subtract(final Coord other) 161 { 162 return get(x - other.x, y - other.y); 163 } 164 165 /** 166 * Separately subtracts operand from the x and y positions of this Coord, producing a different Coord as their 167 * "difference." 168 * @param operand a value to subtract from each of x and y 169 * @return a Coord (usually cached and not a new instance) with {@code x = this.x - operand; y = this.y - operand} 170 */ 171 public Coord subtract(final int operand) 172 { 173 return get(x - operand, y - operand); 174 } 175 176 /** 177 * Separately subtracts operand from the x and y positions of this Coord, rounding to the nearest int for each of x 178 * and y and producing a different Coord as their "difference." 179 * @param operand a value to subtract from each of x and y 180 * @return a Coord (usually cached and not a new instance) with {@code x = this.x - operand; y = this.y - 181 * operand}, with both x and y rounded accordingly 182 */ 183 public Coord subtract(final double operand) 184 { 185 return get((int)Math.round(x - operand), (int)Math.round(y - operand)); 186 } 187 /** 188 * Separately multiplies the x and y positions of other from this Coord, producing a different Coord as their 189 * "product." 190 * @param other another Coord 191 * @return a Coord (usually cached and not a new instance) with {@code x = this.x * other.x; y = this.y * other.y} 192 */ 193 public Coord multiply(final Coord other) 194 { 195 return get(x * other.x, y * other.y); 196 } 197 /** 198 * Separately multiplies the x and y positions of this Coord by operand, producing a different Coord as their 199 * "product." 200 * @param operand a value to multiply each of x and y by 201 * @return a Coord (usually cached and not a new instance) with {@code x = this.x * operand; y = this.y * operand} 202 */ 203 public Coord multiply(final int operand) 204 { 205 return get(x * operand, y * operand); 206 } 207 208 /** 209 * Separately multiplies the x and y positions of this Coord by operand, rounding to the nearest int for each of x 210 * and y and producing a different Coord as their "product." 211 * @param operand a value to multiply each of x and y by 212 * @return a Coord (usually cached and not a new instance) with {@code x = this.x * operand; y = this.y * 213 * operand}, with both x and y rounded accordingly 214 */ 215 public Coord multiply(final double operand) 216 { 217 return get((int)Math.round(x * operand), (int)Math.round(y * operand)); 218 } 219 220 /** 221 * Separately divides the x and y positions of this Coord by other, producing a different Coord as their 222 * "quotient." If other has 0 for x or y, this will throw an exception, as dividing by 0 is expected to do. 223 * @param other another Coord 224 * @return a Coord (usually cached and not a new instance) with {@code x = this.x / other.x; y = this.y / other.y} 225 */ 226 public Coord divide(final Coord other) 227 { 228 return get(x / other.x, y / other.y); 229 } 230 /** 231 * Separately divides the x and y positions of this Coord by operand, producing a different Coord as their 232 * "quotient." If operand is 0, this will throw an exception, as dividing by 0 is expected to do. 233 * @param operand a value to divide each of x and y by 234 * @return a Coord (usually cached and not a new instance) with {@code x = this.x / operand; y = this.y / operand} 235 */ 236 public Coord divide(final int operand) 237 { 238 return get(x / operand, y / operand); 239 } 240 241 /** 242 * Separately divides the x and y positions of this Coord by operand, flooring to a lower int for each of x and 243 * y and producing a different Coord as their "quotient." If operand is 0.0, expect strange results (infinity and 244 * NaN are both possibilities). 245 * @param operand a value to divide each of x and y by 246 * @return a Coord (usually cached and not a new instance) with {@code x = this.x / operand; y = this.y / 247 * operand}, with both x and y rounded accordingly 248 */ 249 public Coord divide(final double operand) 250 { 251 return get((int)(x / operand), (int)(y / operand)); 252 } 253 254 /** 255 * Separately divides the x and y positions of this Coord by operand, rounding to the nearest int for each of x and 256 * y and producing a different Coord as their "quotient." If operand is 0.0, expect strange results (infinity and 257 * NaN are both possibilities). 258 * @param operand a value to divide each of x and y by 259 * @return a Coord (usually cached and not a new instance) with {@code x = this.x / operand; y = this.y / 260 * operand}, with both x and y rounded accordingly 261 */ 262 public Coord divideRounding(final double operand) 263 { 264 return get((int)Math.round(x / operand), (int)Math.round(y / operand)); 265 } 266 267 /** 268 * Separately averages the x and y positions of this Coord with other, producing a different Coord as their 269 * "midpoint." 270 * @param other another Coord 271 * @return a Coord (usually cached and not a new instance) halfway between this and other, rounded nearest. 272 */ 273 public Coord average(final Coord other) 274 { 275 return get(Math.round((x + other.x) / 2.0f), Math.round((y + other.y) / 2.0f)); 276 } 277 /** 278 * @param d 279 * A non-{@code null} direction. 280 * @return The coordinate obtained by applying {@code d} on {@code this}. 281 */ 282 public Coord translate(final Direction d) { 283 return Coord.get(x + d.deltaX, y + d.deltaY); 284 } 285 286 /** 287 * @param i 288 * @return {@code (x*i,y*i)}. 289 */ 290 public Coord scale(final int i) { 291 return Coord.get(x * i, y * i); 292 } 293 294 /** 295 * @param i 296 * @return {@code (x*i,y*j)}. 297 */ 298 public Coord scale(final int i, final int j) { 299 return Coord.get(x * i, y * j); 300 } 301 302 public double distance(final double x2, final double y2) 303 { 304 return Math.sqrt((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y)); 305 } 306 public double distance(final Coord co) 307 { 308 return Math.sqrt((co.x - x) * (co.x - x) + (co.y - y) * (co.y - y)); 309 } 310 public double distanceSq(final double x2, final double y2) 311 { 312 return (x2 - x) * (x2 - x) + (y2 - y) * (y2 - y); 313 } 314 public double distanceSq(final Coord co) { return (co.x - x) * (co.x - x) + (co.y - y) * (co.y - y); } 315 316 /** 317 * Gets a Coord based off this instance but with odd values for x and/or y decreased to the nearest even number. 318 * May be useful for thin-wall maps as produced by {@link squidpony.squidgrid.mapping.ThinDungeonGenerator} and used 319 * with {@link squidpony.squidgrid.Adjacency.ThinWallAdjacency}. 320 * @return a Coord (probably from the pool) with even x and even y, changing (decrementing) only if they are odd 321 */ 322 public Coord makeEven() 323 { 324 return get(x & -2, y & -2); 325 } 326 327 /** 328 * Gets a Coord based off this instance but with even values for x and/or y increased to the nearest odd number. 329 * May be useful for thin-wall maps as produced by {@link squidpony.squidgrid.mapping.ThinDungeonGenerator} and used 330 * with {@link squidpony.squidgrid.Adjacency.ThinWallAdjacency}. 331 * @return a Coord (probably from the pool) with odd x and odd y, changing (incrementing) only if they are even 332 */ 333 public Coord makeOdd() { 334 return get(x | 1, y | 1); 335 } 336 337 /** 338 * @param c 339 * @return Whether {@code this} is adjacent to {@code c}. Not that a cell is 340 * not adjacent to itself with this method. 341 */ 342 public boolean isAdjacent(final Coord c) { 343 switch (Math.abs(x - c.x)) { 344 case 0: 345 return Math.abs(y - c.y) == 1; 346 case 1: 347 return y == c.y || Math.abs(y - c.y) == 1; 348 default: 349 return false; 350 } 351 } 352 353 /** 354 * Gets the {@link Direction} needed to get to {@code target} from this; typically this is more useful when target 355 * and this are adjacent (by {@link #isAdjacent(Coord)}) since that should make it possible to go to target. 356 * <br> 357 * Internally, this delegates to {@link Direction#toGoTo(Coord, Coord)}, and some code may prefer using the method 358 * in Direction instead of this one. Earlier versions of this code only worked for adjacent Coords, which seemed 359 * like an unnecessary limitation since Direction's version worked for any arguments. 360 * @param target a non-null {@link Coord} 361 * @return the direction to go from {@code this} to {@code target} 362 */ 363 public Direction toGoTo(final Coord target) { 364 return Direction.toGoTo(this, target); 365 } 366 367 /** 368 * Returns true if x is between 0 (inclusive) and width (exclusive) and y is between 0 (inclusive) and height 369 * (exclusive), false otherwise. 370 * @param width the upper limit on x to check, exclusive 371 * @param height the upper limit on y to check, exclusive 372 * @return true if this Coord is within the limits of width and height and has non-negative x and y 373 */ 374 public boolean isWithin(final int width, final int height) 375 { 376 return x >= 0 && y >= 0 && x < width && y < height; 377 } 378 /** 379 * Returns true if x is between minX (inclusive) and maxX (exclusive) and y is between minY (inclusive) and maxY 380 * (exclusive), false otherwise. 381 * @param minX the lower limit on x to check, inclusive 382 * @param minY the lower limit on y to check, inclusive 383 * @param maxX the upper limit on x to check, exclusive 384 * @param maxY the upper limit on y to check, exclusive 385 * @return true if this Coord is within the limits of the given parameters 386 */ 387 public boolean isWithinRectangle(int minX, int minY, int maxX, int maxY) 388 { 389 return x >= minX && y >= minY && x < maxX && y < maxY; 390 } 391 public int getX() { 392 return x; 393 } 394 395 public Coord setX(final int x) { 396 return get(x, y); 397 } 398 399 public int getY() { 400 return y; 401 } 402 403 public Coord setY(final int y) { 404 return get(x, y); 405 } 406 407 @Override 408 public String toString() 409 { 410 return "(" + x + "," + y + ")"; 411 } 412 413 /** 414 * Gets the hash code for this Coord; does not use the standard "auto-complete" style of hash that most IDEs will 415 * generate, but instead uses a highly-specific technique based on the Rosenberg-Strong pairing function, a Gray 416 * code, and two XLCG steps at the end. It manages to get extremely low collision rates under many circumstances, 417 * and very frequently manages to avoid colliding on more than 25% of Coords (making the load factor of most 418 * hash-based collections fine at a default of 0.75) while often having 0 collisions with some data sets. 419 * It does much better when Coords are in the default pooled range of -3 or greater. 420 * <br> 421 * This gets slightly better collision rates than previous versions used by SquidLib, around 4% across a wide 422 * variety of rectangular areas (most earlier hashes got about-5%-range collision rates, and using 423 * {@link java.util.Objects#hash(Object...)} gives more than a 75% collision rate). The previous version, which is 424 * still available as {@link #cantorHashCode(int, int)}, has slightly better results when used for seeding 425 * procedural generation based on a Coord (a reasonable usage of this method), but both this hash code and the 426 * Cantor-based one have excellent randomness in the upper bits of the hash (so if you use a hashCode() result as a 427 * whole int, then it should be pretty good as a seed). The method before the Cantor-based one, 428 * {@link #xoroHashCode(int, int)} was structured a little like xoroshiro ({@link XoRoRNG} uses the 64-bit version 429 * of xoroshiro), and while it had pretty low collision rates (low 5% range), its hash codes changed bits in large 430 * checkerboard patterns, leaving heavy square-shaped biases in generated results. 431 * <br> 432 * This changed at least 7 times in SquidLib's history. In general, you shouldn't rely on hashCodes to stay the 433 * same across platforms and versions, whether for the JDK or this library. SquidLib (tries to) never depend on the 434 * unpredictable ordering of some hash-based collections like HashSet and HashMap, instead using its own 435 * {@link OrderedSet} and {@link OrderedMap}; if you use the ordered kinds, then the only things that matter about 436 * this hash code are that it's fast (it's fast enough), it's cross-platform compatible (this version avoids using 437 * long values, which are slow on GWT, and is carefully written to behave the same on GWT as desktop) and that it 438 * doesn't collide often (which is now much more accurate than in earlier versions of this method). 439 * @see #rosenbergStrongHashCode(int, int) A static method that gets the same result as this method without involving a Coord 440 * @return an int that should, for most different Coord values, be significantly different from the other hash codes 441 */ 442 @Override 443 public int hashCode() { 444 //// for Coord, since it can be as low as -3, and Rosenberg-Strong works only for positive integers 445 final int x = this.x + 3; 446 final int y = this.y + 3; 447 //// Rosenberg-Strong pairing function; has excellent traits for keeping the hash gap-less while the 448 //// inputs fit inside a square, and is still good for rectangles. 449 final int n = (x >= y ? x * (x + 2) - y : y * y + x); 450 //// Gray code, XLCG, XLCG (ending on a XOR to stay within int range on GWT). 451 //// The Gray code moves bits around just a little, but keeps the same power-of-two upper bound. 452 //// the XLCGs together only really randomize the upper bits; they don't change the lower bit at all. 453 //// (recall from RNG class that an XLCG is a XOR by a constant, then a multiply by a constant, where 454 //// the XOR constant, mod 8, is 5, while the multiplier, mod 8, is 3; the order can be reversed too.) 455 //// ending on a XOR helps mostly for GWT. 456 return ((n ^ n >>> 1) * 0x9E373 ^ 0xD1B54A35) * 0x125493 ^ 0x91E10DA5; 457 } 458 459 /** 460 * A static version of an earlier {@link #hashCode()} method of this class, taking x and y as parameters instead of 461 * requiring a Coord object. Like the earlier hashCode() method, this involves the close-to-optimal mathematical 462 * Cantor pairing function to distribute x and y without overlap until they get very large. Cantor's pairing 463 * function can be written simply as {@code ((x + y) * (x + y + 1)) / 2 + y}; it produces sequential results for a 464 * sequence of positive points traveling in diagonal stripes away from the origin. The finalization steps this 465 * performs improve the randomness of the lower bits, but also worsen collision rates; most cases involving Coords 466 * will see lower collision rates from {@link #rosenbergStrongHashCode(int, int)}, but more random results from this 467 * method. 468 * @param x the x coordinate of the "imaginary Coord" to hash 469 * @param y the y coordinate of the "imaginary Coord" to hash 470 * @return the equivalent to the hashCode() of an "imaginary Coord" 471 */ 472 public static int cantorHashCode(int x, int y) { 473 x ^= x >> 31; 474 y ^= y >> 31; 475 y += ((x + y) * (x + y + 1) >> 1); 476 y ^= y >>> 1 ^ y >>> 6; 477 return (y ^ (y << 15 | y >>> 17) ^ (y << 23 | y >>> 9)) * 0x125493 ^ 0xD1B54A35; 478 } 479 /** 480 * A static version of the current {@link #hashCode()} method of this class, taking x and y as parameters instead of 481 * requiring a Coord object. Like the current hashCode() method, this involves the close-to-optimal mathematical 482 * Rosenberg-Strong pairing function to distribute x and y without overlap until they get very large. The 483 * Rosenberg-Strong pairing function can be written simply as {@code ((x >= y) ? x * (x + 2) - y : y * y + x)}; it 484 * produces sequential results for a sequence of positive points traveling in square "shells" away from the origin. 485 * <a href="https://hbfs.wordpress.com/2018/08/07/moeud-deux/">the algorithm is discussed more here</a>; the only 486 * changes this makes are adding 3 to x and y (to account for the minimum of -3 in most cases for a Coord), and some 487 * finalizing steps that help randomize the upper bits of the hash code (the lower bits are quite non-random because 488 * they can't permit any gaps while optimizing collision rates). 489 * @param x the x coordinate of the "imaginary Coord" to hash 490 * @param y the y coordinate of the "imaginary Coord" to hash 491 * @return the equivalent to the hashCode() of an "imaginary Coord" 492 */ 493 public static int rosenbergStrongHashCode(int x, int y) { 494 //// for Coord, since it can be as low as -3, and Rosenberg-Strong works only for positive integers 495 x += 3; 496 y += 3; 497 //// Rosenberg-Strong pairing function; has excellent traits for keeping the hash gap-less while the 498 //// inputs fit inside a square, and is still good for rectangles. 499 final int n = (x >= y ? x * (x + 2) - y : y * y + x); 500 //// Gray code, XLCG, XLCG (ending on a XOR to stay within int range on GWT). 501 //// The Gray code moves bits around just a little, but keeps the same power-of-two upper bound. 502 //// the XLCGs together only really randomize the upper bits; they don't change the lower bit at all. 503 //// (recall from RNG class that an XLCG is a XOR by a constant, then a multiply by a constant, where 504 //// the XOR constant, mod 8, is 5, while the multiplier, mod 8, is 3; the order can be reversed too.) 505 //// ending on a XOR helps mostly for GWT. 506 return ((n ^ n >>> 1) * 0x9E373 ^ 0xD1B54A35) * 0x125493 ^ 0x91E10DA5; 507 } 508 /** 509 * An earlier hashCode() implementation used by this class, now standalone in case you want to replicate the results 510 * of the older code. This uses only bitwise operations, which tend to be fairly fast on all platforms, and when 511 * used in a collection it has comparable collision rates to the current hashCode() method (very, very low rates), 512 * but if used for procedural generation it's simply terrible, with large blocks of nearby x,y points having 513 * identical values for several bits and all changes happening in a repetitive checkerboard pattern. It is 514 * structured very similarly to {@link XoRoRNG} and {@link Lathe32RNG} in particular, but using only bitwise math. 515 * @param x the x coordinate of the "imaginary Coord" to hash 516 * @param y the y coordinate of the "imaginary Coord" to hash 517 * @return the equivalent to the hashCode() of an "imaginary Coord" 518 */ 519 public static int xoroHashCode(final int x, final int y) { 520 int r = x ^ y; 521 r ^= (x << 13 | x >>> 19) ^ (r << 5) ^ (r << 28 | r >>> 4); 522 r = x ^ (r << 11 | r >>> 21); 523 return r ^ (r << 25 | r >>> 7); 524 } 525 526 /** 527 * Something like hashCode(), but reversible with {@code Coord.decode()}. Works for Coords between roughly -256 and 528 * 32000 in each of x and y, but will probably only decode to pooled Coords if x and y are both between -3 and 255 529 * (inclusive for both). 530 * @return an int as a unique code for this Coord 531 */ 532 public int encode() 533 { 534 return ((x + 256) << 16) ^ (y + 256); 535 } 536 537 /** 538 * An alternative to getting a Coord with Coord.get() only to encode() it as the next step. This doesn't create a 539 * Coord in the middle step. Can be decoded with Coord.decode() to get the (x,y) Coord. 540 * @param x the x position to encode 541 * @param y the y position to encode 542 * @return the coded int that a Coord at (x,y) would produce with encode() 543 */ 544 public static int pureEncode(final int x, final int y) 545 { 546 return ((x + 256) << 16) ^ (y + 256); 547 } 548 /** 549 * This can take an int produced by {@code someCoord.encode()} and get the original Coord back out of it. It 550 * works for all pooled Coords where the pool hasn't been expanded past about 32,000 in either dimension. It even 551 * works for Coords with negative x or y as well, if they are no lower than -256 in either dimension. This will 552 * almost certainly fail (producing a gibberish Coord that probably won't be pooled) on hashes produced by any other 553 * class, including subclasses of Coord. 554 * @param code an encoded int from a Coord, but not a subclass of Coord 555 * @return the Coord that gave hash as its hashCode() 556 */ 557 public static Coord decode(final int code) 558 { 559 return get((code >>> 16) - 256, (code & 0xFFFF) - 256); 560 } 561 562 @Override 563 public boolean equals(Object o) { 564 if (o instanceof Coord) { 565 Coord other = (Coord) o; 566 return x == other.x && y == other.y; 567 } else { 568 return false; 569 } 570 } 571 private static Coord[][] POOL = new Coord[259][259]; 572 static { 573 int width = POOL.length, height = POOL[0].length; 574 for (int i = 0; i < width; i++) { 575 for (int j = 0; j < height; j++) { 576 POOL[i][j] = new Coord(i - 3, j - 3); 577 } 578 } 579 } 580 581 /** 582 * Gets the width of the pool used as a cache for Coords, not including negative Coords. 583 * Unless expandPool() has been called, this should be 256. 584 * Useful for finding the upper (exclusive) bound for x values that can be used efficiently in Coords. 585 * Requesting a Coord with a x greater than or equal to this value will result in a new Coord being allocated and 586 * not cached, which may cause problems with code that expects the normal reference equality of Coords to be upheld 587 * and in extreme cases may require more time garbage collecting than is normally necessary. 588 * @return the width of the Coord cache, disregarding negative Coords 589 */ 590 public static int getCacheWidth() 591 { 592 return POOL.length - 3; 593 } 594 595 /** 596 * Gets the height of the pool used as a cache for Coords, not including negative Coords. 597 * Unless expandPool() has been called, this should be 256. 598 * Useful for finding the upper (exclusive) bound for y values that can be used efficiently in Coords. 599 * Requesting a Coord with a y greater than or equal to this value will result in a new Coord being allocated and 600 * not cached, which may cause problems with code that expects the normal reference equality of Coords to be upheld 601 * and in extreme cases may require more time garbage collecting than is normally necessary. 602 * @return the height of the Coord cache, disregarding negative Coords 603 */ 604 public static int getCacheHeight() 605 { 606 return POOL[0].length - 3; 607 } 608 609 /** 610 * Enlarges the pool of cached Coords to the given width and height, and doesn't change 611 * a dimension if it would be reduced in size. 612 * Cached Coord values will be reused by Coord.get instead of re-allocated each time. 613 * The default pool allows Coords with x and y each between -3 and 255, inclusive, to 614 * be cached, and is considered to have width and height of 256 to begin with. Giving a 615 * width greater than 256 will allow Coords with x greater than 255 to be cached; 616 * likewise for height. If width or height is smaller than the current cache width or 617 * height, that dimension will not change, but the other still may if it is valid. You 618 * cannot shrink the pool size. 619 * @param width the new width for the pool of cached Coords; will be ignored if smaller than the current width 620 * @param height the new height for the pool of cached Coords; will be ignored if smaller than the current height 621 */ 622 public static void expandPoolTo(final int width, final int height) 623 { 624 expandPool(Math.max(0, width + 3 - POOL.length), Math.max(0, height + 3 - POOL[0].length)); 625 } 626 627 /** 628 * Enlarges the pool of cached Coords by the given amount of expansion for x and y. 629 * Cached Coord values will be reused by Coord.get instead of re-allocated each time. 630 * The default pool allows Coords with x and y each between -3 and 255, inclusive, to 631 * be cached, and this can increase the size in the positive direction. If either 632 * xIncrease or yIncrease is negative, this method returns immediately and does nothing 633 * else; the same is true of both arguments are zero. You cannot shrink the pool size. 634 * @param xIncrease the amount to increase cache's width by 635 * @param yIncrease the amount to increase cache's height by 636 */ 637 public static void expandPool(final int xIncrease, final int yIncrease) 638 { 639 if(xIncrease < 0 || yIncrease < 0 || (xIncrease | yIncrease) == 0 ) 640 return; 641 int width = POOL.length, height = POOL[0].length; 642 Coord[][] POOL2 = new Coord[width + xIncrease][height + yIncrease]; 643 for (int i = 0; i < width; i++) { 644 POOL2[i] = new Coord[height + yIncrease]; 645 System.arraycopy(POOL[i], 0, POOL2[i], 0, height); 646 for (int j = 0; j < height + yIncrease; j++) { 647 if(POOL2[i][j] == null) POOL2[i][j] = new Coord(i - 3, j - 3); 648 } 649 } 650 for (int i = width; i < width + xIncrease; i++) { 651 POOL2[i] = new Coord[height + yIncrease]; 652 for (int j = 0; j < height + yIncrease; j++) { 653 POOL2[i][j] = new Coord(i - 3, j - 3); 654 } 655 } 656 POOL = POOL2; 657 } 658 659 public Coord interpolate(Coord end, float amountTraveled) { 660 return Coord.get(x + Math.round((end.x - x) * amountTraveled), 661 y + Math.round((end.y - y) * amountTraveled)); 662 } 663}