2016-06-23 8 views
2

私はユーザーに質問するボットを作成しようとしています。起動時に、ボットはどの選択肢を取るかを質問します。定義済みの回数FormDialogを呼び出す

  1. (彼はテーマと後にクイズの難易度を選択する必要があります);
  2. 彼が最後のクイズで得た得点を見てください。
  3. スコアをリセットします。

クイズの内容はXMLファイルに含まれています。私はすでに質問と答えを構造体に関連付けて保存しました。

[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をした:

FormBuilderです。ユーザーがクイズを開始することを選択した場合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 Frameworkエミュレータは500の内部サーバーエラーを送信します。

私はforループを使ってFormDialogを呼び出すことができるかどうかを調べるために、単純なメッセージと3つの選択肢からなる "テスト" FormBuilderを思い出しました。 ここ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は一度表示されますが、私は、forループを実行していることを見ました。ただし、testDialog変数はnullです。

ボットフレームワークエミュレータで10個の質問があるようにFormBuilderを正しく呼び戻していく方法を知っていますか?

ありがとうございます!

答えて

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

まず、あなたのためにあなたに感謝します答えはポルノイ!

しかし、私はすでにこのように、あなたの答えの前に、私の問題を解決するために成功:

QuizParameter
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); 
         }) 

は、カテゴリやユーザーの難易度の選択が含まれている構造体です。 質問文とその回答が含まれている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); 
    } 

AND、最終的には、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); 
      } 
     } 
    } 

希望すると助かります! :)

関連する問題