Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/307.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在基于java文本的游戏中解析命令的最佳方法_Java_Parsing - Fatal编程技术网

在基于java文本的游戏中解析命令的最佳方法

在基于java文本的游戏中解析命令的最佳方法,java,parsing,Java,Parsing,我正在用java开发一个基于文本的游戏,我正在寻找处理玩家命令的最佳方法。命令允许玩家与环境交互,如: 向北看:全面描述你在北向的情况 饮用药水:在你的物品清单中选择一个名为药水的物品并饮用它 触摸“奇怪的按钮”:触摸称为“奇怪的按钮”的对象,如果有一个连接到该对象,则触发一个操作,就像你死了一样。。。 库存:对您的库存进行完整描述 等 我现在的目标是开发一套完整的简单命令,但我很难找到一种简单的方法来解析它。我想开发一个灵活且可扩展的解析器,它可以调用主命令,如look、use、attack等

我正在用java开发一个基于文本的游戏,我正在寻找处理玩家命令的最佳方法。命令允许玩家与环境交互,如:

向北看:全面描述你在北向的情况 饮用药水:在你的物品清单中选择一个名为药水的物品并饮用它 触摸“奇怪的按钮”:触摸称为“奇怪的按钮”的对象,如果有一个连接到该对象,则触发一个操作,就像你死了一样。。。 库存:对您的库存进行完整描述 等 我现在的目标是开发一套完整的简单命令,但我很难找到一种简单的方法来解析它。我想开发一个灵活且可扩展的解析器,它可以调用主命令,如look、use、attack等。。。他们每个人在游戏中都有特定的语法和动作

我找到了很多工具来解析命令行参数,比如-I-v-verbose,但它们似乎都没有足够的灵活性来满足我的需要。它们可以逐个解析参数,但不考虑每个参数的特定语法。我试过JCommander,它看起来很完美,但我在什么是参数、参数、谁调用谁等之间迷失了方向


因此,如果有人能帮我选择正确的java库来实现这一点,那就太好了:

我认为您不想解析命令行参数。这意味着游戏中的每一步都需要运行一个新的JVM实例来运行不同的程序,以及在JVM会话之间保存状态的额外复杂性等等

这看起来像一个基于文本的游戏,提示用户下一步要做什么。您可能只想让用户在STDIN上输入输入

例如,假设您的屏幕显示:

你现在在一个黑暗的房间里。有一个电灯开关 你想做什么

然后,用户键入1或2,或者如果您想更有趣,请打开指示灯等。然后从STDIN中读取行并解析字符串,以查看用户选择了什么。我建议您查看java.util.scanner,了解如何轻松解析文本

Scanner scanner = new Scanner(System.in);
String userInput = scanner.readLine();
//parse userInput string here

我认为您不想解析命令行参数。这意味着游戏中的每一步都需要运行一个新的JVM实例来运行不同的程序,以及在JVM会话之间保存状态的额外复杂性等等

这看起来像一个基于文本的游戏,提示用户下一步要做什么。您可能只想让用户在STDIN上输入输入

例如,假设您的屏幕显示:

你现在在一个黑暗的房间里。有一个电灯开关 你想做什么

然后,用户键入1或2,或者如果您想更有趣,请打开指示灯等。然后从STDIN中读取行并解析字符串,以查看用户选择了什么。我建议您查看java.util.scanner,了解如何轻松解析文本

Scanner scanner = new Scanner(System.in);
String userInput = scanner.readLine();
//parse userInput string here

除非您要处理复杂的命令字符串,例如涉及算术表达式或平衡良好的括号,否则我建议您使用普通扫描仪

以下是一个易于阅读和维护的示例:

interface Action {
    void run(Scanner args);
}

class Drink implements Action {
    @Override
    public void run(Scanner args) {
        if (!args.hasNext())
            throw new IllegalArgumentException("What should I drink?");
        System.out.println("Drinking " + args.next());
    }
}

class Look implements Action {
    @Override
    public void run(Scanner args) {
        if (!args.hasNext())
            throw new IllegalArgumentException("Where should I look?");
        System.out.println("Looking " + args.next());
    }
}
并将其用作

