/**
 * @(#)Minoid.java
 * @author JLMJ
 * @date 2001-10-03
 */
package minoids1;
    
public final class Minoid
{
    private int x;
    private int y;
    private int z;
    
    private static int dx, dy, dz; // for internal use...
    private boolean isVisible;
    
    public void setVisible(boolean state) {
        isVisible = state;
    }
    
    public boolean isVisible() {
        return isVisible;
    }
    
    public boolean isAnyConnected(Minoid other) {
        return (isHardConnected(other) || isSoftConnected(other));
    }
    
    public boolean isHardConnected(Minoid other) {
        dx = Math.abs(x - other.x);
        dy = Math.abs(y - other.y);
        dz = Math.abs(z - other.z);
        if (dx == 0 && dy == 1 && dz == 1)
            return true;
        if (dx == 1 && dy == 0 && dz == 1)
            return true;
        if (dx == 1 && dy == 1 && dz == 0)
            return true;
        return false;
    }
    
    public boolean isSoftConnected(Minoid other) {
        dx = Math.abs(x - other.x);
        dy = Math.abs(y - other.y);
        dz = Math.abs(z - other.z);
        if ((x & 1) == 0 && dx == 0) {
            if ((dy == 2 && dz == 0) || (dy == 0 && dz == 2))
                return true;
        } else if ((y & 1) == 0 && dy == 0) {
            if ((dx == 2 && dz == 0) || (dx == 0 && dz == 2))
                return true;
        } else if ((z & 1) == 0 && dz == 0) {
            if ((dx == 2 && dy == 0) || (dx == 0 && dy == 2))
                return true;
        }
        return false;
    }
    
    public String toString() {
        return "(" + x + ", " + y + ", " + z + ")";
    }
    
    public int getX() { return x; }
    public int getY() { return y; }
    public int getZ() { return z; }
    
    public static Minoid createMinoid(int x, int y, int z) {
        boolean xIsOdd = (x & 1) != 0;
        boolean yIsOdd = (y & 1) != 0;
        boolean zIsOdd = (z & 1) != 0;
        
        boolean isMinoid =
            (!xIsOdd && yIsOdd && zIsOdd) ||
            (xIsOdd && !yIsOdd && zIsOdd) ||
            (xIsOdd && yIsOdd && !zIsOdd);
            
        if (isMinoid) {
            Minoid m = new Minoid();
            m.x = x;
            m.y = y;
            m.z = z;
            return m;
        }
        return null;
    }

    /**
     *  Example of minoids generated for order n=3:
     *      x y z        x y z        x y z
     *  ---------    ---------    ---------
     *   1. 0 1 1     4. 0 1 3    13. 0 1 5
     *   2. 1 0 1     5. 0 3 1    14. 0 3 3
     *   3. 1 1 0     6. 1 0 3    15. 0 5 1
     *                7. 1 1 2    16. 1 0 5
     *                8. 1 2 1    17. 1 1 4
     *                9. 1 3 0    18. 1 2 3
     *               10. 2 1 1    19. 1 3 2
     *               11. 3 0 1    20. 1 4 1
     *               12. 3 1 0    21. 1 5 0
     *                            22. 2 1 3
     *                            23. 2 3 1
     *                            24. 3 0 3
     *                            25. 3 1 2
     *                            26. 3 2 1
     *                            27. 3 3 0
     *                            28. 4 1 1
     *                            29. 5 0 1
     *                            30. 5 1 0
     */
    public static Minoid[] getPyramidMinoids(int n) {
        if (n < 1)
            return null;
        // We already know the number of minoids for order n
        // is three times the corresponding tetrahedral number.
        // (n)(n+1)(n+2)/6
        Minoid[] minoids = new Minoid[3*n*(n+1)*(n+2)/6];
        Minoid minoid;
        int m = 0;
        for (int sum=2; sum <= 2*n; sum += 2) {
            for (int x=0; x < sum; x++) {
                for (int y=0; y < (x + sum); y++) {
                    for (int z=0; z < (x + y + sum); z++) {
                        if (x + y + z == sum) {
                            minoid = createMinoid(x, y, z);
                            if (minoid != null) {
                                minoids[m++] = minoid;
                            }
                        }
                    }
                }
            }
        }
        return minoids;
    }

    public static Minoid[] getBoxMinoids(int x, int y, int z) {
        if ((x + y + z < 2) || (x < 0) || (y < 0) || (z < 0))
            return null;
        // We already know the number of minoids for box(x,y,z):
        // max_order = xy(z+1) + x(y+1)z + (x+1)yz
        Minoid[] minoids = new Minoid[x*y*(z+1) + x*(y+1)*z + (x+1)*y*z];
        Minoid minoid;
        int m = 0;
        for (int i=0; i < (2*x + 1); i++) {
            for (int j=0; j < (2*y + 1); j++) {
                for (int k=0; k < (2*z + 1); k++) {
                    minoid = createMinoid(i, j, k);
                    if (minoid != null) {
                        minoids[m++] = minoid;
                    }
                }
            }
        }
        return minoids;
    }
    
    // Only for test
    public static void main(String[] args) {
        Minoid[] minoids = Minoid.getPyramidMinoids(11);
        for (int i=0; i < minoids.length; i++)
            System.out.println((i+1) + ". " + minoids[i]);
    }
}

