I'm currently working on a Dungeon game project which is composed of multiples rooms connected to each other.
Depending on the room you're in you can go to rooms next to yours by picking directions (North
, South
, East
, West
).
I've represented the directions with an Enum
class and I'm looking for a way to implements that North
is the opposite of South
, East
for West
(and so on ...) for the sake of creating the layout of all the rooms in the final form of the game.
Here is my Enum
class :
public enum Direction {
NORTH,
EAST,
SOUTH,
WEST;
public Direction getOppositeDirection() {
return Direction.values()[(this.ordinal()+2)%4];
}
}
The problem is that currently the method is not very safe, any change in the order of declarations in the direction will break the method, any suggestions on how to do this in a better way?
You could make the method abstract
, and implement it for each constant.
enum Direction {
NORTH() {
public Direction getOppositeDirection() {
return SOUTH;
}
},
EAST() {
public Direction getOppositeDirection() {
return WEST;
}
},
SOUTH() {
public Direction getOppositeDirection() {
return NORTH;
}
},
WEST() {
public Direction getOppositeDirection() {
return EAST;
}
};
public abstract Direction getOppositeDirection();
}
It's a bit wordy, though.
The next method is shorter but more difficult to read.
enum Direction {
NORTH, EAST, SOUTH, WEST;
static {
(SOUTH.oppositeDirection = NORTH).oppositeDirection = SOUTH;
(WEST.oppositeDirection = EAST).oppositeDirection = WEST;
}
private Direction oppositeDirection;
public Direction getOppositeDirection() {
return oppositeDirection;
}
}
The concise answer is:
public Direction getOppositeDirection() {
return
this==NORTH ? SOUTH :
this==EAST ? WEST :
this==SOUTH ? NORTH :
EAST;
}
You might prefer case statement
public Direction getOppositeDirection() {
switch (this) {
case NORTH: return SOUTH;
case EAST: return WEST;
case SOUTH: return NORTH;
case WEST: return EAST;
default: throw new Error();
}
}
You may also want to look in lambda for other case, but you will need to use a little cheat code because NORTH and EAST can't reference constant/field before they are defined:
import java.util.function.Supplier;
public enum Direction {
NORTH,
EAST,
SOUTH,
WEST;
private Supplier<Direction> opposite;
private Direction() {
}
static { // initialize opposite field
for (final Direction direction : Direction.values()) {
direction.opposite = oppositeOf(direction);
}
}
private static Supplier<Direction> oppositeOf(final Direction self) {
switch (self) {
case NORTH: return () -> SOUTH;
case WEST: return () -> EAST;
case EAST: return () -> WEST;
case SOUTH: return () -> NORTH;
default: throw new IllegalStateException("Invalid opposite: " + self);
}
}
public final Direction getOppositeDirection() {
return opposite.get();
}
public static void main(final String[] args) {
for (final Direction dir : Direction.values()) {
System.out.println(dir + " is opposite of " + dir.getOppositeDirection());
}
}
}
This does the same than having abstract method, but is more concise (except here because you need to add more to the code): you read directly what is the opposite direction instead of having the verbose method declaration (it is another matter if you need to also add other methods).
Also, it will not create pseudo class for each enums constant (eg: Direction$1
, Direction$2
, ...) because there is no need to.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With