如何在C#中实现交互式决策树

How to implement an interactive decision tree in C#

我需要允许用户通过在屏幕上显示的两个简单选项之间进行选择来选择自己的路径,以便继续进行下一组选择,直到他们到达其中一个结局,即像这样的事情应该实现:

我试过下面的代码,但每次只计算左边。我想知道如何才能获得如上图(覆盖所有分支)的结果?例如,如果用户选择 "No" 应用程序不应该向用户询问任何进一步的问题,而只是简单地显示 "Maybe you want a Pizza" 消息。我已经用决策树算法完成了这个并且需要修复它,以便它像上图一样覆盖左侧和右侧。

namespace ConsoleApp3
{
    class Program
    {
        static void Main(string[] args)
        {
            var decisionTree = MainDecisionTree();

            var client = new Client();

            Console.WriteLine("Do you want a book? true/false");
            client.Answer[0] = bool.Parse(Console.ReadLine());
            Console.WriteLine("Do you like it? true/false");
            client.Answer[1] = bool.Parse(Console.ReadLine());
            Console.WriteLine("Are you sure? true/false");
            client.Answer[2] = bool.Parse(Console.ReadLine());

            decisionTree.Evaluate(client);

            Console.WriteLine("Press any key...");
            Console.ReadKey();
        }

        private static DecisionQuery MainDecisionTree()
        {
            //Decision 2
            var wantBranch = new DecisionQuery
            {
                Title = "Do you want a book?",
                Test = (client) => client.Answer[0],
                Positive = new DecisionResult { Result = true },
                Negative = new DecisionResult { Result = false }
            };

            //Decision 1
            var deserveBranch = new DecisionQuery
            {
                Title = "Do you like it?",
                Test = (client) => client.Answer[1],
                Positive = wantBranch,
                Negative = new DecisionResult { Result = false }
            };


            //Decision 0
            var sureBranch = new DecisionQuery
            {
                Title = "Are you sure?",
                Test = (client) => client.Answer[2],
                Positive = deserveBranch,
                Negative = new DecisionResult { Result = false }
            };

            return sureBranch;
        }
    }

    public class DecisionResult : Decision
    {
        public bool Result { get; set; }

        public override void Evaluate(Client client)
        {
            Console.WriteLine("\r\nThe result: {0}", Result ? "Buy it" : "You need to wait");
        }
    }

    public class DecisionQuery : Decision
    {
        public string Title { get; set; }
        public Decision Positive { get; set; }
        public Decision Negative { get; set; }
        public Func<Client, bool> Test { get; set; }

        public override void Evaluate(Client client)
        {
            bool result = this.Test(client);
            string resultAsString = result ? "yes" : "no";

            Console.WriteLine($"\t- {this.Title}? {resultAsString}");

            if (result) this.Positive.Evaluate(client);
            else this.Negative.Evaluate(client);
        }
    }

    public abstract class Decision
    {
        public abstract void Evaluate(Client client);
    }

    public class Client
    {
        public bool[] Answer { get; set; } = new bool[3];
    }
}

你的决策树设计的很好,只是你问用户的方式不行。 你提前问所有的问题,然后再去决策树。 当然,这棵树不能让被问到的问题不被问到。 这不是决策树问题。

你必须把这些行:

    Console.WriteLine("Are you sure? true/false");
    client.Answer[2] = bool.Parse(Console.ReadLine());

进入 Evaluate 方法,或者您执行回调或任何架构设计以将逻辑与 user-interface 分开。 decision-tree 必须问,或者至少知道这个问题。 答案无需保存,输入即可评价。

也许你将一些东西传递给要求用户评估方法

public interface IAsk
{
    bool Question(string message);
}

对于您的示例,您将其实例化为

public class ConsoleAsk : IAsk
{
    bool Question(string message)
    {
         Console.WriteLine(message);
         return  bool.Parse(Console.ReadLine());
    }
}

然后你像这样修改你的评估:

    public override void Evaluate(IAsk ask)
    {
        bool result = ask.Question("do you feel good or bad");
        string resultAsString = result ? "yes" : "no";

        Console.WriteLine($"\t- {this.Title}? {resultAsString}");

        if (result) this.Positive.Evaluate(ask);
        else this.Negative.Evaluate(ask);
    }

当然你用你的标题替换问题 属性。

如果我理解你的问题,这里是你的代码更正。

我重命名了一些东西。

我调用了 MakeDecisionTree 使用条件树初始化专家系统的方法,它 returns 根条件。

每个condition包含一个sentenceevaluate,它可以是一个query或一个result

对于resultevaluate显示sentence

对于 queryevaluate 方法要求用户通过 yesno 回答问题。并使用这个答案,它调用下一个 child condition.

的相应 evaluate

对不起我的英语,这不是我的母语,而且我不参与人工智能。

static private void DecisionTreeTest()
{
  Console.WriteLine("Please, answer a few questions with yes or no.");
  Console.WriteLine();
  MakeDecisionTree().Evaluate();
}
static private bool GetUserAnswer(string question)
{
  Console.WriteLine(question);
  string userInput;
  while ( true )
  {
    userInput = Console.ReadLine().ToLower();
    if ( userInput == "yes" )
      return true;
    else
    if ( userInput == "no" )
      return false;
    else
      Console.WriteLine("Your answer is not supported, retry please." +
                        Environment.NewLine + Environment.NewLine +
                        question);
  }
}
static private DecisionTreeQuery MakeDecisionTree()
{
  var queryAreYouSure
    = new DecisionTreeQuery("Are you sure?",
                            new DecisionTreeResult("Buy it."),
                            new DecisionTreeResult("You need to wait."),
                            GetUserAnswer);
  var queryIsItAGoodBook
    = new DecisionTreeQuery("Is it a good book?",
                            new DecisionTreeResult("What are you waiting for? Just buy it."),
                            new DecisionTreeResult("Find another one."),
                            GetUserAnswer);
  var queryDoYouLikeIt
    = new DecisionTreeQuery("Do you like it?",
                            queryAreYouSure,
                            queryIsItAGoodBook,
                            GetUserAnswer);
  var queryDoYouWantABook
    = new DecisionTreeQuery("Do you want a book?",
                            queryDoYouLikeIt,
                            new DecisionTreeResult("Maybe you want a pizza."),
                            GetUserAnswer);
  return queryDoYouWantABook;
}
abstract public class DecisionTreeCondition
{
  protected string Sentence { get; private set; }
  abstract public void Evaluate();
  public DecisionTreeCondition(string sentence)
  {
    Sentence = sentence;
  }
}
public class DecisionTreeQuery : DecisionTreeCondition
{
  private DecisionTreeCondition Positive;
  private DecisionTreeCondition Negative;
  private Func<string, bool> UserAnswerProvider;
  public override void Evaluate()
  {
    if ( UserAnswerProvider(Sentence) )
      Positive.Evaluate();
    else
      Negative.Evaluate();
  }
  public DecisionTreeQuery(string sentence,
                           DecisionTreeCondition positive,
                           DecisionTreeCondition negative,
                           Func<string, bool> userAnswerProvider)
    : base(sentence)
  {
    Positive = positive;
    Negative = negative;
    UserAnswerProvider = userAnswerProvider;
  }
}
public class DecisionTreeResult : DecisionTreeCondition
{
  public override void Evaluate()
  {
    Console.WriteLine(Sentence);
  }
  public DecisionTreeResult(string sentence)
    : base(sentence)
  {
  }
}