Map<String, Action> actions = new HashMap<>();
actions.put("look", new Look());
actions.put("drink", new Drink());

String command = "drink coke";

// Parse
Scanner cmdScanner = new Scanner(command);
actions.get(cmdScanner.next()).run(cmdScanner);
并按如下方式使用:

@Retention(RetentionPolicy.RUNTIME)
@interface Command {
    String value();
}

@Command("drink")
class Drink implements Action {
    ...
}

@Command("look")
class Look implements Action {
    ...
}
List<Action> actions = Arrays.asList(new Drink(), new Look());

String command = "drink coke";

// Parse
Scanner cmdScanner = new Scanner(command);
String cmd = cmdScanner.next();
for (Action a : actions) {
    if (a.getClass().getAnnotation(Command.class).value().equals(cmd))
        a.run(cmdScanner);
}

除非您要处理复杂的命令字符串,例如涉及算术表达式或平衡良好的括号,否则我建议您使用普通扫描仪

以下是一个易于阅读和维护的示例:

interface Action {
    void run(Scanner args);
}

class Drink implements Action {
    @Override
    public void run(Scanner args) {
        if (!args.hasNext())
            throw new IllegalArgumentException("What should I drink?");
        System.out.println("Drinking " + args.next());
    }
}

class Look implements Action {
    @Override
    public void run(Scanner args) {
        if (!args.hasNext())
            throw new IllegalArgumentException("Where should I look?");
        System.out.println("Looking " + args.next());
    }
}
并将其用作

Map<String, Action> actions = new HashMap<>();
actions.put("look", new Look());
actions.put("drink", new Drink());

String command = "drink coke";

// Parse
Scanner cmdScanner = new Scanner(command);
actions.get(cmdScanner.next()).run(cmdScanner);
并按如下方式使用:

@Retention(RetentionPolicy.RUNTIME)
@interface Command {
    String value();
}

@Command("drink")
class Drink implements Action {
    ...
}

@Command("look")
class Look implements Action {
    ...
}
List<Action> actions = Arrays.asList(new Drink(), new Look());

String command = "drink coke";

// Parse
Scanner cmdScanner = new Scanner(command);
String cmd = cmdScanner.next();
for (Action a : actions) {
    if (a.getClass().getAnnotation(Command.class).value().equals(cmd))
        a.run(cmdScanner);
}

它的有趣之处在于,有一些命令是人类可读的,同时,它是机器可分析的

首先,您需要定义语言的语法,例如:

look (north|south|east|west)
但它是正则表达式,一般来说,这不是解释语法规则的最佳方式,所以我认为这更好:

Sequence("look", Xor("north", "south", "east", "west"));
因此,通过这样做,我认为你已经有了想法。您需要定义如下内容:

public abstract class Syntax { public abstract boolean match(String cmd); }
然后

大概吧

现在您需要的只是一个根据这些规则的递归解析器

您可以看到,它是递归结构,非常容易编码,并且非常容易维护。通过这样做,您的命令不仅是人类可读的,而且是机器可解析的


当然它还没有完成,你需要定义动作。但这很容易,对吗?这是典型的OO技巧。所有需要做的就是在Atom匹配时执行某些操作。

其中有趣的部分是有一些命令是人类可读的,同时,它是机器可解析的

首先,您需要定义语言的语法,例如:

look (north|south|east|west)
但它是正则表达式,一般来说,这不是解释语法规则的最佳方式,所以我认为这更好:

Sequence("look", Xor("north", "south", "east", "west"));
因此,通过这样做,我认为你已经有了想法。您需要定义如下内容:

public abstract class Syntax { public abstract boolean match(String cmd); }
然后

大概吧

现在您需要的只是一个根据这些规则的递归解析器

您可以看到,它是递归结构,非常容易编写代码,而且非常简单 我需要保持冷静。通过这样做,您的命令不仅是人类可读的,而且是机器可解析的



当然它还没有完成,你需要定义动作。但这很容易,对吗?这是典型的OO技巧。需要做的只是在Atom匹配时执行某些操作。

