【问题标题】:Designing a simple console trivia application设计一个简单的控制台琐事应用程序
【发布时间】:2013-11-25 15:59:20
【问题描述】:

我们的任务是设计一个 C# 琐事应用程序作为文件 I/O 练习。到目前为止,我有一个良好的开端,但演示步骤有点难倒我。

我从一个包含以下数据的分隔文件开始:

Question;CorrectAnswerA;AnswerB;AnswerC;AnswerD;AnswerExplanation

例如,

 What color is the sky?;Blue;White;Green;Yellow;The sky is blue.

游戏将显示用户可以选择的问题和四个答案。

What Color is the Sky?
A. Blue
B. White
C. Green
D. Yellow

Select A, B, C, or D: 

不幸的是,为了便于填充数据集,A 始终是正确答案。我想随机化四个答案的显示顺序,但程序仍然需要知道哪个是正确答案。我还需要将ABCD 的用户输入绑定到答案的特定实例,以将selectedAnswerStringcorrectAnswerString 进行比较。

我一直在玩随机填充的四个答案的数组,但我无法理解如何根据用户的选择将某些内容标记为正确;我执行或分配的逻辑似乎总是超出范围或在数组中的所有四个记录中重复。

与我交谈过的其他学生说,他们创建了数据集,其中包含预先打乱的答案(这样他们就可以按阅读的顺序打印它们),并带有第五个答案字段以获取正确答案。虽然绝对是实现它的简单方法,但我认为它不像我的策略那么优雅。

我应该只更改输入数据集吗?有人对实现我的随机化想法的好方法有任何想法吗?

