001package squidpony; 002 003import java.util.ArrayList; 004import java.util.Arrays; 005 006/** 007 * Static methods for various frequently-used operations on 1D and 2D arrays. Has methods for copying, inserting, and 008 * filling 2D arrays of primitive types (char, int, double, and boolean). Has a few mehods for creating ranges of ints 009 * or chars easily as 1D arrays. Also contains certain methods for working with orderings, which can be naturally used 010 * with {@link squidpony.squidmath.OrderedMap}, {@link squidpony.squidmath.OrderedSet}, {@link squidpony.squidmath.K2}, 011 * and similar ordered collections plus ArrayList using {@link #reorder(ArrayList, int...)} in this class. 012 * Created by Tommy Ettinger on 11/17/2016. 013 */ 014public class ArrayTools { 015 016 static final char[] letters = { 017 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 018 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'À', 'Á', 019 'Â', 'Ã', 'Ä', 'Å', 'Æ', 'Ç', 'È', 'É', 'Ê', 'Ë', 'Ì', 'Í', 'Î', 'Ï', 'Ð', 'Ñ', 'Ò', 'Ó', 'Ô', 'Õ', 'Ö', 'Ø', 'Ù', 'Ú', 'Û', 'Ü', 'Ý', 020 'Þ', 'ß', 'à', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è', 'é', 'ê', 'ë', 'ì', 'í', 'î', 'ï', 'ð', 'ñ', 'ò', 'ó', 'ô', 'õ', 'ö', 'ø', 'ù', 021 'ú', 'û', 'ü', 'ý', 'þ', 'ÿ', 'Ā', 'ā', 'Ă', 'ă', 'Ą', 'ą', 'Ć', 'ć', 'Ĉ', 'ĉ', 'Ċ', 'ċ', 'Č', 'č', 'Ď', 'ď', 'Đ', 'đ', 'Ē', 'ē', 'Ĕ', 022 'ĕ', 'Ė', 'ė', 'Ę', 'ę', 'Ě', 'ě', 'Ĝ', 'ĝ', 'Ğ', 'ğ', 'Ġ', 'ġ', 'Ģ', 'ģ', 'Ĥ', 'ĥ', 'Ħ', 'ħ', 'Ĩ', 'ĩ', 'Ī', 'ī', 'Ĭ', 'ĭ', 'Į', 'į', 023 'İ', 'ı', 'Ĵ', 'ĵ', 'Ķ', 'ķ', 'ĸ', 'Ĺ', 'ĺ', 'Ļ', 'ļ', 'Ľ', 'ľ', 'Ŀ', 'ŀ', 'Ł', 'ł', 'Ń', 'ń', 'Ņ', 'ņ', 'Ň', 'ň', 'ʼn', 'Ō', 'ō', 'Ŏ', 024 'ŏ', 'Ő', 'ő', 'Œ', 'œ', 'Ŕ', 'ŕ', 'Ŗ', 'ŗ', 'Ř', 'ř', 'Ś', 'ś', 'Ŝ', 'ŝ', 'Ş', 'ş', 'Š', 'š', 'Ţ', 'ţ', 'Ť', 'ť', 'Ŧ', 'ŧ', 'Ũ', 'ũ', 025 'Ū', 'ū', 'Ŭ', 'ŭ', 'Ů', 'ů', 'Ű', 'ű', 'Ų', 'ų', 'Ŵ', 'ŵ', 'Ŷ', 'ŷ', 'Ÿ', 'Ź', 'ź', 'Ż', 'ż', 'Ž', 'ž', 'Ǿ', 'ǿ', 'Ș', 'ș', 'Ț', 'ț', 026 'Γ', 'Δ', 'Θ', 'Λ', 'Ξ', 'Π', 'Σ', 'Φ', 'Ψ', 'Ω', 'α', 'β', 'γ'}; 027 static final char[] empty = new char[0]; 028 029 /** 030 * Stupidly simple convenience method that produces a range from 0 to end, not including end, as an int array. 031 * 032 * @param end the exclusive upper bound on the range 033 * @return the range of ints as an int array 034 */ 035 public static int[] range(int end) { 036 if (end <= 0) 037 return new int[0]; 038 int[] r = new int[end]; 039 for (int i = 0; i < end; i++) { 040 r[i] = i; 041 } 042 return r; 043 } 044 045 /** 046 * Stupidly simple convenience method that produces a range from start to end, not including end, as an int array. 047 * 048 * @param start the inclusive lower bound on the range 049 * @param end the exclusive upper bound on the range 050 * @return the range of ints as an int array 051 */ 052 public static int[] range(int start, int end) { 053 if (end - start <= 0) 054 return new int[0]; 055 int[] r = new int[end - start]; 056 for (int i = 0, n = start; n < end; i++, n++) { 057 r[i] = n; 058 } 059 return r; 060 } 061 062 /** 063 * Stupidly simple convenience method that produces a char range from start to end, including end, as a char array. 064 * 065 * @param start the inclusive lower bound on the range, such as 'a' 066 * @param end the inclusive upper bound on the range, such as 'z' 067 * @return the range of chars as a char array 068 */ 069 public static char[] charSpan(char start, char end) { 070 if (end - start <= 0) 071 return empty; 072 if (end == 0xffff) { 073 074 char[] r = new char[0x10000 - start]; 075 for (char i = 0, n = start; n < end; i++, n++) { 076 r[i] = n; 077 } 078 r[0xffff - start] = 0xffff; 079 return r; 080 } 081 char[] r = new char[end - start + 1]; 082 for (char i = 0, n = start; n <= end; i++, n++) { 083 r[i] = n; 084 } 085 return r; 086 } 087 088 /** 089 * Stupidly simple convenience method that produces a char array containing only letters that can be reasonably 090 * displayed (with SquidLib's default text display assets, at least). The letters are copied from a single source 091 * of 256 chars; if you need more chars or you don't need pure letters, you can use {@link #charSpan(char, char)}. 092 * This set does not contain "visual duplicate" letters, such as Latin alphabet capital letter 'A' and Greek 093 * alphabet capital letter alpha, 'Α'; it does contain many accented Latin letters and the visually-distinct Greek 094 * letters, up to a point. 095 * @param charCount the number of letters to return in an array; the maximum this will produce is 256 096 * @return the range of letters as a char array 097 */ 098 public static char[] letterSpan(int charCount) { 099 if (charCount <= 0) 100 return empty; 101 char[] r = new char[Math.min(charCount, 256)]; 102 System.arraycopy(letters, 0, r, 0, r.length); 103 return r; 104 } 105 106 /** 107 * Gets the nth letter from the set that SquidLib is likely to support; from index 0 (returning 'A') to 255 108 * (returning the Greek lower-case letter gamma, 'γ') and wrapping around if given negative numbers or numbers 109 * larger than 255. This set does not contain "visual duplicate" letters, such as Latin alphabet capital letter 'A' 110 * and Greek alphabet capital letter alpha, 'Α'; it does contain many accented Latin letters and the 111 * visually-distinct Greek letters, up to a point. 112 * @param index typically from 0 to 255, but all ints are allowed and will produce letters 113 * @return the letter at the given index in a 256-element portion of the letters SquidLib usually supports 114 */ 115 public static char letterAt(int index) 116 { 117 return letters[index & 255]; 118 } 119 120 /** 121 * Gets a copy of the 2D char array, source, that has the same data but shares no references with source. 122 * 123 * @param source a 2D char array 124 * @return a copy of source, or null if source is null 125 */ 126 public static char[][] copy(char[][] source) { 127 if (source == null) 128 return null; 129 if (source.length < 1) 130 return new char[0][0]; 131 char[][] target = new char[source.length][]; 132 for (int i = 0; i < source.length; i++) { 133 target[i] = new char[source[i].length]; 134 System.arraycopy(source[i], 0, target[i], 0, source[i].length); 135 } 136 return target; 137 } 138 139 /** 140 * Gets a copy of the 2D double array, source, that has the same data but shares no references with source. 141 * 142 * @param source a 2D double array 143 * @return a copy of source, or null if source is null 144 */ 145 public static double[][] copy(double[][] source) { 146 if (source == null) 147 return null; 148 if (source.length < 1) 149 return new double[0][0]; 150 double[][] target = new double[source.length][]; 151 for (int i = 0; i < source.length; i++) { 152 target[i] = new double[source[i].length]; 153 System.arraycopy(source[i], 0, target[i], 0, source[i].length); 154 } 155 return target; 156 } 157 158 159 /** 160 * Gets a copy of the 2D float array, source, that has the same data but shares no references with source. 161 * 162 * @param source a 2D float array 163 * @return a copy of source, or null if source is null 164 */ 165 public static float[][] copy(float[][] source) { 166 if (source == null) 167 return null; 168 if (source.length < 1) 169 return new float[0][0]; 170 float[][] target = new float[source.length][]; 171 for (int i = 0; i < source.length; i++) { 172 target[i] = new float[source[i].length]; 173 System.arraycopy(source[i], 0, target[i], 0, source[i].length); 174 } 175 return target; 176 } 177 178 /** 179 * Gets a copy of the 2D int array, source, that has the same data but shares no references with source. 180 * 181 * @param source a 2D int array 182 * @return a copy of source, or null if source is null 183 */ 184 public static int[][] copy(int[][] source) { 185 if (source == null) 186 return null; 187 if (source.length < 1) 188 return new int[0][0]; 189 int[][] target = new int[source.length][]; 190 for (int i = 0; i < source.length; i++) { 191 target[i] = new int[source[i].length]; 192 System.arraycopy(source[i], 0, target[i], 0, source[i].length); 193 } 194 return target; 195 } 196 197 /** 198 * Gets a copy of the 2D boolean array, source, that has the same data but shares no references with source. 199 * 200 * @param source a 2D boolean array 201 * @return a copy of source, or null if source is null 202 */ 203 public static boolean[][] copy(boolean[][] source) { 204 if (source == null) 205 return null; 206 if (source.length < 1) 207 return new boolean[0][0]; 208 boolean[][] target = new boolean[source.length][]; 209 for (int i = 0; i < source.length; i++) { 210 target[i] = new boolean[source[i].length]; 211 System.arraycopy(source[i], 0, target[i], 0, source[i].length); 212 } 213 return target; 214 } 215 216 /** 217 * Inserts as much of source into target at the given x,y position as target can hold or source can supply. 218 * Modifies target in-place and also returns target for chaining. 219 * Used primarily to place a smaller array into a different position in a larger array, often freshly allocated. 220 * 221 * @param source a 2D char array that will be copied and inserted into target 222 * @param target a 2D char array that will be modified by receiving as much of source as it can hold 223 * @param x the x position in target to receive the items from the first cell in source 224 * @param y the y position in target to receive the items from the first cell in source 225 * @return target, modified, with source inserted into it at the given position 226 */ 227 public static char[][] insert(char[][] source, char[][] target, int x, int y) { 228 if (source == null || target == null) 229 return target; 230 if (source.length < 1 || source[0].length < 1) 231 return copy(target); 232 for (int i = 0; i < source.length && x + i < target.length; i++) { 233 System.arraycopy(source[i], 0, target[x + i], y, Math.min(source[i].length, target[x + i].length - y)); 234 } 235 return target; 236 } 237 238 /** 239 * Inserts as much of source into target at the given x,y position as target can hold or source can supply. 240 * Modifies target in-place and also returns target for chaining. 241 * Used primarily to place a smaller array into a different position in a larger array, often freshly allocated. 242 * 243 * @param source a 2D double array that will be copied and inserted into target 244 * @param target a 2D double array that will be modified by receiving as much of source as it can hold 245 * @param x the x position in target to receive the items from the first cell in source 246 * @param y the y position in target to receive the items from the first cell in source 247 * @return target, modified, with source inserted into it at the given position 248 */ 249 public static double[][] insert(double[][] source, double[][] target, int x, int y) { 250 if (source == null || target == null) 251 return target; 252 if (source.length < 1 || source[0].length < 1) 253 return copy(target); 254 for (int i = 0; i < source.length && x + i < target.length; i++) { 255 System.arraycopy(source[i], 0, target[x + i], y, Math.min(source[i].length, target[x + i].length - y)); 256 } 257 return target; 258 } 259 260 /** 261 * Inserts as much of source into target at the given x,y position as target can hold or source can supply. 262 * Modifies target in-place and also returns target for chaining. 263 * Used primarily to place a smaller array into a different position in a larger array, often freshly allocated. 264 * 265 * @param source a 2D float array that will be copied and inserted into target 266 * @param target a 2D float array that will be modified by receiving as much of source as it can hold 267 * @param x the x position in target to receive the items from the first cell in source 268 * @param y the y position in target to receive the items from the first cell in source 269 * @return target, modified, with source inserted into it at the given position 270 */ 271 public static float[][] insert(float[][] source, float[][] target, int x, int y) { 272 if (source == null || target == null) 273 return target; 274 if (source.length < 1 || source[0].length < 1) 275 return copy(target); 276 for (int i = 0; i < source.length && x + i < target.length; i++) { 277 System.arraycopy(source[i], 0, target[x + i], y, Math.min(source[i].length, target[x + i].length - y)); 278 } 279 return target; 280 } 281 282 /** 283 * Inserts as much of source into target at the given x,y position as target can hold or source can supply. 284 * Modifies target in-place and also returns target for chaining. 285 * Used primarily to place a smaller array into a different position in a larger array, often freshly allocated. 286 * 287 * @param source a 2D int array that will be copied and inserted into target 288 * @param target a 2D int array that will be modified by receiving as much of source as it can hold 289 * @param x the x position in target to receive the items from the first cell in source 290 * @param y the y position in target to receive the items from the first cell in source 291 * @return target, modified, with source inserted into it at the given position 292 */ 293 public static int[][] insert(int[][] source, int[][] target, int x, int y) { 294 if (source == null || target == null) 295 return target; 296 if (source.length < 1 || source[0].length < 1) 297 return copy(target); 298 for (int i = 0; i < source.length && x + i < target.length; i++) { 299 System.arraycopy(source[i], 0, target[x + i], y, Math.min(source[i].length, target[x + i].length - y)); 300 } 301 return target; 302 } 303 304 /** 305 * Inserts as much of source into target at the given x,y position as target can hold or source can supply. 306 * Modifies target in-place and also returns target for chaining. 307 * Used primarily to place a smaller array into a different position in a larger array, often freshly allocated. 308 * 309 * @param source a 2D boolean array that will be copied and inserted into target 310 * @param target a 2D boolean array that will be modified by receiving as much of source as it can hold 311 * @param x the x position in target to receive the items from the first cell in source 312 * @param y the y position in target to receive the items from the first cell in source 313 * @return target, modified, with source inserted into it at the given position 314 */ 315 public static boolean[][] insert(boolean[][] source, boolean[][] target, int x, int y) { 316 if (source == null || target == null) 317 return target; 318 if (source.length < 1 || source[0].length < 1) 319 return copy(target); 320 for (int i = 0; i < source.length && x + i < target.length; i++) { 321 System.arraycopy(source[i], 0, target[x + i], y, Math.min(source[i].length, target[x + i].length - y)); 322 } 323 return target; 324 } 325 326 /** 327 * Creates a 2D array of the given width and height, filled with entirely with the value contents. 328 * You may want to use {@link #fill(char[][], char)} to modify an existing 2D array instead. 329 * @param contents the value to fill the array with 330 * @param width the desired width 331 * @param height the desired height 332 * @return a freshly allocated 2D array of the requested dimensions, filled entirely with contents 333 */ 334 public static char[][] fill(char contents, int width, int height) { 335 char[][] next = new char[width][height]; 336 for (int x = 0; x < width; x++) { 337 Arrays.fill(next[x], contents); 338 } 339 return next; 340 } 341 342 /** 343 * Creates a 2D array of the given width and height, filled with entirely with the value contents. 344 * You may want to use {@link #fill(float[][], float)} to modify an existing 2D array instead. 345 * @param contents the value to fill the array with 346 * @param width the desired width 347 * @param height the desired height 348 * @return a freshly allocated 2D array of the requested dimensions, filled entirely with contents 349 */ 350 public static float[][] fill(float contents, int width, int height) { 351 float[][] next = new float[width][height]; 352 for (int x = 0; x < width; x++) { 353 Arrays.fill(next[x], contents); 354 } 355 return next; 356 } 357 358 /** 359 * Creates a 2D array of the given width and height, filled with entirely with the value contents. 360 * You may want to use {@link #fill(double[][], double)} to modify an existing 2D array instead. 361 * @param contents the value to fill the array with 362 * @param width the desired width 363 * @param height the desired height 364 * @return a freshly allocated 2D array of the requested dimensions, filled entirely with contents 365 */ 366 public static double[][] fill(double contents, int width, int height) { 367 double[][] next = new double[width][height]; 368 for (int x = 0; x < width; x++) { 369 Arrays.fill(next[x], contents); 370 } 371 return next; 372 } 373 374 /** 375 * Creates a 2D array of the given width and height, filled with entirely with the value contents. 376 * You may want to use {@link #fill(int[][], int)} to modify an existing 2D array instead. 377 * @param contents the value to fill the array with 378 * @param width the desired width 379 * @param height the desired height 380 * @return a freshly allocated 2D array of the requested dimensions, filled entirely with contents 381 */ 382 public static int[][] fill(int contents, int width, int height) { 383 int[][] next = new int[width][height]; 384 for (int x = 0; x < width; x++) { 385 Arrays.fill(next[x], contents); 386 } 387 return next; 388 } 389 390 /** 391 * Creates a 2D array of the given width and height, filled with entirely with the value contents. 392 * You may want to use {@link #fill(byte[][], byte)} to modify an existing 2D array instead. 393 * @param contents the value to fill the array with 394 * @param width the desired width 395 * @param height the desired height 396 * @return a freshly allocated 2D array of the requested dimensions, filled entirely with contents 397 */ 398 public static byte[][] fill(byte contents, int width, int height) { 399 byte[][] next = new byte[width][height]; 400 for (int x = 0; x < width; x++) { 401 Arrays.fill(next[x], contents); 402 } 403 return next; 404 } 405 406 /** 407 * Creates a 2D array of the given width and height, filled with entirely with the value contents. 408 * You may want to use {@link #fill(boolean[][], boolean)} to modify an existing 2D array instead. 409 * @param contents the value to fill the array with 410 * @param width the desired width 411 * @param height the desired height 412 * @return a freshly allocated 2D array of the requested dimensions, filled entirely with contents 413 */ 414 public static boolean[][] fill(boolean contents, int width, int height) { 415 boolean[][] next = new boolean[width][height]; 416 if (contents) { 417 for (int x = 0; x < width; x++) { 418 Arrays.fill(next[x], true); 419 } 420 } 421 return next; 422 } 423 /** 424 * Fills {@code array2d} with {@code value}. 425 * Not to be confused with {@link #fill(boolean, int, int)}, which makes a new 2D array. 426 * @param array2d a 2D array that will be modified in-place 427 * @param value the value to fill all of array2D with 428 */ 429 public static void fill(boolean[][] array2d, boolean value) { 430 final int width = array2d.length; 431 for (int i = 0; i < width; i++) { 432 Arrays.fill(array2d[i], value); 433 } 434// final int width = array2d.length; 435// final int height = width == 0 ? 0 : array2d[0].length; 436// if(width > 0) { 437// for (int i = 0; i < height; i++) { 438// array2d[0][i] = value; 439// } 440// } 441// for (int x = 1; x < width; x++) { 442// System.arraycopy(array2d[0], 0, array2d[x], 0, height); 443// } 444 } 445 446 /** 447 * Fills {@code array2d} with {@code value}. 448 * Not to be confused with {@link #fill(char, int, int)}, which makes a new 2D array. 449 * @param array2d a 2D array that will be modified in-place 450 * @param value the value to fill all of array2D with 451 */ 452 public static void fill(char[][] array2d, char value) { 453 final int width = array2d.length; 454 for (int i = 0; i < width; i++) { 455 Arrays.fill(array2d[i], value); 456 } 457// final int width = array2d.length; 458// final int height = width == 0 ? 0 : array2d[0].length; 459// if(width > 0) { 460// for (int i = 0; i < height; i++) { 461// array2d[0][i] = value; 462// } 463// } 464// for (int x = 1; x < width; x++) { 465// System.arraycopy(array2d[0], 0, array2d[x], 0, height); 466// } 467 } 468 469 /** 470 * Fills {@code array2d} with {@code value}. 471 * Not to be confused with {@link #fill(float, int, int)}, which makes a new 2D array. 472 * @param array2d a 2D array that will be modified in-place 473 * @param value the value to fill all of array2D with 474 */ 475 public static void fill(float[][] array2d, float value) { 476 final int width = array2d.length; 477 for (int i = 0; i < width; i++) { 478 Arrays.fill(array2d[i], value); 479 } 480// final int width = array2d.length; 481// final int height = width == 0 ? 0 : array2d[0].length; 482// if(width > 0) { 483// for (int i = 0; i < height; i++) { 484// array2d[0][i] = value; 485// } 486// } 487// for (int x = 1; x < width; x++) { 488// System.arraycopy(array2d[0], 0, array2d[x], 0, height); 489// } 490 } 491 492 493 /** 494 * Fills {@code array2d} with {@code value}. 495 * Not to be confused with {@link #fill(double, int, int)}, which makes a new 2D array. 496 * @param array2d a 2D array that will be modified in-place 497 * @param value the value to fill all of array2D with 498 */ 499 public static void fill(double[][] array2d, double value) { 500 final int width = array2d.length; 501 for (int i = 0; i < width; i++) { 502 Arrays.fill(array2d[i], value); 503 } 504// final int height = width == 0 ? 0 : array2d[0].length; 505// if(width > 0) { 506// for (int i = 0; i < height; i++) { 507// array2d[0][i] = value; 508// } 509// } 510// for (int x = 1; x < width; x++) { 511// System.arraycopy(array2d[0], 0, array2d[x], 0, height); 512// } 513 } 514 515 /** 516 * Fills {@code array3d} with {@code value}. 517 * Not to be confused with {@link #fill(double[][], double)}, which fills a 2D array instead of a 3D one, or with 518 * {@link #fill(double, int, int)}, which makes a new 2D array. 519 * @param array3d a 3D array that will be modified in-place 520 * @param value the value to fill all of array3d with 521 */ 522 public static void fill(double[][][] array3d, double value) { 523 final int depth = array3d.length; 524 final int width = depth == 0 ? 0 : array3d[0].length; 525 final int height = width == 0 ? 0 : array3d[0][0].length; 526 if(depth > 0 && width > 0) { 527 for (int i = 0; i < width; i++) { 528 for (int j = 0; j < height; j++) { 529 Arrays.fill(array3d[i][j], value); 530 } 531 } 532 } 533 } 534 535 /** 536 * Fills {@code array2d} with {@code value}. 537 * Not to be confused with {@link #fill(int, int, int)}, which makes a new 2D array. 538 * @param array2d a 2D array that will be modified in-place 539 * @param value the value to fill all of array2D with 540 */ 541 public static void fill(int[][] array2d, int value) { 542 final int width = array2d.length; 543 for (int i = 0; i < width; i++) { 544 Arrays.fill(array2d[i], value); 545 } 546 547// final int width = array2d.length; 548// final int height = width == 0 ? 0 : array2d[0].length; 549// if(width > 0) { 550// for (int i = 0; i < height; i++) { 551// array2d[0][i] = value; 552// } 553// } 554// for (int x = 1; x < width; x++) { 555// System.arraycopy(array2d[0], 0, array2d[x], 0, height); 556// } 557 } 558 559 /** 560 * Fills {@code array2d} with {@code value}. 561 * Not to be confused with {@link #fill(byte, int, int)}, which makes a new 2D array. 562 * @param array2d a 2D array that will be modified in-place 563 * @param value the value to fill all of array2D with 564 */ 565 public static void fill(byte[][] array2d, byte value) { 566 final int width = array2d.length; 567 for (int i = 0; i < width; i++) { 568 Arrays.fill(array2d[i], value); 569 } 570// final int width = array2d.length; 571// final int height = width == 0 ? 0 : array2d[0].length; 572// if(width > 0) { 573// for (int i = 0; i < height; i++) { 574// array2d[0][i] = value; 575// } 576// } 577// for (int x = 1; x < width; x++) { 578// System.arraycopy(array2d[0], 0, array2d[x], 0, height); 579// } 580 } 581 582 583 /** 584 * Fills a sub-section of {@code array2d} with {@code value}, with the section defined by start/end x/y. 585 * Not to be confused with {@link #fill(boolean, int, int)}, which makes a new 2D array. 586 * @param array2d a 2D array that will be modified in-place 587 * @param value the value to fill all of array2D with 588 * @param startX the first x position to fill (inclusive) 589 * @param startY the first y position to fill (inclusive) 590 * @param endX the last x position to fill (inclusive) 591 * @param endY the last y position to fill (inclusive) 592 */ 593 public static void fill(boolean[][] array2d, boolean value, int startX, int startY, int endX, int endY) { 594 final int width = array2d.length; 595 final int height = width == 0 ? 0 : array2d[0].length; 596 for (int x = startX; x <= endX && x < width; x++) { 597 for (int y = startY; y <= endY && y < height; y++) { 598 array2d[x][y] = value; 599 } 600 } 601 } 602 603 /** 604 * Fills a sub-section of {@code array2d} with {@code value}, with the section defined by start/end x/y. 605 * Not to be confused with {@link #fill(char, int, int)}, which makes a new 2D array. 606 * @param array2d a 2D array that will be modified in-place 607 * @param value the value to fill all of array2D with 608 * @param startX the first x position to fill (inclusive) 609 * @param startY the first y position to fill (inclusive) 610 * @param endX the last x position to fill (inclusive) 611 * @param endY the last y position to fill (inclusive) 612 */ 613 public static void fill(char[][] array2d, char value, int startX, int startY, int endX, int endY) { 614 final int width = array2d.length; 615 final int height = width == 0 ? 0 : array2d[0].length; 616 for (int x = startX; x <= endX && x < width; x++) { 617 for (int y = startY; y <= endY && y < height; y++) { 618 array2d[x][y] = value; 619 } 620 } 621 } 622 623 /** 624 * Fills a sub-section of {@code array2d} with {@code value}, with the section defined by start/end x/y. 625 * Not to be confused with {@link #fill(float, int, int)}, which makes a new 2D array. 626 * @param array2d a 2D array that will be modified in-place 627 * @param value the value to fill all of array2D with 628 * @param startX the first x position to fill (inclusive) 629 * @param startY the first y position to fill (inclusive) 630 * @param endX the last x position to fill (inclusive) 631 * @param endY the last y position to fill (inclusive) 632 */ 633 public static void fill(float[][] array2d, float value, int startX, int startY, int endX, int endY) { 634 final int width = array2d.length; 635 final int height = width == 0 ? 0 : array2d[0].length; 636 for (int x = startX; x <= endX && x < width; x++) { 637 for (int y = startY; y <= endY && y < height; y++) { 638 array2d[x][y] = value; 639 } 640 } 641 } 642 643 /** 644 * Fills a sub-section of {@code array2d} with {@code value}, with the section defined by start/end x/y. 645 * Not to be confused with {@link #fill(double, int, int)}, which makes a new 2D array. 646 * @param array2d a 2D array that will be modified in-place 647 * @param value the value to fill all of array2D with 648 * @param startX the first x position to fill (inclusive) 649 * @param startY the first y position to fill (inclusive) 650 * @param endX the last x position to fill (inclusive) 651 * @param endY the last y position to fill (inclusive) 652 */ 653 public static void fill(double[][] array2d, double value, int startX, int startY, int endX, int endY) { 654 final int width = array2d.length; 655 final int height = width == 0 ? 0 : array2d[0].length; 656 for (int x = startX; x <= endX && x < width; x++) { 657 for (int y = startY; y <= endY && y < height; y++) { 658 array2d[x][y] = value; 659 } 660 } 661 } 662 663 /** 664 * Fills a sub-section of {@code array2d} with {@code value}, with the section defined by start/end x/y. 665 * Not to be confused with {@link #fill(int, int, int)}, which makes a new 2D array. 666 * @param array2d a 2D array that will be modified in-place 667 * @param value the value to fill all of array2D with 668 * @param startX the first x position to fill (inclusive) 669 * @param startY the first y position to fill (inclusive) 670 * @param endX the last x position to fill (inclusive) 671 * @param endY the last y position to fill (inclusive) 672 */ 673 public static void fill(int[][] array2d, int value, int startX, int startY, int endX, int endY) { 674 final int width = array2d.length; 675 final int height = width == 0 ? 0 : array2d[0].length; 676 for (int x = startX; x <= endX && x < width; x++) { 677 for (int y = startY; y <= endY && y < height; y++) { 678 array2d[x][y] = value; 679 } 680 } 681 } 682 683 /** 684 * Randomly fills all of {@code array2d} with random values generated from {@code seed}; can fill an element with 685 * any long, positive or negative. 686 * Fairly efficient; uses a fast random number generation algorithm that can avoid some unnecessary work in this 687 * context, and improves quality by seeding each column differently. Generates {@code (height + 1) * width} random 688 * values to fill the {@code height * width} elements in array2d. 689 * @param array2d a 2D array that will be modified in-place 690 * @param seed the seed for the random values, as a long 691 */ 692 public static void randomFill(long[][] array2d, final long seed) 693 { 694 final int width = array2d.length; 695 final int height = width == 0 ? 0 : array2d[0].length; 696 long r0 = seed, z; 697 for (int x = 0; x < width; x++) { 698 for (int y = 0; y < height; y++) { 699 z = r0 ^ (((r0 >>> 23) ^ (r0 += 0xA99635D5B8597AE5L)) * 0xAD5DE9A61A9C3D95L); 700 array2d[x][y] = z ^ (z >>> 29); 701 } 702 } 703 } 704 /** 705 * Randomly fills all of {@code array2d} with random values generated from {@code seed}; can fill an element with 706 * any int, positive or negative. 707 * Fairly efficient; uses a fast random number generation algorithm that can avoid some unnecessary work in this 708 * context, and improves quality by seeding each column differently. Generates {@code (height + 1) * width} random 709 * values to fill the {@code height * width} elements in array2d. 710 * @param array2d a 2D array that will be modified in-place 711 * @param seed the seed for the random values, as a long 712 */ 713 public static void randomFill(int[][] array2d, final long seed) 714 { 715 final int width = array2d.length; 716 final int height = width == 0 ? 0 : array2d[0].length; 717 long r0 = seed, z; 718 for (int x = 0; x < width; x++) { 719 for (int y = 0; y < height; y++) { 720 z = r0 ^ (((r0 >>> 23) ^ (r0 += 0xA99635D5B8597AE5L)) * 0xAD5DE9A61A9C3D95L); 721 array2d[x][y] = (int)(z ^ (z >>> 29)); 722 } 723 } 724 } 725 /** 726 * Randomly fills all of {@code array2d} with random values generated from {@code seed}, limiting results to between 727 * 0 and {@code bound}, exclusive. 728 * Fairly efficient; uses a fast random number generation algorithm that can avoid some unnecessary work in this 729 * context, and improves quality by seeding each column differently. Generates {@code (height + 1) * width} random 730 * values to fill the {@code height * width} elements in array2d. 731 * @param array2d a 2D array that will be modified in-place 732 * @param bound the upper exclusive limit for the ints this can produce 733 * @param seed the seed for the random values, as a long 734 */ 735 public static void randomFill(int[][] array2d, final int bound, final long seed) 736 { 737 final int width = array2d.length; 738 final int height = width == 0 ? 0 : array2d[0].length; 739 long r0 = seed, z; 740 for (int x = 0; x < width; x++) { 741 for (int y = 0; y < height; y++) { 742 z = r0 ^ (((r0 >>> 23) ^ (r0 += 0xA99635D5B8597AE5L)) * 0xAD5DE9A61A9C3D95L); 743 array2d[x][y] = (int) ((bound * ((z ^ (z >>> 29)) & 0xFFFFFFFFL)) >> 32); 744 } 745 } 746 } 747 /** 748 * Randomly fills all of {@code array2d} with random values generated from {@code seed}, choosing chars to place in 749 * the given 2D array by selecting them at random from the given 1D char array {@code values}. 750 * Fairly efficient; uses a fast random number generation algorithm that can avoid some unnecessary work in this 751 * context, and improves quality by seeding each column differently. Generates {@code (height + 1) * width} random 752 * values to fill the {@code height * width} elements in array2d. 753 * @param array2d a 2D array that will be modified in-place 754 * @param values a 1D char array containing the possible char values that can be chosen to fill array2d 755 * @param seed the seed for the random values, as a long 756 */ 757 public static void randomFill(char[][] array2d, final char[] values, final long seed) 758 { 759 final int width = array2d.length; 760 final int height = width == 0 ? 0 : array2d[0].length; 761 final int bound = values.length; 762 long r0 = seed + bound, z; 763 for (int x = 0; x < width; x++) { 764 for (int y = 0; y < height; y++) { 765 z = r0 ^ (((r0 >>> 23) ^ (r0 += 0xA99635D5B8597AE5L)) * 0xAD5DE9A61A9C3D95L); 766 array2d[x][y] = values[(int) ((bound * ((z ^ (z >>> 29)) & 0xFFFFFFFFL)) >>> 32)]; 767 } 768 } 769 } 770 771 /** 772 * Randomly fills all of {@code array2d} with random values generated from {@code seed}, choosing chars to place in 773 * the given 2D array by selecting them at random from the given 1D char array {@code values}. 774 * Fairly efficient; uses a fast random number generation algorithm that can avoid some unnecessary work in this 775 * context, and improves quality by seeding each column differently. Generates {@code (height + 1) * width} random 776 * values to fill the {@code height * width} elements in array2d. 777 * @param array2d a 2D array that will be modified in-place 778 * @param values a 1D char array containing the possible char values that can be chosen to fill array2d 779 * @param seed the seed for the random values, as a long 780 */ 781 public static void randomFill(char[][] array2d, final CharSequence values, final long seed) 782 { 783 final int width = array2d.length; 784 final int height = width == 0 ? 0 : array2d[0].length; 785 final int bound = values.length(); 786 long r0 = seed + bound, z; 787 for (int x = 0; x < width; x++) { 788 for (int y = 0; y < height; y++) { 789 z = r0 ^ (((r0 >>> 23) ^ (r0 += 0xA99635D5B8597AE5L)) * 0xAD5DE9A61A9C3D95L); 790 array2d[x][y] = values.charAt((int) ((bound * ((z ^ (z >>> 29)) & 0xFFFFFFFFL)) >>> 32)); 791 } 792 } 793 } 794 795 /** 796 * Randomly fills all of {@code array2d} with random values generated from {@code seed}; can fill an element with 797 * any float between 0.0 inclusive and 1.0 exclusive. 798 * Fairly efficient; uses a fast random number generation algorithm that can avoid some unnecessary work in this 799 * context, and improves quality by seeding each column differently. Generates {@code (height + 1) * width} random 800 * values to fill the {@code height * width} elements in array2d. 801 * @param array2d a 2D array that will be modified in-place 802 * @param seed the seed for the random values, as a long 803 */ 804 public static void randomFill(float[][] array2d, final long seed) 805 { 806 final int width = array2d.length; 807 final int height = width == 0 ? 0 : array2d[0].length; 808 long r0 = seed, z; 809 for (int x = 0; x < width; x++) { 810 for (int y = 0; y < height; y++) { 811 z = r0 ^ (((r0 >>> 23) ^ (r0 += 0xA99635D5B8597AE5L)) * 0xAD5DE9A61A9C3D95L); 812 array2d[x][y] = ((z ^ (z >>> 29)) & 0xFFFFFFL) * 0x1p-24f; 813 } 814 } 815 } 816 /** 817 * Randomly fills all of {@code array2d} with random values generated from {@code seed}, limiting results to between 818 * 0 and {@code bound}, exclusive. 819 * Fairly efficient; uses a fast random number generation algorithm that can avoid some unnecessary work in this 820 * context, and improves quality by seeding each column differently. Generates {@code (height + 1) * width} random 821 * values to fill the {@code height * width} elements in array2d. 822 * @param array2d a 2D array that will be modified in-place 823 * @param bound the upper exclusive limit for the floats this can produce 824 * @param seed the seed for the random values, as a long 825 */ 826 public static void randomFill(float[][] array2d, final float bound, final long seed) { 827 final int width = array2d.length; 828 final int height = width == 0 ? 0 : array2d[0].length; 829 long r0 = seed, z; 830 final float mul = 0x1p-24f * bound; 831 for (int x = 0; x < width; x++) { 832 for (int y = 0; y < height; y++) { 833 z = r0 ^ (((r0 >>> 23) ^ (r0 += 0xA99635D5B8597AE5L)) * 0xAD5DE9A61A9C3D95L); 834 array2d[x][y] = ((z ^ (z >>> 29)) & 0xFFFFFFL) * mul; 835 } 836 } 837 } 838 839 /** 840 * Randomly fills all of {@code array2d} with random values generated from {@code seed}; can fill an element with 841 * any double between 0.0 inclusive and 1.0 exclusive. 842 * Fairly efficient; uses a fast random number generation algorithm that can avoid some unnecessary work in this 843 * context, and improves quality by seeding each column differently. Generates {@code (height + 1) * width} random 844 * values to fill the {@code height * width} elements in array2d. 845 * @param array2d a 2D array that will be modified in-place 846 * @param seed the seed for the random values, as a long 847 */ 848 public static void randomFill(double[][] array2d, final long seed) 849 { 850 final int width = array2d.length; 851 final int height = width == 0 ? 0 : array2d[0].length; 852 long r0 = seed, z; 853 for (int x = 0; x < width; x++) { 854 for (int y = 0; y < height; y++) { 855 z = r0 ^ (((r0 >>> 23) ^ (r0 += 0xA99635D5B8597AE5L)) * 0xAD5DE9A61A9C3D95L); 856 array2d[x][y] = ((z ^ (z >>> 29)) & 0x1FFFFFFFFFFFFFL) * 0x1p-53; 857 } 858 } 859 } 860 /** 861 * Randomly fills all of {@code array2d} with random values generated from {@code seed}, limiting results to between 862 * 0 and {@code bound}, exclusive. 863 * Fairly efficient; uses a fast random number generation algorithm that can avoid some unnecessary work in this 864 * context, and improves quality by seeding each column differently. Generates {@code (height + 1) * width} random 865 * values to fill the {@code height * width} elements in array2d. 866 * @param array2d a 2D array that will be modified in-place 867 * @param bound the upper exclusive limit for the doubles this can produce 868 * @param seed the seed for the random values, as a long 869 */ 870 public static void randomFill(double[][] array2d, final double bound, final long seed) 871 { 872 final int width = array2d.length; 873 final int height = width == 0 ? 0 : array2d[0].length; 874 long r0 = seed, z; 875 final double mul = 0x1p-53 * bound; 876 for (int x = 0; x < width; x++) { 877 for (int y = 0; y < height; y++) { 878 z = r0 ^ (((r0 >>> 23) ^ (r0 += 0xA99635D5B8597AE5L)) * 0xAD5DE9A61A9C3D95L); 879 array2d[x][y] = ((z ^ (z >>> 29)) & 0x1FFFFFFFFFFFFFL) * mul; 880 } 881 } 882 883 } 884 885 /** 886 * Rearranges an ArrayList to use the given ordering, returning a copy; random orderings can be produced with 887 * {@link squidpony.squidmath.RNG#randomOrdering(int)} or 888 * {@link squidpony.squidmath.RNG#randomOrdering(int, int[])}. These orderings will never repeat an earlier element, 889 * and the returned ArrayList may be shorter than the original if {@code ordering} isn't as long as {@code list}. 890 * Using a random ordering is like shuffling, but allows you to repeat the shuffle exactly on other collections of 891 * the same size. A reordering can also be inverted with {@link #invertOrdering(int[])} or 892 * {@link #invertOrdering(int[], int[])}, getting the change that will undo another ordering. 893 * 894 * @param list an ArrayList that you want a reordered version of; will not be modified. 895 * @param ordering an ordering, typically produced by one of RNG's randomOrdering methods. 896 * @param <T> any generic type 897 * @return a modified copy of {@code list} with its ordering changed to match {@code ordering}. 898 */ 899 public static <T> ArrayList<T> reorder(ArrayList<T> list, int... ordering) { 900 int ol; 901 if (list == null || ordering == null || (ol = Math.min(list.size(), ordering.length)) == 0) 902 return list; 903 ArrayList<T> alt = new ArrayList<T>(ol); 904 for (int i = 0; i < ol; i++) { 905 alt.add(list.get((ordering[i] % ol + ol) % ol)); 906 } 907 return alt; 908 } 909 910 /** 911 * Given an ordering such as one produced by {@link squidpony.squidmath.RNG#randomOrdering(int, int[])}, this finds 912 * its inverse, able to reverse the reordering and vice versa. 913 * 914 * @param ordering the ordering to find the inverse for 915 * @return the inverse of ordering 916 */ 917 public static int[] invertOrdering(int[] ordering) { 918 int ol; 919 if (ordering == null || (ol = ordering.length) == 0) return ordering; 920 int[] next = new int[ol]; 921 for (int i = 0; i < ol; i++) { 922 if (ordering[i] < 0 || ordering[i] >= ol) return next; 923 next[ordering[i]] = i; 924 } 925 return next; 926 } 927 928 /** 929 * Given an ordering such as one produced by {@link squidpony.squidmath.RNG#randomOrdering(int, int[])}, this finds 930 * its inverse, able to reverse the reordering and vice versa. This overload doesn't allocate a new int 931 * array, and instead relies on having an int array of the same size as ordering passed to it as an 932 * additional argument. 933 * 934 * @param ordering the ordering to find the inverse for 935 * @param dest the int array to put the inverse reordering into; should have the same length as ordering 936 * @return the inverse of ordering; will have the same value as dest 937 */ 938 public static int[] invertOrdering(int[] ordering, int[] dest) { 939 int ol; 940 if (ordering == null || dest == null || (ol = Math.min(ordering.length, dest.length)) == 0) 941 return ordering; 942 for (int i = 0; i < ol; i++) { 943 if (ordering[i] < 0 || ordering[i] >= ol) return dest; 944 dest[ordering[i]] = i; 945 } 946 return dest; 947 } 948 949 /** 950 * Reverses the array given as a parameter, in-place, and returns the modified original. 951 * @param data an array that will be reversed in-place 952 * @return the array passed in, after reversal 953 */ 954 public static boolean[] reverse(boolean[] data) 955 { 956 int sz; 957 if(data == null || (sz = data.length) <= 0) return data; 958 boolean t; 959 for (int i = 0, j = sz - 1; i < j; i++, j--) { 960 t = data[j]; 961 data[j] = data[i]; 962 data[i] = t; 963 } 964 return data; 965 } 966 967 /** 968 * Reverses the array given as a parameter, in-place, and returns the modified original. 969 * @param data an array that will be reversed in-place 970 * @return the array passed in, after reversal 971 */ 972 public static char[] reverse(char[] data) 973 { 974 int sz; 975 if(data == null || (sz = data.length) <= 0) return data; 976 char t; 977 for (int i = 0, j = sz - 1; i < j; i++, j--) { 978 t = data[j]; 979 data[j] = data[i]; 980 data[i] = t; 981 } 982 return data; 983 } 984 985 /** 986 * Reverses the array given as a parameter, in-place, and returns the modified original. 987 * @param data an array that will be reversed in-place 988 * @return the array passed in, after reversal 989 */ 990 public static float[] reverse(float[] data) 991 { 992 int sz; 993 if(data == null || (sz = data.length) <= 0) return data; 994 float t; 995 for (int i = 0, j = sz - 1; i < j; i++, j--) { 996 t = data[j]; 997 data[j] = data[i]; 998 data[i] = t; 999 } 1000 return data; 1001 } 1002 1003 /** 1004 * Reverses the array given as a parameter, in-place, and returns the modified original. 1005 * @param data an array that will be reversed in-place 1006 * @return the array passed in, after reversal 1007 */ 1008 public static double[] reverse(double[] data) 1009 { 1010 int sz; 1011 if(data == null || (sz = data.length) <= 0) return data; 1012 double t; 1013 for (int i = 0, j = sz - 1; i < j; i++, j--) { 1014 t = data[j]; 1015 data[j] = data[i]; 1016 data[i] = t; 1017 } 1018 return data; 1019 } 1020 1021 /** 1022 * Reverses the array given as a parameter, in-place, and returns the modified original. 1023 * @param data an array that will be reversed in-place 1024 * @return the array passed in, after reversal 1025 */ 1026 public static int[] reverse(int[] data) 1027 { 1028 int sz; 1029 if(data == null || (sz = data.length) <= 0) return data; 1030 int t; 1031 for (int i = 0, j = sz - 1; i < j; i++, j--) { 1032 t = data[j]; 1033 data[j] = data[i]; 1034 data[i] = t; 1035 } 1036 return data; 1037 } 1038 1039 /** 1040 * Reverses the array given as a parameter, in-place, and returns the modified original. 1041 * @param data an array that will be reversed in-place 1042 * @return the array passed in, after reversal 1043 */ 1044 public static byte[] reverse(byte[] data) 1045 { 1046 int sz; 1047 if(data == null || (sz = data.length) <= 0) return data; 1048 byte t; 1049 for (int i = 0, j = sz - 1; i < j; i++, j--) { 1050 t = data[j]; 1051 data[j] = data[i]; 1052 data[i] = t; 1053 } 1054 return data; 1055 } 1056 /** 1057 * Reverses the array given as a parameter, in-place, and returns the modified original. 1058 * @param data an array that will be reversed in-place 1059 * @return the array passed in, after reversal 1060 */ 1061 public static<T> T[] reverse(T[] data) 1062 { 1063 int sz; 1064 if(data == null || (sz = data.length) <= 0) return data; 1065 T t; 1066 for (int i = 0, j = sz - 1; i < j; i++, j--) { 1067 t = data[j]; 1068 data[j] = data[i]; 1069 data[i] = t; 1070 } 1071 return data; 1072 } 1073}