简体   繁体   中英

The easiest way to achieve a responsive orientation enum? java

I will quickly display what I want to achieve in the "clearest" way:

public enum Orientation {
    NORTH, WEST, SOUTH, EAST }

public enum Turn {
    LEFT, RIGHT }

So what I want those two enums to do is secure and efficiently look up the changed orientation according to the move:

Orientation orient = Orientation.NORTH;
// orient points to NORTH now
orient = orient.turn(Turn.LEFT);
// orient points to WEST now

The first way I tried to achieve this was through creating a map:

 EnumMap<Orientation, EnumMap<Turn, Orientation>>

And map all the directions statically but that is a huge chunk of map.get.put.get.... and is probably a bit too overdosed, altough resulting in this desired effect:

directionMap.get(NORTH).get(LEFT)
// the value would then be WEST

The next way I went was through a Compass class that links all orientations into a circle.. Working like a LinkedCircuitList ...<->NORTH<->EAST<->SOUTH<->WEST<->NORTH<->... So Compass could have a static function that calls any Member of that linked list and step to the left or to the right, resulting in the correct change of direction. But the code did not really work out the way I wanted it.

So my question in the end, does anybody has experience on that kind of code, or has an idea how to achieve the desired result in a nice enumerish way?

I see nothing wrong with the Map solution. If you want something more consise:

public enum Orientation {
    NORTH, EAST, SOUTH, WEST;

    private static Orientation[] vals = values();

    Orientation turnTo(Turn t) {
        return vals[(4 + this.ordinal() + (t == Turn.RIGHT ? 1 : -1)) % 4];
    }
}

This, however, is less clean and maintainable (it would break if someone changes the order of the enums).

A little cleaner (but less consise) :

public enum Orientation {
    NORTH(0), EAST(1), SOUTH(2), WEST(3);

    private final int p;

    Orientation(int p) {
        this.p = p;
    }

    private static Orientation[] vals = new Orientation[4];
    static {
        for( Orientation o : Orientation.values() )
            vals[o.p] = o;
    }

    Orientation turnTo(Turn t) {
        return vals[(4 + this.p + (t == Turn.RIGHT ? 1 : -1)) % 4];
    }
}

Another way to trick java into accepting this is using methods instead of fields:

enum Orientation {

    NORTH {
        Orientation left(){return WEST;}
        Orientation right(){return EAST;}
    },
    EAST {
        Orientation left(){return NORTH;}
        Orientation right(){return SOUTH;}
    },
    SOUTH {
        Orientation left(){return EAST;}
        Orientation right(){return WEST;}
    },
    WEST {
        Orientation left(){return SOUTH;}
        Orientation right(){return NORTH;}
    };

    abstract Orientation left();
    abstract Orientation right();

    public Orientation turn(Turn where){
        return where == Turn.LEFT ? this.left() : this.right();
    }
}

You can save yourself the turn() and just write stuff like Orientation.North.left() , if you want to. Gives you very concise Syntax.

I think your idea of a circular list is very good:

public enum Turn {
    LEFT(-1), RIGHT(1);

    private final int offset;

    private Turn(int offset) {
        this.offset = offset;
    }

    public int offset() {
        return this.offset;
    }
}

public enum Orientation {
    NORTH, EAST, SOUTH, WEST;

    private static final List<Orientation> orientations = 
        Arrays.asList(NORTH, EAST, SOUTH, WEST); // to not depend on ordinal

    public Orientation turn(Turn to) {
        int size = orientations.size();
        int myIndex = orientations.indexOf(this);
        int remainder = (myIndex + to.offset()) % size;
        int index = remainder < 0 ? size + remainder : remainder;
        return orientations.get(index);
    }
}

This seems quite extensible, ie HARD_LEFT would have a -2 offset and the circular list of orientations should be ordered from left to right.

Does not use ordinals, and easy to understand:

public enum Orientation { NORTH, WEST, EAST, SOUTH;

    static {
        NORTH.left = WEST;
        NORTH.right = EAST;
        WEST.left = SOUTH;
        WEST.right = NORTH;
        EAST.left = NORTH;
        EAST.right = SOUTH;
        SOUTH.left = EAST;
        SOUTH.right = WEST;
    }

    private Orientation left;
    private Orientation right;

    public Orientation turnTo(Turn t) { return t == Turn.LEFT ? left : right; }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM