好的,我现在有一个目标是进行基本的文字冒险。但是,要做到这一点,我需要/想要一个可以执行以下操作的switch语句:
我将如何做到这一点?你能告诉我这个具体例子的编码:
提示用户输入数据。 switch语句将“look box”视为一种情况,并将“sleep”视为另一种情况。该程序不关心任何单词的顺序,但是关心字母的顺序。
请详细解释一切。我刚刚开始编码。
编辑:谢谢你的所有答案。我知道有更好,更复杂,更有用的处理方式,但它还不是我的水平。答案 0 :(得分:12)
人们有时会问我为什么不建造船只。我很方便,我喜欢建造东西,然后我开航。我总是告诉他们,那些喜欢航行的人不应该建造船只,因为你最终会在你的船库里建造一艘船前花三年时间才能开航。如果你的目标是航行,买船。如果你的目标是建造一艘船,建造一艘船。
如果您的目标是通过撰写文本冒险来学习C#,那么您将学到很多东西。如果你的目标是编写文本冒险,那么不要使用C#,使用Inform7。它易于学习,专门用于编写文本冒险,可能是世界上最高级的语言。这是一种很棒的编程语言,我强烈推荐它。
回答你的具体问题:这不是一个很好的方法。文本冒险处理器实际工作的方式是首先编写一个程序,将用户键入的句子分解为标记。您必须逐个字符地搜索字符串,以查找单词之间的边界,例如空格,逗号,句点等。一旦找到边界,就可以提取边界之间的子串,并尝试通过将每个单词与字典中的单词进行比较来识别每个单词。
一旦你有一系列令牌,你就会尝试将序列与语法进行匹配。也就是说,您可以看到令牌序列是否可以归类为单字命令,如{“look”}或动词 - 名词短语,如{“look”,“at”,“the”,“red”,“按钮“}。你想打破它 - “看”是动词,“at”是介词,“红色按钮”是动词的对象,“the”是文章,“red”是形容词和“按钮”是名词。
听起来你是初学者,所以首先要集中精力进行词法分析;一次遍历字符串一个字符,识别单词边界,并构建List<string>
个标记。语法分析技术可能非常复杂;得到简单的东西,先坚实。
答案 1 :(得分:2)
考虑到你的开始,我们可以先在简单的案例中看一下,但是你不能用switch
语句来实现这个目标。
为了简单起见,我们假设您的命令限制为1或2个单词,并且第一个单词是动词,第二个单词如果存在则是名词。这为我们提供了很多可能性:
North
South
Examine
Take
Drop
等...
鉴于我们的输入字符串为strInput
:
string strInput = "examine hat";
我们想首先将其拆分。我们可以使用String.Split
:
string[] arguments = strInput.Split(' ');
这会给我们一个字符串数组:
参数[0]是检查
参数[1]是帽子
注意,如果用户输入了以下内容,我们并不总是第二个:
`North`
然后:
参数[0]是北
我们需要检查一下!现在,检查这个的可怕(但简单)方法是:
if(arguments[0] == "North")
{
// code to go North
}
else if(arguments[0] == "Take")
{
// code to work with Take. We'd check on arguments[1] here!
}
// etc...
不幸的是,这段代码会变得冗长,复杂且无法使用。你怎么知道在任何阶段你能做什么,不能做什么?你如何添加新命令?因此,让我们使用C#的精彩委托功能,并介绍Dictionary
。字典允许我们将一种类型(一种键)映射到另一种类型(在本例中为委托)。使用此方法,我们可以创建委托来处理不同类型的命令。
public delegate void HandleCommand(string[] _input);
在这里,我们委派了一名代表。不要担心它,但让我们介绍一些可以使用命令的函数:
public void Handle_North(string[] _input)
{
// code to go North. This function could just as easily be something that handles
// *all* directions and checks _input[0] to see where to go!
}
public void Handle_Take(string[] _input)
{
if(_input.Length > 1) // Did the user specify an object to take?
{
// code to handle Take.
}
}
等等。现在我们需要创建一个字典来将命令映射到这些函数:
Dictionary<String, HandleCommand> map = new Dictionary<String, HandleCommand>();
在这里,我们声明一个将字符串映射到我们的委托类型HandleCommand
的字典。现在我们需要填充它!
map["north"] = Handle_North;
map["take"] = Handle_Take;
// and the rest of our commands
现在,根据我们之前的示例,让我们像以前一样拆分字符串,并调用正确的处理程序!
string[] arguments = strInput.Split(' ');
if(arguments.Length > 0 && map.ContainsKey(arguments[0]))
map[arguments[0]](arguments); // calls our function!
现在我们有了一个可扩展的系统。添加新命令和处理程序很容易!它变得更复杂,但实质上这是做你想做的事情的好方法。
编辑:我知道你的问题说它不应该关心单词的顺序。如果你正在写一个文本冒险游戏,你最好形成一些动词/名词或其他语法,而不是允许随机输入内容。
答案 2 :(得分:1)
您无法使用switch
执行此操作,您必须使用if-else-if类型的结构。
string input=...
if(input.Contains("sleep")){ //contains sleep?
//do stuff for some word
}else if(input.Contains("look") && input.Contains("box")){ //contains look and box
//do stuff for the combination thing
}
switch
每个case
必须是一些静态的唯一值。因此,您无法使用.Contains
作为案例。
答案 3 :(得分:1)
这是另一个想法:
string input = "look at the sleep box";
bool caseA = input.Contains("sleep");
bool caseB = input.Contains("look") && input.Contains("box");
int scenarioId;
if (caseA && caseB)
scenarioId = 1;
else if (caseA)
scenarioId = 2;
else if (caseB)
scenarioId = 3;
// more logic?
else
scenarioId = 0;
switch (scenarioId)
{
case 1:
Console.WriteLine("Do scenario 1");
break;
case 2:
Console.WriteLine("Do scenario 2");
break;
case 3:
Console.WriteLine("Do scenario 3");
break;
// more cases
default:
Console.WriteLine("???");
break;
}
它使用if / then / else来评估特定场景,包括诸如"look at the sleep box"
之类的输入之类的潜在组合,然后使用switch语句来执行。
答案 4 :(得分:0)
你不能直接使用switch
,但是我认为你不应该这样做。您可能应该具有在与包含switch
的逻辑不同的位置查找单词的逻辑。
考虑使用枚举来包含所有可能的操作:
public enum AdventureAction
{
LookBox,
Sleep
}
考虑编写一个执行“解析”的方法:
public static AdventureAction Parse(string text)
{
if (text.Contains("look") && text.Contains("box"))
return AdventureAction.LookBox;
if (text.Contains("sleep"))
return AdventureAction.Sleep;
}
然后您可以使用简单的switch
语句来执行操作:
var action = Parse(input);
switch (action)
{
case AdventureAction.LookBox:
// do something interesting with the box
break;
case AdventureAction.Sleep:
// go to sleep
break;
}
答案 5 :(得分:0)
我目前正在编写自己的文本冒险引擎,因为Inform / Adrift / Quest都倾向于有一个致命的缺陷让我感到困惑 - 通知噩梦般的,混淆语法(这来自UX设计师喜欢为初学者提供尽可能简单的东西),Adrift丑陋的读者和Adrift / Quests缺乏真正的课堂/对象支持。
这可能不是最好的方法,但它到目前为止工作正常。我查看了Regex,但决定这样做。
首先要做的是将播放器的输入/命令字符串拆分为List。幸运的是,在这些游戏中,这个列表的第一个元素几乎总是一个动词。
您将需要可通过键访问的动词/对象/ etc数据类,其中包含可与其匹配的所有值,例如&#34;查看,检查,ex&#34;。
class Verb
{
string uniqueID;
List<string> values;
}
class Object
{
public uniqueID; // Because this is shared with Verbs, you could do a better unique ID system, but hey...
public List<string> articles;
public List<string> adjectives;
public List<string> noun;
}
你还需要一堆&#34;动作&#34;将从玩家的输入中匹配的子类。在这里你&#34;建立&#34;你的句子结构需要与玩家的输入相匹配。
class Action
{
string uniqueID;
List<SentenceElement> sentence;
void Execute();
bool RestrictionsCheck();
}
class Look : Action
{
override void Execute();
override bool RestrictionsCheck();
}
class LookAtObject : Action
{
override void Execute();
override bool RestrictionsCheck();
}
class LookAtBook : Action
{
override void Execute();
override bool RestrictionsCheck();
}
基类Action类有一个使用SentenceElements的句子构建器。它可以是一个逐段描述句子的列表。
class SentenceElement
{
List<string> values;
bool isOptional;
}
class VerbID : SentenceElement {}
class ObjectID : SentenceElement {}
class ObjectAny : SentenceElement {}
class CharacterID : SentenceElement {}
class CharacterAny : SentenceElement {}
class TextOptional : SentenceElement {}
class TextRequired : SentenceElement {}
class Parameter : SentenceElement {}
您现在可以搜索您的&#34;行动&#34;类,将第一个SentenceElement与玩家第一个输入动词进行比较,并保留一个匹配的列表作为&#34; potentialActions&#34;。 &#34; string.Contains&#34;会工作的。
现在你必须通过踩过你的玩家来找到最接近的匹配动作&#39;输入命令,并逐步执行比较它们的每个SentenceElement。保留每个位置的索引(playerInputIndex,potentialActionsIndex,sentenceElementIndex)。
如果找到匹配项,请增加playerInputIndex,直到它与SentenceElement不匹配,检查您的设置(isOptional等),然后移动到下一个句子元素索引并再次运行比较。最终,您将到达播放器输入或SentenceElements的末尾。
如果SentenceElements是&#34; isOptional&#34;,则会添加复杂性,因此必须进行检查,或者具有ObjectAny类型的SentenceElements的动作不应该与现有的一致,但显示一个&#34;你想吃哪个对象?&#34;信息。此外,与动词不同,对象具有额外的匹配参数,例如前缀/形容词/名词,而不是动词。
此系统还需要为您可能想要执行的每个操作创建一个新类。每个动作都有自定义&#34;限制&#34;它必须在它运行之前通过,例如&#34;引用的字符是否存活?&#34;等等。