/**
 * 
 */
package mathsquared.resultswizard2;

import java.lang.reflect.Array;
import java.util.Arrays;

/**
 * @author MathSquared
 * 
 */
public class ArrayUtils {
    /**
     * Creates a deep copy of a multi-dimensional array, copying all sub-arrays of the array (but not the elements themselves).
     * 
     * @param toCopy the multi-dimensional array to copy
     * @return a copy of the array
     */
    // HASHTAG UNCHECKED CASTS
    @SuppressWarnings("unchecked")
    public static <T> T[][] deepCopyOf (T[][] toCopy) {
        // Instantiate a generic array
        Class<T[]> type = (Class<T[]>) toCopy.getClass().getComponentType();
        T[][] copied = (T[][]) Array.newInstance(type, toCopy.length);

        // If a two-dimensional array, use Arrays.copyOf; otherwise, recurse
        if (!(toCopy instanceof Object[][][])) { // not 3-D; by parameter, must be 2-D
            for (int i = 0; i < toCopy.length; i++) {
                copied[i] = Arrays.copyOf(toCopy[i], toCopy[i].length);
            }
        } else { // 3-D or above
            for (int i = 0; i < toCopy.length; i++) {
                copied[i] = (T[]) deepCopyOf((Object[][]) toCopy[i]);
            }
        }

        return copied;
    }

    /**
     * Checks that all ties are represented validly.
     * 
     * <p>
     * For every sub-array of a result array (which represents a tie), if the sub-array contains more than one element, places should be skipped in accordance. This corresponds to normal practice; for example, if two people tie for first place, the next place awarded is third place (and the second-place array should be null or empty).
     * </p>
     * 
     * @param results the results array whose integrity to check
     * @return true if the array correctly skips places for ties; false otherwise
     */
    public static boolean checkTies (String[][] results) {
        /*
         * Implementation:
         * 
         * The algorithm keeps track of the amount of results that have been seen so far, where a "result" is one String.
         * 
         * For each sub-array of the input array, the algorithm adds subArr.length - 1 to an internal tracking variable.
         * 
         * If this variable is non-zero, it means that there was a tie previously, and the next few places should be skipped with null.
         * 
         * If this variable is zero, it means that there have been no ties--or all were accounted for--so the next array should have elements.
         */

        int num = 0; // tracking variable mentioned above
        for (String[] x : results) {
            // num never decreases by more than 1 each turn, and can never decrease if it is 0, so check for num < 0 is unnecessary
            assert (num >= 0);
            if (num == 0 && (results == null || results.length == 0)) {
                return false;
            }
            if (num > 0 && results != null && results.length != 0) {
                return false;
            }
            num += (x == null) ? -1 : x.length - 1;
        }

        // no problems; num does not need to be 0 in case of ties for last place
        return true;
    }
}

@@ -3160,11 +3160,1356 @@
 e;%0A    %7D
+%0A%0A    /**%0A     * Checks that the structure of two arrays is the same. That is:%0A     * %0A     * %3Cul%3E%0A     * %3Cli%3E%3Ccode%3Ea.length == b.length%3C/code%3E%3C/li%3E%0A     * %3Cli%3EFor any integer %3Ccode%3Ei%3C/code%3E, %3Ccode%3Ea%5Bi%5D%3C/code%3E is an array iff %3Ccode%3Eb%5Bi%5D%3C/code%3E is an array%3C/li%3E%0A     * %3Cli%3EFor any integer %3Ccode%3Ei%3C/code%3E, if %3Ccode%3Ea%5Bi%5D%3C/code%3E and %3Ccode%3Eb%5Bi%5D%3C/code%3E are arrays, the first two statements are recursively valid for them as well%3C/li%3E%0A     * %3C/ul%3E%0A     * %0A     * @param a the first array to check%0A     * @param b the second array to check%0A     * @return true if the arrays have the same structure as defined above, false otherwise%0A     */%0A    public static boolean checkStructureSame (Object%5B%5D a, Object%5B%5D b) %7B%0A        if (a.length != b.length)%0A            return false;%0A        for (int i = 0; i %3C a.length; i++) %7B%0A            if (a%5Bi%5D instanceof Object%5B%5D && b%5Bi%5D instanceof Object%5B%5D) %7B%0A                if (!checkStructureSame((Object%5B%5D) a%5Bi%5D, (Object%5B%5D) b%5Bi%5D)) %7B%0A                    return false;%0A                %7D%0A            %7D%0A%0A            // In theory, since U is the same for both arrays, we wouldn't have one be an array of arrays and the other not be...but let's check%0A            if (a%5Bi%5D instanceof Object%5B%5D %5E b%5Bi%5D instanceof Object%5B%5D) %7B%0A                return false;%0A            %7D%0A        %7D%0A%0A        // no problems%0A        return true;%0A    %7D
 %0A%7D%0A

Add and document checkStructureSame