
/**
 * Represents a cardinal direction.
 * 
 * This enumeration represents a cardinal direction (N, S, E, W, ...) as well as
 * operations on cardinals, such as rotation and inverse cardinals.
 */
public enum Cardinal {
    N  (0),
    NE (1),
    E  (2),
    SE (3),
    S  (4),
    SW (5),
    W  (6),
    NW (7);

    /** Integer representation of the cardinal (starting at 0 for North) */
    private final int value;

    /** Private constructor for the enumeration */
    private Cardinal(int value) {
        this.value = value;
    }

    /**
     * Returns the integer representation of the cardinal direction.
     * @return the integer representing the cardinal direction
     *         (starting at 0 for North)
     */
    public int asInt() {
        return this.value;
    }

    /**
     * Returns the cardinal direction corresponding to the given integer.
     * @param value integer representing a cardinal direction
     * @return a cardinal corresponding to the integer parameter
     * @throws IllegalArgumentException when the integer value is not valid
     *         (not in the range 0-7)
     */
    public static Cardinal fromInt(int value) {
        for (Cardinal cardinal : Cardinal.values()) {
            if (cardinal.value == value) {
                return cardinal;
            }
        }
        throw new IllegalArgumentException("Invalid value: " + value);
    }

    /**
     * Returns the opposite cardinal direction.
     * @return the opposite cardinal direction of this cardinal
     */
    public Cardinal inverse() {
        return fromInt((this.value + 4) % 8);
    }

    /**
     * Rotates the cardinal direction by a given number of steps.
     * @param steps the number of steps to rotate (positive for clockwise,
     *              negative for counterclockwise)
     * @return the new cardinal direction after rotation
     * @throws IllegalArgumentException when the number of steps is not valid
     *         (not in the range -7 to 7)
     */
    public Cardinal rotate(int steps) {
        return fromInt((this.value + steps + 8) % 8);
    }

    /**
     * Rotates the cardinal direction 90 degrees clockwise.
     * @return the new cardinal direction after a 90-degree clockwise rotation
     */
    public Cardinal rotate90CW() {
        return rotate(2);
    }

    /**
     * Rotates the cardinal direction 90 degrees counterclockwise.
     * @return the new cardinal direction after a 90-degree counterclockwise rotation
     */
    public Cardinal rotate90CCW() {
        return rotate(-2);
    }
}
