如何实现连通房?

时间:2009-11-07 19:16:50

标签: java data-structures

这可能是一个重复的问题,因为我不知道用短语搜索查询。我正在Java中创建一个类似Zork的文本游戏,角色移动到彼此连接的不同房间。我希望能够列出玩家可用于此房间的所有选项。

例如,A室连接到B的东边,B连接到A的西边,C的南面,D的北面,依此类推。

我应该使用哪种数据结构,或者我应该如何尽可能有效地实现它?

7 个答案:

答案 0 :(得分:16)

要决定的第一件事是什么构成一个有效的方向:是来自固定列表还是自由形式的文本?最简单的解决方案是拥有四个基本方向。有人建议将其作为int数组。这可能是C / C ++ / C#中的有效解决方案(所有这些中的枚举只是int常量),但没有理由用Java来实现。

在Java中,您可以使用(类型安全)枚举 - 顺便提一下,它可以具有状态和行为 - 并使用EnumMap,这是高度高效。在内部,它只是一个由枚举序数值索引的数组。您可能会争辩说它与int数组有什么区别?答案是EnumMap中的int数组是类型安全随机访问集合的内部实现细节。

如果允许自由格式文本作为退出方向,则结构将如下所示:

Map<String, Direction> exits;

但我不建议这样做。我建议列举可能的方向:

public enum Direction {
  NORTH("north", "n"),
  NORTHWEST("northwest", "nw"),
  ...
  IN("in"),
  OUT("out");

  private final static Map<String, Direction> INSTANCES;

  static {
    Map<String, Direction> map = new HashMap<String, Direction>();
    for (Direction direction : values()) {
      for (String exit : direction.exits) {
        if (map.containsKey(exit)) {
          throw new IllegalStateException("Exit '" + exit + "' duplicated");
        }
        map.put(exit, direction);
      }
    }
    INSTANCES = Collections.unmodifiableMap(map);
  }

  private final List<String> exits;

  Direction(String... exits) {
    this.exits = Collections.unmodifiableList(Arrays.asList(exits));
  }

  public List<String> getExits() { return exits; }
  public String getName() { return exits.get(0); }
  public static Map<String, Direction> getInstances() { return INSTANCES; }
  public static Direction getDirection(String exit) { return INSTANCES.get(exit); }
}

然后存储:

private final Map<Direction, Exit> exits =
  new EnumMap<Direction, Exit>(Direction.class);

这为您提供了类型安全性,性能和可扩展性。

第一种思考方式是地图:

Map<String, Room> exits;

其中键是自由形式的方向(北,东,南等)。

下一个问题:什么是退出?在最简单的情况下,退出就是您最终的房间,但随后您开始询问各种问题,如:

  • 玩家可以看到出口吗?
  • 出口是关闭还是打开?
  • 可以关闭,打开,锁定,解锁,推开等出口吗?
  • 可以使用退出程序(例如你必须携带某个护身符)?
  • 你最终可能是程序化的(例如,你可能陷入陷阱并完全陷入其他地方)?
  • 可以使用退出触发器执行其他操作(例如,设置闹钟)吗?

有必要考虑文本冒险游戏的界面。玩家以下列形式输入命令:

Verb [[preposition1] object1 [[preposition2] object2]] 

这至少是一种可能性。例子包括:

  • 坐(动词=坐着);
  • 打开门(动词=打开,对象1 =门)
  • 看书;
  • 用铁键锁住胸部(动词=锁,对象1 =胸部,介词2 =用,对象2 =铁键);
  • 在orc上投掷火球;

所以上面介绍了一套相当全面的行为。所有这一切的重点是:

  • 退出将支持一些动词或命令(例如,你可以打开/关闭一扇门,但不能通道);
  • 怪物和物品也会支持命令(魔杖可以“挥手”,兽人可以“击中”);
  • 退出,​​怪物和物品就是所有类型的物体(游戏中可以通过某种方式与之互动的物品)。

这样:

public enum Command { LOOK, HIT, WAVE, OPEN, CLOSE, ... };

(毫无疑问是与这些实例相关的行为)和:

public class GameObject {
  boolean isSupported(Command command);
  boolean trigger(Command command);
}

public class Exit extends GameObject {
  ...
}

GameObjects也可能有其他状态,例如是否可以看到它们。有趣的是,Direction enum实例也可以说是Commands,它再次改变了抽象。

所以希望这有助于指出你正确的方向。抽象没有“正确”的答案,因为它完全取决于您需要建模和支持的内容。这应该有希望给你一个起点。

答案 1 :(得分:1)

一系列房间,每个房间都有一个出口列表,参考它所通过的房间。

答案 2 :(得分:1)

您可以将Room对象存储在List或Set中,或者(如Lars D建议的那样)存储数组。

在Room中,我认为存储出口的好方法(考虑到它们可能不仅仅是4个基本方向)将在地图中,方向为Enum,相邻房间为值。

这在存储空间非常有效,并且应该足够快速地浏览。

答案 3 :(得分:1)

听起来我需要一种称为 multimap 的数据结构。

这是一个类似哈希的集合,但键可以有多个值。在Java中没有这样的东西,但它可以通过使用具有两个级别的普通集合轻松构建:在地图中存储列表。钥匙是门的唯一标记,列表包含门连接的所有房间。通常这只是两个房间,但也许门有一定的魔力。

大致相同的是拥有自己的类门,其中包含您想要的任何内容以及对两个连通房的引用。这只需要一张普通的地图。

在任何一种情况下,Room类都有门钥匙,可以在集合中查找。

你当然可以将房间的拓扑结构直接放入房间的物体中,门的结构直接引用其他房间,但我怀疑门会有自己的状态(打开,关闭,锁定......)和在任何情况下,你都有一个关于如何创建所有这些链接的鸡与蛋的问题。使用库集合可以解决所有这些问题。

答案 4 :(得分:0)

您可以使用数组实现此目的:

class Room {
    private Room[] exits = new Room[4];
}

在此示例中,exits[0]可以包含对北方房间的引用,exits[1]到东方的房间,依此类推。如果一个元素包含null,则表示该方向没有退出。

请注意,您可以使用此方法创建非线性数据结构,例如A - &gt; B - &gt; C - &gt;甲

答案 5 :(得分:0)

当我看到这个问题时想到的第一件事就是创建一个Graph数据结构,但是阅读这些其他注释,Map可能要好得多。图表太复杂了。

答案 6 :(得分:0)

使用正确的图形库比这里的大多数Map方法更强大,更灵活。 Jung库(http://jung.sourceforge.net/)在Java中提供了许多基于图形的功能。虽然它可能看起来有点复杂,但从长远来看,它可能值得投入时间。