【问题讨论】:

    标签: c# random user-input


    【解决方案1】:

    创建一个名为 Question 的类,其属性为:int Idstring QuestionTextList<string> Answersstring CorrectAnswer

    或者,作为进一步的步骤,还使用IdValue 创建类Answer 并引用它。

       public class Question
        {
            public int Id;
            public string QuestionText;
            public List<Answer> Answers;
            public Answer CorrectAnswer;
        }
    
        public class Answer
        {
            public int Id;
            public string Value;
        }
    

    然后填充此结构并在打印时随机化

    【讨论】:

      【解决方案2】:

      使用单独的变量跟踪正确答案。然后使用Fisher-Yates 打乱你的数组:

      Random random = new Random();
      
      void Shuffle(string[] answers) {
         for (int i = 0; i < answers.Length - 1; i++) {
            int j = random.Next(i, answers.Length);
            string temp = answers[j];
            answers[j] = answers[i];
            answers[i] = temp;
         }
      }
      

      用户回复后,只需将他们的选择与您保存的正确答案进行比较。

      【讨论】:

      • 我如何跟踪用户的选择和答案? switch 管理A 的最佳方式是answers[1]Banswers[2] 等吗?还是有更好的策略?
      • @dwwilson66 这很好,尽管您需要记住数组是从零开始索引的。你可以使用answers[selectedChar - 'A'],它会给你A = 0, B = 1, ...
      • 时间还早……还没有咖啡。 :) 我知道。
      【解决方案3】:

      尝试以这种方式为问题定义数据结构:

      public class Question
      {
          public string Question;
          public string[] Answers;
          public int CorrectAnswer;
          public string CorrectAnswerExplanation
      }
      

      这样您可以打乱数组Answers 中的字符串,同时仍跟踪CorrectAnswer 中正确答案的索引。

      或者,如果您不能使用单独的类来模拟问题(这是一个家庭作业问题,所以您可能还没有学过),您可以使用数组中的预定位置(第 1 个或第 5 个元素)保存正确答案的索引。所以你的答案数组看起来像:

      "Blue", "White", "Green", "Yellow", "0"
      

      【讨论】:

      • 我们已经学会了如何使用单独的课程......但是我与之交谈的所有其他学生都在使用他们数据集中的一个字段来保存正确答案标记。就个人而言,我认为这违背了可重用性的目的,我试图避免对任何可以通过编程确定的东西进行硬编码。我的导师和我整个学期都在讨论对象或数据结构需要或应该有多通用。但这是 interpersonal-relations-overflow.com 的主题。 ;)
      【解决方案4】:

      第 1 步:定义数据结构。其他人已经给了你一个结构,所以使用它。

      第 2 步:填充数据结构。您可以 System.IO.File.ReadLines 并解析每一行 - 我假设您已经处理了这一点。

      第 3 步:随机排列答案的顺序。为此,假设你有你的结构:

      public static void RandomiseAnswers(IEnumerable<Question> questions)
      {
          var rand = new Random((int)DateTime.Now.Ticks);
          foreach (var question in questions) 
          {
              question.Answers = question.Answers.OrderBy(x => rand.Next()).ToArray();
          }
      }
      

      第 4 步:为您的出色工作获得老师颁发的金星

      【讨论】:

      • 我希望。她是为我们提供的 UML 添加方法而停靠点的类型。但我喜欢这个……只是为了惹她。我对这条线确实有一个问题:var rand = new Random((int)DateTime.Now.Ticks); 是否使用当前时间作为种子进行随机化?我不熟悉其中的.Ticks,现在我要去看看 MSDN 上的内容。 :)
      【解决方案5】:

      就我个人而言,我会在默认为 false 的 Answer 类中放置一个布尔值。这样,当您选择答案时,您可以阅读它是否正确。

      public class AskQuestion
      {
          public int Id;
          public string Question;
          public string Explanation;
          public List<Answer> Answers = new List<Answer>();
      }
      
      public class Answer
      {
          public bool Correct = false;
          public string Value;
      }
      

      现在,当您将列表随机化时,会自动识别正确答案

      使用这些类的一种方法如下:

          static void Main(string[] args)
          {
              StreamReader sr = new StreamReader("text.txt");
              List<AskQuestion> Questions = new List<AskQuestion>();
              Random rnd = new Random(DateTime.Now.Millisecond);
              //Loop through the file building a list of questions
              while(!sr.EndOfStream)
              {
                  AskQuestion NewQuestion = new AskQuestion();
                  string[] input = sr.ReadLine().Split(';');
                  NewQuestion.Question = input[0];
                  NewQuestion.Explanation = input[5];
                  for(int i = 1; i < 5; i++)
                  {
                      Answer NewAnswer = new Answer();
                      NewAnswer.Value = input[i];
                      NewQuestion.Answers.Add(NewAnswer);
                  }
                  //The first question is always correct so set its boolean value to true;
                  NewQuestion.Answers[0].Correct = true;
                  //Now ranmdomize the order of the answers
                  NewQuestion.Answers = NewQuestion.Answers.OrderBy(x => rnd.Next()).ToList();
                  Questions.Add(NewQuestion);
              }
              //Generate menu and get response for each question
              foreach(AskQuestion q in Questions)
              {
                  Console.WriteLine(q.Question + ":\n\tA - " + q.Answers[0].Value + "\n\tB - " + q.Answers[1].Value + "\n\tC - " + q.Answers[2].Value + "\n\tD - " + q.Answers[3].Value + "\n");
                  char input = '0';
                  while(input < 'A' || input > 'D')
                  {
                      input = char.ToUpper(Console.ReadKey().KeyChar);
                      if(input >= 'A' && input <= 'D')
                      {
                          //Use the boolean value in the answer to test for correctness.
                          if(q.Answers[input - 'A'].Correct)
                          {
                              Console.WriteLine("\nCorrect\n");
                          }
                          else
                              Console.WriteLine("\nWrong\n");
      
                          Console.WriteLine(q.Explanation);
                      }
                  }
              }
              Console.ReadLine();
          }
      

      【讨论】:

      • 那么这样的答案不能在不同的问题中重复使用。
      • 每个问题都有自己的答案列表。重复使用不同问题的答案没有多大意义。类的每个实例都有自己的字符串和布尔值。
      • “它自己的答案列表” - 正确,但“唯一答案列表” - 没有必要,因为可能存在“真/假”问题或“2^3=”或“字节中有多少位”等。这不是必需品,而是概率,在这种情况下,重复使用已经存在的答案比创建新的副本更明智
      • 如果希望重新使用 AskQuestion 对象并更改可以轻松完成的值。该代码中的任何内容都不会排除这种情况。只需更改值。
      • in this case it will be wiser to re-use already existent answers than to create new duplicates 所以你的意思是,从数据源中获取问题和答案,并循环遍历所有以前的答案,找到一个重复的并重新使用它,而不是创建一个新的具有重复值。这没有任何意义。
      猜你喜欢
      • 1970-01-01
      • 2017-05-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多