8

一種の演習としてGroovyでテキストアドベンチャーゲームを作成していますが、奇妙なエラーが発生しています。

今、私はenumプレイヤーが進むことができる方向を持っています。現在、北、南、東、西、上、下が含まれています。

私が持っRoomて保持しているクラスMapの他の接続されたお部屋とその方向のを。私は追加するRoomと、他Roomに特定Directionで、私はまた、電流を追加できるようにしたいRoomRoomにで反対方向。

例:北に向かう部屋1から部屋2への接続を追加する場合、同時に南に向かう部屋2から部屋1への接続を追加できるようにしたい。

現在、 (タイプの)インスタンス変数が付加されたenumnamedを使用してこれを実装しようとしています。これは許可されていませんか?コンパイラエラーなどは発生していませんが、動作しないようです。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
}

はどこにconnectionsありますかpublic 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でうまく機能しているように見える1つの解決策は、値を初期化するためにクラスにブロックを追加することstaticDirectionoppositeです。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
    }
}

しかし、最初の1つは、インデックスheheにこれらの魔法数を必要としないため、より明確になります。

アップデート2

さて、私はおそらくここでゴルフ場に少し入り込んでいますが、列挙値(それらのインデックス)を使用するだけで、余分なフィールドを必要とせずに反対方向に進むことができます:ordinal()

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

見た目ほど怖くない!偶数の方向(北、東、上)ordinal() + 1は反対の方向を返しますが、奇数の方向(他の方向)はでの方向を返し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

Directionsenumコンストラクターが呼び出されたときに半分が初期化されていないようです。つまり、を呼び出すときNorth(South)、Southは初期化されていません。次の行です。

チキン/エッグのパラドックスに巻き込まれ、列挙型定数の1つを初期化する前にすべての列挙型定数を初期化する必要があります。これを説明するために、コードの一部を再編成する必要があるようです。私は提案するかもしれません:

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 に答える