Java 如何实现互联房间?

Java 如何实现互联房间?,java,data-structures,Java,Data Structures,这可能是一个重复的问题,因为我不知道搜索查询的词组。我正在用Java创建一个类似Zork的基于文本的游戏,角色移动到相互连接的不同房间。我想能够列出一个球员在这个房间里的所有选择 例如,房间A东与B相连,B西与A相连,南与C相连,北与D相连,依此类推 我应该使用什么样的数据结构,或者我应该如何尽可能有效地实现这一点?一个房间数组,每个房间都有一个出口列表,并参考它所指向的房间。您可以使用一个数组来实现这一点: class Room { private Room[] exits = new

这可能是一个重复的问题,因为我不知道搜索查询的词组。我正在用Java创建一个类似Zork的基于文本的游戏,角色移动到相互连接的不同房间。我想能够列出一个球员在这个房间里的所有选择

例如,房间A东与B相连,B西与A相连,南与C相连,北与D相连,依此类推


我应该使用什么样的数据结构,或者我应该如何尽可能有效地实现这一点?

一个房间数组,每个房间都有一个出口列表,并参考它所指向的房间。

您可以使用一个数组来实现这一点:

class Room {
    private Room[] exits = new Room[4];
}
在本例中,
出口[0]
可能包含对北面房间的引用,
出口[1]
房间东面的引用,依此类推。如果元素包含
null
,则可能表示该方向没有出口


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

您可以将房间对象存储在列表、集合或(如Lars D所建议的)数组中

在房间内,我认为存储出口的一个好方法(考虑到它们可能不是4个基本方向)是在地图中,用枚举表示方向,用相邻房间作为值


这在存储空间上非常有效,而且应该足够快地导航。

首先要确定什么是有效的方向:它是来自固定列表还是自由格式的文本?最简单的解决方案是有四个基本方向。有些人建议将其作为int数组。这在C/C++/C#中可能是一个有效的解决方案(它们中的枚举都只是int常量),但在Java中没有理由这样做

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

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

Map<String, Direction> exits;
这至少是一种可能性。例如:

  • 坐(动词=坐)
  • 打开门(动词=打开,对象1=门)
  • 看看书
  • 用铁钥匙锁上箱子(动词=锁,对象1=箱子,介词2=带,对象2=铁钥匙)
  • 向兽人投掷火球
  • 等等
因此,上述内容涵盖了一系列相当全面的行为。所有这些的要点是:

  • 出口将支持许多动词或命令(例如,您可以打开/关闭门,但不能打开/关闭通道)
  • 怪物和物品也支持命令(魔杖可以“挥动”,兽人可以“命中”)
  • 出口、怪物和物品都是所有类型的物品(游戏中可以以某种方式进行交互的物品)
因此:

(毫无疑问,会有与这些情况相关的行为)以及:

游戏对象还可能具有其他状态,例如是否可以看到它们。有趣的是,enum实例的方向也可以说是命令,这再次改变了抽象


所以希望这能帮你找到正确的方向。抽象没有“正确”的答案,因为它完全取决于您需要建模和支持什么。然而,这应该给你一个起点。

当我看到这个问题时,首先想到的是制作一个图形数据结构,但是阅读这些其他评论,一个地图可能要好得多。图表太复杂了

使用适当的图形库将比这里的大多数映射方法更强大、更灵活。Jung库()在Java中提供了许多基于图形的功能。虽然它看起来有点复杂,但从长远来看,它可能是值得投入时间的。

在我看来,您需要一种称为多重映射的数据结构

这是一个类似于散列的集合,但其中的键可以有多个值。Java中没有这样一个集合,但它可以通过使用一个具有两个级别的普通集合来轻松构建:在映射中存储列表。钥匙是门的唯一标记,列表包含门连接的所有房间。通常只有两个房间,但门可能有某种程度的魔力

大致相同的事情是拥有自己的类门,其中包含您想要的任何内容,以及对两个连接房间的引用。然后,这只需要法线贴图

在任何一种情况下,Room类中都只有可以在集合中查找的门键


当然,您可以将房间的拓扑直接放入房间对象中,使门结构直接引用其他房间,但我怀疑门将具有其自身的状态(打开、关闭、锁定等),并且在任何情况下,您都有一个鸡和蛋的问题,即如何首先创建所有这些链接。使用图书馆藏品可以解决所有这些问题。

使用地图还可以存储一些非标准方向,如进站、出站、坠落等。-1这是一种糟糕且过于简单的表示方式。它使用字符串和int常量。至少使用EnumMap和方向枚举。即使如此,除了最基本的示例之外,它还不足以满足所有的需求。我建议您看看EnumMap的实现。它可能“糟糕且过于简单”,但也很简单且易于理解。从OP的问题来看,最终效率似乎不是这里的主要目标,而是理解可能涉及的数据结构。我提供了一个选项。@Greg:这样的数组在C#中可能有意义,因为枚举只是int,所以数组是一个自然选择,但在Java枚举中是这样的
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]] 
public enum Command { LOOK, HIT, WAVE, OPEN, CLOSE, ... };
public class GameObject {
  boolean isSupported(Command command);
  boolean trigger(Command command);
}

public class Exit extends GameObject {
  ...
}