命令行是您键入以调用程序的行。这些只是用户输入。您拥有的是基于文本的游戏,而不是命令行。为此使用常规解析器。也许您可以看看Jflex和Cup?它们是扫描器和词法分析器。@Udy我认为op需要更像词法分析的东西,而不是cli解析器。如果您想自己编写一个,我可以向您展示一个很好的范例来实现这一点。命令行是您为调用程序而键入的行。这些只是用户输入。您拥有的是基于文本的游戏,而不是命令行。为此使用常规解析器。也许您可以看看Jflex和Cup?它们是一个扫描器和词法分析器。@Udy我认为op需要更像词法分析的东西,而不是cli解析器。如果您想自己编写一个,我可以向您展示一个很好的范例来实现这一点。是的,确实如此,但我不想等待像choose 1、2或3这样的特定响应。玩家可以做任何他想做的事情,而命令(可能是一个复杂的命令)必须被解析并触发正确的动作。好吧,无论哪种方式,你都必须把用户的选择读作字符串,然后从那里开始。你可以把它弄得很复杂。还要确保有一个全面的操作,如果你不理解用户想要什么,允许用户重新输入命令是的,确实如此,但我不想等待像选择1、2或3这样的特定响应。玩家可以做任何他想做的事情,而命令(可能是一个复杂的命令)必须被解析并触发正确的动作。好吧,无论哪种方式,你都必须把用户的选择读作字符串,然后从那里开始。你可以把它弄得很复杂。还要确保有一个全面的操作,如果你不理解用户想要什么,允许用户重新输入命令。这似乎是一个很好的方法。是的,但你必须编写大量代码来验证用户输入否?比如检查参数的正确数目等等。。。如果我可以将其委托给一个完美的解析器,那么我将尝试使用JavaCup/JFlex或ANTLR。但我担心的是,如何区分判断哪种输入是有效的以及如何处理这种输入的逻辑。例如,如果您想添加一种饮料,则必须更新语法验证器和处理饮料的类,而不是在饮料类内的switch语句中添加另一个case。考虑到您的注释,我将向Action.run接口方法添加throws-SyntaxException。每当action类遇到意外情况时,可能会抛出一个SyntaxException,语法和语义将齐头并进。添加新对象应该不是问题,因为我想将其从逻辑中分离出来,例如,命令drink将在数据库中查找饮料,如果找不到,然后它会弹出一条消息给玩家。我唯一需要关心的是:我的命令看起来像饮料吗?还有:有东西存在吗?是饮料吗?库存中的数量>0?我试着对调节剂这样做,比如,饮料给+5pv,+10力量,或者干脆杀了我。我正在考虑直接在数据库中向对象附加一个操作列表。如果可用的饮料字符串存储在数据库中,我看不出如何使用解析器库,甚至不能完全分离语法/语义。任何这样的方法都需要有效命令的完整语法。这似乎是一种很好的方法,是的,但你必须编写大量代码来验证用户输入否?比如检查参数的正确数目等等。。。如果我可以将其委托给一个完美的解析器,那么我将尝试使用JavaCup/JFlex或ANTLR。但我担心的是,如何区分判断哪种输入是有效的以及如何处理这种输入的逻辑。例如,如果您想添加一种饮料,则必须更新语法验证器和处理饮料的类,而不是在饮料类内的switch语句中添加另一个case。考虑到您的注释,我将向Action.run接口方法添加throws-SyntaxException。每当action类遇到意外情况时,可能会抛出一个SyntaxException,语法和语义将齐头并进。添加新对象应该不是问题,因为我想将其从逻辑中分离出来,例如,命令drink将在数据库中查找饮料,如果找不到,然后它会弹出一条消息给玩家。我唯一需要关心的是:我的命令看起来像饮料吗?还有:有东西存在吗?是饮料吗?库存中的数量>0?我正试着这么做
例如,对于调节剂,饮料的强度为+5pv、+10,或者干脆杀了我。我正在考虑直接在数据库中向对象附加一个操作列表。如果可用的饮料字符串存储在数据库中,我看不出如何使用解析器库,甚至不能完全分离语法/语义。任何这样的方法都需要有效命令的完整语法。