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}