如何在C# WinForms trivia游戏中实现Fisher-Yates洗牌算法随机排序题目
实现步骤
1. 定义题目实体类
先创建专门存储题目信息的类,把题干、选项、正确答案序号、题目配图封装在一起,方便后续存入数组统一管理:
// 可以直接写在categoryquestion_form类的同级,或者单独存为.cs文件 public class Question { // 题干内容 public string Text { get; set; } // 四个选项 public string[] Options { get; set; } // 正确答案的序号(对应btn1到btn4的1-4编号,和你原有逻辑保持一致) public int CorrectAnswerNo { get; set; } // 题目配图 public Image Img { get; set; } }
2. 新增窗体全局变量
在你原有quiz game variables变量区新增3个变量:
// 存储所有题目的数组 private Question[] _questionBank; // 记录当前展示的题目在打乱后数组中的下标 private int _currentQuestionIndex = 0; // 随机数实例,供洗牌算法调用 private Random _rnd = new Random();
3. 实现Fisher-Yates洗牌算法
在窗体类里添加通用洗牌方法,支持打乱任意类型的数组,该算法是公认的无偏置公平洗牌实现:
private void ShuffleArray<T>(T[] array) { for (int i = array.Length - 1; i > 0; i--) { int j = _rnd.Next(i + 1); // 交换i和j位置的元素 (array[i], array[j]) = (array[j], array[i]); } }
4. 修改构造函数逻辑,初始化题库并洗牌
把原有构造函数替换为以下内容,先把所有题目存入数组,调用洗牌算法打乱后再加载第一题:
public categoryquestion_form() { InitializeComponent(); // 初始化所有题目到题库数组 _questionBank = new Question[] { new Question() { Text = "Which famous inventor worked at a patent office?", Options = new string[]{"Nikola Tesla", "Thomas Edison", "Albert Einstein", "Albert Wesker"}, CorrectAnswerNo = 3, Img = Properties.Resources.alberteinstein }, new Question() { Text = "The Niepce Crater on the Moon was named in recognition of the famous inventor Joseph Niepce. What did Niepce invent?", Options = new string[]{"A telescope", "A camera", "A microscope", "A nanoscope"}, CorrectAnswerNo = 2, Img = Properties.Resources.niepcecamera }, new Question() { Text = "What do inventors, Tesla, Popov and Lodge have in common?", Options = new string[]{"They invented engines.", "They invented telephone technology.", "They invented electric motors.", "They invented radio technology."}, CorrectAnswerNo = 4, Img = Properties.Resources.inventionofradio }, new Question() { Text = "The invention of the refrigerator made a significant improvement to our standard of living. When it was invented, not many people wanted one. Who invented the refrigerator ?", Options = new string[]{"Oliver Evans", "Michael Faraday", "Carl Von Linde", "Benjamin Franklin"}, CorrectAnswerNo = 1, Img = Properties.Resources.oliverevans }, new Question() { Text = "Many inventors contributed to the technology that created the television. There were conflicts between inventors over their rights to various aspects of this technology. Who invented the television?", Options = new string[]{"John Baird", "Philo Farnsworth", "Vladimir Zworykin", "Carl Von Linde"}, CorrectAnswerNo = 2, Img = Properties.Resources.farnsworth } }; // 调用洗牌算法打乱题目顺序 ShuffleArray(_questionBank); // 总题数直接取数组长度,后续加题无需手动修改 totalQuestions2 = _questionBank.Length; // 加载第一题 askquestionInventors(_currentQuestionIndex); }
5. 重写askquestionInventors方法,删除原有switch逻辑
原有硬编码题目的switch逻辑可以完全删除,现在直接从打乱的数组里取对应下标的题目赋值即可:
private void askquestionInventors(int qIndex) { // 取出当前要展示的题目 Question currentQ = _questionBank[qIndex]; // 赋值配图、题干 pictureBox_2.Image = currentQ.Img; question_label2.Text = currentQ.Text; // 赋值四个选项 btn1.Text = currentQ.Options[0]; btn2.Text = currentQ.Options[1]; btn3.Text = currentQ.Options[2]; btn4.Text = currentQ.Options[3]; // 赋值正确答案 correctAnswer2 = currentQ.CorrectAnswerNo; }
6. 微调答题事件的题号逻辑
把checkAnswerEvent2方法里原来操作questionNumber2的逻辑,替换为操作_currentQuestionIndex即可:
private void checkAnswerEvent2(object sender, EventArgs e) { var senderObject2 = (Button)sender; int buttonTag2 = Convert.ToInt32(senderObject2.Tag); if (buttonTag2 == correctAnswer2) { score2++; } _currentQuestionIndex++; // 所有题目答完 if (_currentQuestionIndex == totalQuestions2) { percentage2 = (int)Math.Round((double)(score2 * 100) / totalQuestions2); MessageBox.Show( "Quiz Ended!" + Environment.NewLine + "You have answered " + score2 + " questions correctly." + Environment.NewLine + "Your total percentage is " + percentage2 + "%" + Environment.NewLine + "Click OK to return menu" + Environment.NewLine ); score2 = 0; this.Close(); mainmenu_form f1 = new mainmenu_form(); f1.ShowDialog(); return; } // 加载下一题 askquestionInventors(_currentQuestionIndex); }
补充说明
- 后续新增题目只需要在
_questionBank数组初始化的位置按照原有格式新增Question实例即可,无需修改其他逻辑 - 每次打开答题窗体,题目顺序都会随机打乱
内容的提问来源于stack exchange,提问作者Joshua
相关产品推荐
相关产品推荐

