2016-06-23 17 views
2

我正在嘗試創建一個向用戶提問的bot。在發佈時,機器人會詢問用戶會選擇哪個選項:回調FormDialog的定義次數

  1. 開始測驗(他將不得不選擇測驗的主題和難度);
  2. 查看他在最後一次測驗中得分;
  3. 重置分數。

測驗的內容是在XML文件中。我已經在結構中存儲了相關的問題和答案。

的FormBuilder是:

[Serializable] 
public class QuizQuestionsLoader 
{ 
    public QuizQuestion Question { get; set; } 

    public static IForm<QuizQuestionsLoader> QuestionLoaderForm(QuizQuestion question) 
    { 
     return new FormBuilder<QuizQuestionsLoader>() 
      .Field(new FieldReflector<QuizQuestionsLoader>(nameof(Question)) 
       .SetType(null) 
       .SetDefine(async (state, field) => 
       { 
        field 
         .AddDescription(state.Question.QuestionText, state.Question.QuestionText) 
         .AddTerms(state.Question.QuestionText, state.Question.QuestionText); 

        return true; 
       })) 
      .AddRemainingFields() 
      .Build(); 
    } 
} 

所以,我做了一個IDialog與確定用戶採取何種選擇開關。如果用戶選擇啓動測驗的DefaultCase將被激活:

new DefaultCase<QuizChoices?, IDialog<string>>((context, value) => 
       { 
        return Chain.From(() => FormDialog.FromForm(QuizStart.QuizForm, FormOptions.PromptInStart)) 
         .Select(c => c.category) 
         .ContinueWith(async (ctx, res) => 
         { 
          CategoryOptions? category = await res; 
          IList<QuizQuestion> questions = QuestionsLoader.LoadQuestions(category.Value.ToString().ToLowerInvariant()).ToList(); 

          QuizQuestion currentQuestion = questions[0]; 
          var questionsDialogs = Chain.From(() => FormDialog.FromForm(() => { return QuizQuestionsLoader.QuestionLoaderForm(currentQuestion); })).PostToUser(); 

          for (int i = 1; i < questions.Count(); i++) 
          { 
           currentQuestion = questions[i]; 

           questionsDialogs.ContinueWith(async (forctx, fores) => 
           { 
            await fores; 
            return Chain.From(() => FormDialog.FromForm(() => { return QuizQuestionsLoader.QuestionLoaderForm(currentQuestion); })); 
           }).PostToUser(); 
          } 

          return Chain.Return(questionsDialogs).Unwrap(); 
        }) 
        .ContinueWith(async (ctx, res) => 
        { 
         await res; 
         return Chain.Return("Quiz fini !"); 
        }); 
       }) 

我想顯示10個問題給用戶,這就是爲什麼我認爲召回FormBuilder是一個好主意,因爲我沒有看到我如何以另一種方式做到這一點。當我構建和運行這個時,在選擇難度之後,Bot框架模擬器發送500內部服務器錯誤。

這就是爲什麼我試圖回憶「測試」 FormBuilder,它是由蒙山一個簡單的消息和三個選擇,看看我是否可以用一個for循環召回FormDialog。 這裏是FormBuilder:

public enum TestOptions 
{ 
    A, B, C 
} 

[Serializable] 
public class Test 
{ 
    public TestOptions? choice; 

    public static IForm<Test> TestForm() 
    { 
     return new FormBuilder<Test>() 
      .Message("Test") 
      .Field(nameof(choice)) 
      .Build(); 
    } 
} 

這裏是IDialog:

return Chain.From(() => FormDialog.FromForm(Test.TestForm, FormOptions.PromptInStart)) 
         .ContinueWith(async(ctx, res) => 
         { 
          await res; 
          var testDialog = Chain.From(() => FormDialog.FromForm(() => { return Test.TestForm(); })).PostToUser(); 

          for (int i = 0; i < 2; i++) 
          { 
           testDialog.ContinueWith<Test, Test>(async (forctx, fores) => 
           { 
            await fores; 
            return Chain.From(() => FormDialog.FromForm(Test.TestForm, FormOptions.PromptInStart)); 
           }); 
          } 

          return Chain.Return(testDialog); 
         }) 

這樣,FormDialog就會顯示一次,但我看到了循環執行。但是,testDialog變量爲空。

所以,你知道我怎麼能繼續記錯我FormBuilder會對機器人框架模擬器10個問題?

非常感謝!

回答

2

我補充說,說明了如何在測驗中的這個commit問題迭代的樣本。它使用一個名爲FoldDialog一個可鏈接對話框調用一系列序列對話框並聚集響應:

var quiz = Chain 
      .PostToChain() 
      .Select(_ => "how many questions?") 
      .PostToUser() 
      .WaitToBot() 
      .Select(m => int.Parse(m.Text)) 
      .Select(count => Enumerable.Range(0, count).Select(index => Chain.Return($"question {index + 1}?").PostToUser().WaitToBot().Select(m => m.Text))) 
      .Fold((l, r) => l + "," + r) 
      .Select(answers => "your answers were: " + answers) 
      .PostToUser(); 

它允許這樣的劇本的創作:

"hello", 
"how many questions?", 
"3", 
"question 1?", 
"A", 
"question 2?", 
"B", 
"question 3?", 
"C", 
"your answers were: A,B,C" 
0

首先,感謝你回答Will Pornoy!

不過,我已經成功你的答案之前解決我的問題,是這樣的:

new DefaultCase<QuizChoices?, IDialog<string>>((context, value) => 
       { 
        return Chain.From(() => FormDialog.FromForm(QuizStart.QuizForm, FormOptions.PromptInStart)) 
         .Select(c => new QuizParameters 
         { 
          CategoryParameter = c.category.Value.ToString(), 
          DifficultyParameter = c.difficulty.Value.ToString() 
         }) 
         .ContinueWith<QuizParameters?, int>(async (ctx, res) => 
         { 
          await res; 

          IList<QuizQuestion> questions = QuestionsLoader.LoadQuestions(QuizParameters.CategoryParameter, QuizParameters.DifficultyParameter).ToList(); 
          return new QuizQuestionsLoader(questions); 
         }) 

哪裏QuizParameter是包含類別和用戶的難度選擇一個結構。 我得到一個簡單的IList其中包含問題文本及其答案。

最後,我把它傳遞給一個新對象QuizQuestionLoader。在這個類中,我提出一些方法:

[Serializable] 
public class QuizQuestionsLoader : IDialog<int> 
{ 
    public static int Score { get; private set; } 

    private IList<QuizQuestion> problems; 
    private QuizQuestion theQuestion; 

    private int index;  
    private int jokerCount = 2; 
    private const string jokerAnswerText = "Utiliser un joker"; 

    public QuizQuestionsLoader(IList<QuizQuestion> problems) 
    { 
     this.problems = problems; 
    } 

Task方法,其在每次測驗開始時間稱爲:

public async Task StartAsync(IDialogContext context) 
    { 
     problems.Shuffle(); 

     DisplayQuestion(context); 
    } 

一種DisplayQuestion方法重載(第一是的情況下,其中沒有百搭左起):

private void DisplayQuestion(IDialogContext context) 
    { 
     DisplayQuestion(context, false); 
    } 

    private void DisplayQuestion(IDialogContext context, bool useJoker) 
    { 
     theQuestion = problems[index]; 
     string questionText = theQuestion.QuestionText; 
     IList<Answer> answers = theQuestion.Answers.ToList(); 

     if (useJoker) 
     { 
      IList<Answer> randomBadAnswers = answers.Where(a => !a.IsCorrect).ToList(); 
      randomBadAnswers.Shuffle(); 
      randomBadAnswers = randomBadAnswers.Take(2).ToList(); 

      answers = answers.Except(randomBadAnswers).ToList(); 
     } 
     else if (jokerCount > 0) 
     { 
      Answer jokerAnswer = new Answer 
      { 
       AnswerText = $"{jokerAnswerText} ({jokerCount}) restant(s)" 
      }; 

      answers.Add(jokerAnswer); 
     } 

     PromptDialog.Choice(context, CheckResponseAsync, answers, questionText, null, 0, PromptStyle.Auto); 
    } 

,最後循環,直到顯示10個問題,這將刷新這一過程:

public async Task CheckResponseAsync(IDialogContext context, IAwaitable<Answer> argument) 
    { 
     Answer answer = await argument; 

     if (answer.AnswerText.StartsWith(jokerAnswerText)) 
     { 
      jokerCount--; 
      await context.PostAsync("Suppression de deux mauvaises réponses..."); 
      DisplayQuestion(context, true); 
     } 
     else 
     { 
      await context.PostAsync(answer.IsCorrect ? "Bonne réponse !" : "Mauvaise réponse !"); 
      index++; 

      Answer goodAnswer = theQuestion.Answers.First(a => a.IsCorrect); 

      if (answer.AnswerText == goodAnswer.AnswerText) 
      { 
       Score++; 
      } 

      if (index < problems.Count) 
      { 
       DisplayQuestion(context); 
      } 
      else 
      { 
       await context.PostAsync($"Votre score est de {Score}"); 
       context.Done(Score); 
      } 
     } 
    } 

希望它能幫上忙! :)