I'm making a Text Adventure game in Groovy as a sort of exercise, and I'm running into a strange error.
Right now, I have an enum
for the directions that a player will be able to go, currently containing North, South, East, West, Up, and Down.
I have a Room
class that holds a Map
of other connected rooms and their directions. When I add a Room
to another Room
at a certain Direction
, I want to be able to also add the current Room
to the other Room
at the opposite direction.
Ex: If I add a connection from Room 1 to Room 2 going north, I want to be able to add a connection from Room 2 to Room 1 going south at the same time.
Currently, I am trying to implement this using an enum
named Direction
with an attached instance variable opposite
(of type Direction
). Is this not allowed? I'm not getting compiler errors or anything, but I can't seem to get it to work.
Here's the full enum
declaration:
public enum Direction {
North(South), South(North), East(West), West(East), Up(Down), Down(Up)
private Direction opposite
Direction(Direction d){
opposite = d
}
public opposite(){
return opposite
}
}
And this is the method that I am calling it from:
public void addConnection(Direction d, Spot spot){
connections[d] = spot
spot.connections[d.opposite()] = this
}
where connections
is a public Map<Direction, Spot>
.
In this case, an entry gets added to connections
that looks like this:
null:Spot@some_hexadecimal_representation
Any help would be great. Thank you!
Enums are very powerful as they may have instance variables, instance methods, and constructors. Each enum constant should be written in capital letters. Every enum constant is by default internally public static final of type Enum declared.
10) You can not create an instance of enums by using a new operator in Java because the constructor of Enum in Java can only be private and Enums constants can only be created inside Enums itself. 11) An instance of Enum in Java is created when any Enum constants are first called or referenced in code.
Variables in Groovy can be defined in two ways − using the native syntax for the data type or the next is by using the def keyword. For variable definitions it is mandatory to either provide a type name explicitly or to use "def" in replacement. This is required by the Groovy parser.
Enum constants are final but it's variable can still be changed. For example, we can use setPriority() method to change the priority of enum constants. We will see it in usage in below example. Since enum constants are final, we can safely compare them using “==” and equals() methods.
Groovy seems to circumvent what in Java is a compilation error:
Main.java:2: illegal forward reference
North(South), South(North), East(West), West(East), Up(Down), Down(Up);
^
Main.java:2: illegal forward reference
North(South), South(North), East(West), West(East), Up(Down), Down(Up);
^
Main.java:2: illegal forward reference
North(South), South(North), East(West), West(East), Up(Down), Down(Up);
^
3 errors
The groovy compiler does not complain about that, but initializes the enum values that need forward declarations as null
:
public enum Direction {
North(South), South(North), East(West), West(East), Up(Down), Down(Up)
Direction(Direction d){
println "opposite of $this is $d"
}
}
Direction.South // Force enum instantiation in GroovyConsole.
Outputs:
opposite of North is null
opposite of South is North
opposite of East is null
opposite of West is East
opposite of Up is null
opposite of Down is Up
One solution that seems to work just fine in Java is adding a static
block on the Direction
class to initialize the opposite
values. Translated to Groovy, that would be:
enum Direction {
North, South, East, West, Up, Down
private Direction opposite
Direction getOpposite() { opposite }
static {
def opposites = { d1, d2 -> d1.opposite = d2; d2.opposite = d1 }
opposites(North, South)
opposites(East, West)
opposites(Up, Down)
}
}
Direction.values().each {
println "opposite of $it is $it.opposite"
}
Which now prints the correct values:
opposite of North is South
opposite of South is North
opposite of East is West
opposite of West is East
opposite of Up is Down
opposite of Down is Up
Another, maybe more straightforward, solution can using the direction indexes on the enum to find the opposites:
public enum Direction {
North(1), South(0), East(3), West(2), Up(5), Down(4)
private oppositeIndex
Direction getOpposite() {
values()[oppositeIndex]
}
Direction(oppositeIndex) {
this.oppositeIndex = oppositeIndex
}
}
But i find the first one clearer as it doesn't need those magic numbers for the indexes hehe.
Now, i'm probably getting a bit into golfing lands here, but you can get the opposite direction without the need of an extra field, just using the enum values' ordinal()
(their index):
enum Direction {
North, South, East, West, Up, Down
Direction getOpposite() {
values()[ordinal() + ordinal() % 2 * -2 + 1]
}
}
It's not as scary as it looks! Even directions (North, East, Up) return the direction at ordinal() + 1
as their opposite, while odd directions (the other ones) return the ones at ordinal() - 1
. Of course it is heavily relying on the order of the elements in the enum, but, don't you love the succinctness? =D
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