【问题标题】:How do I implement a dispatch table for a text adventure game?如何为文本冒险游戏实现调度表?
【发布时间】:2012-05-13 05:56:24
【问题描述】:

我正在制作text adventure in C#,有人建议我使用dispatch table 而不是switch 语句。

下面是switch语句代码:

        #region Public Methods
        public static void Do(string aString)
        {
                if(aString == "")
                        return;

                string verb = "";
                string noun = "";

                if (aString.IndexOf(" ") > 0)
                {
                        string[] temp = aString.Split(new char[] {' '}, 2);
                        verb = temp[0].ToLower();
                        noun = temp[1].ToLower();
                }
                else
                {
                        verb = aString.ToLower();
                }

                switch(Program.GameState)
                {
                        case Program.GameStates.Playing:
                                if (IsValidInput(Commands, verb, true))
                                {
                                        switch(verb) //this is the switch statement
                                        {
                                                case "help":
                                                case "?":
                                                        WriteCommands();
                                                        break;
                                                case "exit":
                                                case "quit":
                                                        Program.GameState = Program.GameStates.Quit;
                                                        break;
                                                case "move":
                                                case "go":
                                                        MoveTo(noun);
                                                        break;
                                                case "examine":
                                                        Examine(noun);
                                                        break;
                                                case "take":
                                                case "pickup":
                                                        Pickup(noun);
                                                        break;
                                                case "drop":
                                                case "place":
                                                        Place(noun);
                                                        break;
                                                case "use":
                                                        Use(noun);
                                                        break;
                                                case "items":
                                                case "inventory":
                                                case "inv":
                                                        DisplayInventory();
                                                        break;
                                                case "attack":
                                                        //attack command
                                                        break;
                                        }
                                }
                                break;

                        case Program.GameStates.Battle:
                                if(IsValidInput(BattleCommands, verb, true))
                                {
                                        switch(verb) //this is the other switch statement
                                        {
                                                case "attack":
                                                        //attack command
                                                        break;
                                                case "flee":
                                                case "escape":
                                                        //flee command
                                                        break;
                                                case "use":
                                                        //use command
                                                        break;
                                                case "items":
                                                case "inventory":
                                                case "inv":
                                                        //items command
                                                        break;
                                        }
                                }
                                break;
                }
        }
        #endregion

如何重构它以使用调度表?

【问题讨论】:

  • 您应该看看this question,其中一个答案显示了一个看起来非常正确的 C# 示例,恕我直言。
  • 在我担心这个之前,我会专注于编写更小更模块化的函数 ;-)
  • @psycho 这完美地回答了我的问题。您应该将此作为答案发布,以便我接受。
  • @pst 你能给我举个例子说明要解决什么吗?
  • @ryansworld10 我可能会将每个游戏状态逻辑都放在它自己的函数中,这样分支(开关或调度或其他)就不会嵌套。

标签: c# adventure dispatch-table


【解决方案1】:

也许他指的是“双重调度”,或者Visitor Pattern

您可以拆分代码以改进更“调度员”的样式,如下所示:

public interface IGameState{
  void Help();
  void Question();
  void Attack();
}

public interface ICommand{
  bool IsValidFor(PlayingState state);
  bool IsValidFor(BattleState state);
  void Execute(IGameState state);
}

public class PlayingState : IGameState {
   public void Help(){ // Do Nothing }
   public void Question() { WriteCommands(); }

   private void WriteCommands(){ }
}

public class Battle : IGameState{
   public void Help(){ // Do Nothing }
   public void Question() { WriteCommands(); }
   public void Attack() { Roll(7); }

   private void Roll(int numDice){ }
}

public class CommandBuilder{
  public ICommand Parse(string verb){
    switch(verb){
       case "help":
         return new HelpCommand();
       case "?":
         return new QuestionCommand();
       case "attack":
         return new AttackCommand();
       default:
         return new UnknownCommand();
    }
  }
}

public class QuestionCommand(){
  bool IsValidFor(PlayingState  state){
     return true;
  }

  bool IsValidFor(BattleState state){
     return false;
  }

  void Execute(IGameState state){
     state.Question();
  }
}

public static void Do(string aString){
  var command = CommandBuilder.Parse(aString);
  if(command.IsValidFor(Program.GameStates))
     command.Execute(Program.Gamestates);
}

【讨论】:

  • 我不知道这意味着什么。这并没有回答我关于如何实现它的问题。
  • 我对此表示怀疑。调度表通常类似于Dictionary<string,Action>,至少在我谈到它时是这样。访问者模式只是为了 OO 而颠倒了一切。
  • 我已经更新了我的答案,说明我将如何以更加双重派发的方式解释实现。
  • 嗯,它更像是一种面向对象的方法。使用这种模式,您可以将动词切换全部集中在一个地方,并且随着界面的变化 - 您的代码将在构建时中断;而不是运行时。
【解决方案2】:

最简单的方法是使用代表字典。

例如:

Dictionary<string, Action> dispatch = new Dictionary<string, Action>();

dispatch["help"] = new Action(() => Console.WriteLine("Hello"));
dispatch["dosomething"] = new Action(() =>
{
    // Do something else
    Console.WriteLine("Do Something");
});

// Call the 'help' command
dispatch["help"]();

对于多个不同的参数,使用基本委托并使用动态调用可能是最简单的。

Dictionary<string, Delegate> dispatch = new Dictionary<string, Delegate>();

dispatch["help"] = new Action(() => Console.WriteLine("Hello"));
dispatch["dosomething"] = new Action<string>(s => Console.WriteLine(s));

dispatch["help"].DynamicInvoke();
dispatch["dosomething"].DynamicInvoke("World");

如果使用 .NET 4,您还可以使用动态类型在运行时解析,以稍微减少动态调用的混乱。

Dictionary<string, dynamic> dispatch = new Dictionary<string, dynamic>();

dispatch["help"] = new Action(() => Console.WriteLine("Hello"));
dispatch["dosomething"] = new Action<string>(s => Console.WriteLine(s));

dispatch["help"]();
dispatch["dosomething"]("World");

【讨论】:

  • 这有帮助,但是我如何将参数传递给在操作中调用的函数>
  • 好吧,我会选择这个。这似乎是最简单的方法。
  • 我仍然不太明白如何将参数传递给存储在字典中的语句(所以我可以告诉被调用的方法我的名词)。
  • 我为你添加了一些变种。
【解决方案3】:

收回@Jon Ericson 的介绍:

调度表是一种将索引(或键,请阅读下面@pst 的评论)值与操作相关联的数据结构。它是 switch 类型语句的相当优雅的替代品。

关于实现部分,请查看this question,尤其是this answer,恕我直言,这似乎很正确,但很容易理解。

【讨论】:

  • 一个“索引”可能不是完整的,正如它通常所暗示的那样。 “键”是一个更通用的术语,但不经常与可以制作合适的调度表的数组一起使用......
猜你喜欢
  • 2016-08-25
  • 2013-07-08
  • 2018-07-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多