8

我在 Groovy 中制作一个文本冒险游戏作为一种练习,我遇到了一个奇怪的错误。

现在,我有enum一个玩家可以去的方向,目前包含北、南、东、西、上和下。

我有一Room堂课,里面有Map其他相连的房间和他们的方向。当我在某个位置添加一个Room到另一个时,我希望能够在相反的方向上将电流添加到另一个。RoomDirectionRoomRoom

例如:如果我添加从房间 1 到房间 2 的北向连接,我希望能够同时添加从房间 2 到房间 1 的南向连接。

目前,我正在尝试使用带有附加实例变量(类型)的enum命名来实现这一点。这是不允许的吗?我没有收到编译器错误或任何东西,但我似乎无法让它工作。DirectionoppositeDirection

这是完整的enum声明:

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
    }
}

这就是我调用它的方法:

public void addConnection(Direction d, Spot spot){
    connections[d] = spot
    spot.connections[d.opposite()] = this
}

哪里connectionspublic Map<Direction, Spot>

在这种情况下,将添加一个条目connections,如下所示:

null:Spot@some_hexadecimal_representation

任何帮助都会很棒。谢谢!

4

3 回答 3

8

Groovy 似乎规避了 Java 中的编译错误

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

groovy 编译器不会对此抱怨,而是将需要前向声明的枚举值初始化为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.

输出

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

在 Java 中似乎工作得很好的一种解决方案是在类上添加一个staticDirection来初始化opposite值。翻译成 Groovy,那将是:

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"
}

现在打印正确的值

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

更新

另一种可能更直接的解决方案可以使用枚举上的方向索引来找到相反的:

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
    }
}

但我发现第一个更清晰,因为它不需要索引的那些神奇数字呵呵。

更新 2

现在,我可能对这里的高尔夫球场有所了解,但是您可以在不需要额外字段的情况下获得相反的方向,只需使用枚举值ordinal()(它们的索引):

enum Direction {
    North, South, East, West, Up, Down
    Direction getOpposite() { 
        values()[ordinal() + ordinal() % 2 * -2 + 1]
    }
}

它并不像看起来那么可怕!偶数方向(北、东、上)以相反的方向返回 at 的方向ordinal() + 1,而奇数方向(其他方向)返回 at 的方向ordinal() - 1。当然它在很大程度上依赖于枚举中元素的顺序,但是,你不喜欢简洁吗?=D

于 2012-07-02T23:57:11.103 回答
2

您可以通过在闭包中传递它并在需要相反时调用闭包来推迟对相反的评估:

public enum Direction {
    North({South}), South({North}), East({West}), West({East}), Up({Down}), Down({Up})
    private def opp
    Direction(opp) {
        this.opp = opp
    }
    public opposite() {
        return opp()
    }
}
public static void main(String[] args) {
    Direction.each { d ->
        println "${d} ... ${d.opposite()}"
    }
}

输出:

北...南
南北
东西
西...东
上...下
向下...向上
于 2013-03-05T17:05:24.440 回答
1

Directions调用枚举构造函数时,似乎有一半没有初始化。也就是说,当您调用时North(South), South 尚未初始化。它是下一个。

您陷入了一个鸡/蛋悖论,其中所有枚举常量必须先初始化,然后才能初始化其中一个。看来您需要重新组织一些代码来解决这个问题。我可能会建议:

public enum Direction {
    North(1), South(~1), East(2), West(~2), Up(4), Down(~4);

    private int value;

    Direction(int d){
        value = d;
    }

    private int getValue() {
        return value;
    }

    public Direction opposite(){
        for (Direction d : Direction.values()) {
            if (value == ~(d.getValue())) 
                return d;
        }
        return null;
    }
}

这利用按位运算符~来区分对立面。

于 2012-07-02T23:30:22.483 回答