Skip to content

questionmanager.cs #6

Description

@tranlongcbvn112-sketch

using Microsoft.VisualBasic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;

public class QuestionManager
{
private int currentIndex = 0;
private int score = 0;
private List currentQuiz = new List();
private Random rnd = new Random();

public List<(string Question, string YourAnswer, string CorrectAnswer, bool IsCorrect)> Summary
    = new List<(string, string, string, bool)>();

public void SaveAnswerSummary(Question q, string yourAnswer, bool isCorrect)
{
    Summary.Add((q.QuestionText, yourAnswer, q.GetCorrectAnswer(), isCorrect));
}

public void ClearSummary()
{
    Summary.Clear();
}

public void AddQuestionFromUI(string type, string questionText, string[] options, int correct, string[] openAnswers, bool? isTrue)
{
    if (type == "mcq")
    {
        SaveQuestionToBank(new MultipleChoiceQuestion
        {
            QuestionText = questionText,
            Options = options ?? new string[0],
            CorrectOption = correct
        });
    }
    else if (type == "tf" && isTrue.HasValue)
    {
        SaveQuestionToBank(new TrueFalseQuestion
        {
            QuestionText = questionText,
            IsTrue = isTrue.Value
        });
    }
    else if (type == "open")
    {
        SaveQuestionToBank(new OpenEndedQuestion
        {
            QuestionText = questionText,
            AcceptedAnswers = (openAnswers ?? new string[0]).ToList()
        });
    }
}


public void StartQuiz(string targetType, int count)
{
    ClearSummary(); 
    currentQuiz.Clear();

    var selectedRaw = AIQuestionBank.Questions
        .OrderBy(_ => rnd.Next())
        .Take(count)
        .ToList();

    foreach (var raw in selectedRaw)
    {
        var q = ConvertAIToQuestion(raw);
        if (q != null)
        {
            var converted = ConvertToTargetType(q, targetType);
            currentQuiz.Add(converted);
        }
    }

    currentIndex = 0;
    score = 0;
}

public Question GetCurrentQuestion()
{
    if (currentIndex < currentQuiz.Count)
        return currentQuiz[currentIndex];
    return null;
}

public bool SubmitAnswer(string userAnswer)
{
    if (currentIndex >= currentQuiz.Count) return false;

    bool isCorrect = currentQuiz[currentIndex].CheckAnswer(userAnswer);
    if (isCorrect) score++;

    
    SaveAnswerSummary(currentQuiz[currentIndex], userAnswer, isCorrect);

    currentIndex++;
    return isCorrect;
}

public bool HasNextQuestion() => currentIndex < currentQuiz.Count;
public int GetScore() => score;
public int GetTotalQuestions() => currentQuiz.Count;

private Question ConvertToTargetType(Question q, string targetType)
{
    if (targetType == "mcq")
    {
        if (q is MultipleChoiceQuestion mcq) return mcq;
        if (q is TrueFalseQuestion tf)
        {
            var options = new List<string> { "True", "False", "Maybe", "Not sure" }
                .OrderBy(x => rnd.Next()).ToList();
            int correctIndex = options.FindIndex(opt =>
                (tf.IsTrue && opt == "True") || (!tf.IsTrue && opt == "False"));

            return new MultipleChoiceQuestion
            {
                QuestionText = tf.QuestionText,
                Options = options.ToArray(),
                CorrectOption = correctIndex
            };
        }
        if (q is OpenEndedQuestion open)
        {
            var correct = open.AcceptedAnswers.FirstOrDefault() ?? "N/A";
            var options = new[] { correct, "Wrong 1", "Wrong 2", "Wrong 3" }
                .OrderBy(x => rnd.Next())
                .ToArray();
            return new MultipleChoiceQuestion
            {
                QuestionText = open.QuestionText,
                Options = options,
                CorrectOption = Array.IndexOf(options, correct)
            };
        }
    }
    else if (targetType == "tf")
    {
        if (q is TrueFalseQuestion tf) return tf;
        if (q is MultipleChoiceQuestion mcq)
        {
            return new TrueFalseQuestion
            {
                QuestionText = $"Is correct answer \"{mcq.Options[mcq.CorrectOption]}\" for \"{mcq.QuestionText}\"?",
                IsTrue = true
            };
        }
        if (q is OpenEndedQuestion open)
        {
            var correct = open.AcceptedAnswers.FirstOrDefault() ?? "";
            return new TrueFalseQuestion
            {
                QuestionText = $"Is \"{correct}\" correct for \"{open.QuestionText}\"?",
                IsTrue = true
            };
        }
    }
    else if (targetType == "open")
    {
        if (q is OpenEndedQuestion open) return open;
        if (q is MultipleChoiceQuestion mcq)
        {
            return new OpenEndedQuestion
            {
                QuestionText = mcq.QuestionText,
                AcceptedAnswers = new List<string> { mcq.Options[mcq.CorrectOption] }
            };
        }
        if (q is TrueFalseQuestion tf)
        {
            return new OpenEndedQuestion
            {
                QuestionText = tf.QuestionText,
                AcceptedAnswers = new List<string> { tf.IsTrue ? "True" : "False" }
            };
        }

    }
    return q;
}

public Question ConvertAIToQuestion(string raw)
{
    if (string.IsNullOrWhiteSpace(raw)) return null;

    string[] lines = raw.Split('\n').Select(l => l.Trim()).Where(l => !string.IsNullOrWhiteSpace(l)).ToArray();
    if (lines.Length == 0) return null;

    string questionText = lines[0].Replace("Question:", "").Trim();

    // True/False
    if (lines.Any(l => l.StartsWith("Answer: True", StringComparison.OrdinalIgnoreCase)) ||
        lines.Any(l => l.StartsWith("Answer: False", StringComparison.OrdinalIgnoreCase)))
    {
        bool isTrue = lines.First(l => l.StartsWith("Answer:", StringComparison.OrdinalIgnoreCase))
                             .ToLower().Contains("true");
        return new TrueFalseQuestion { QuestionText = questionText, IsTrue = isTrue };
    }

    // Open Ended
    if (lines.Any(l => l.StartsWith("Answer:", StringComparison.OrdinalIgnoreCase)))
    {
        var accepted = lines.First(l => l.StartsWith("Answer:", StringComparison.OrdinalIgnoreCase))
                            .Replace("Answer:", "")
                            .Split(',')
                            .Select(x => x.Trim())
                            .Where(x => !string.IsNullOrWhiteSpace(x))
                            .ToList();
        return new OpenEndedQuestion { QuestionText = questionText, AcceptedAnswers = accepted };
    }

    // Multiple Choice 
    var optionsList = new List<string>();
    int correctIndex = -1;

    for (int i = 1; i < lines.Length; i++)
    {
        string line = lines[i];
        bool isCorrect = line.StartsWith("*");
        if (isCorrect)
        {
            line = line.Substring(1).Trim();
            correctIndex = optionsList.Count;
        }

        
        if (line.Length > 2 && line[1] == '.')
            line = line.Substring(2).Trim();

        optionsList.Add(line);
    }

    return new MultipleChoiceQuestion
    {
        QuestionText = questionText,
        Options = optionsList.ToArray(),
        CorrectOption = correctIndex
    };
}

private void SaveQuestionToBank(Question q)
{
    string formatted = FormatAsAIEntry(q);
    AIQuestionBank.AddToBank(formatted);
}
public string FormatAsAIEntry(Question q)
{
    if (q is MultipleChoiceQuestion mcq)
    {
        string result = $"Question: {mcq.QuestionText}";
        for (int i = 0; i < mcq.Options.Length; i++)
        {
            string mark = (i == mcq.CorrectOption) ? "*" : "";
            result += $"\n{mark}{i + 1}. {mcq.Options[i]}";
        }
        return result;
    }
    else if (q is OpenEndedQuestion open)
    {
        return $"Question: {open.QuestionText}\nAnswer: {string.Join(", ", open.AcceptedAnswers)}";
    }
    else if (q is TrueFalseQuestion tf)
    {
        return $"Question: {tf.QuestionText}\nAnswer: {(tf.IsTrue ? "True" : "False")}";
    }
    else
    {
        return q.QuestionText;
    }
}

}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions