# Основные понятия Для того чтобы составить варианты, вам сперва нужно: 1) написать все задачи/генераторы задач, 2) составить из них пул задач и 3) описать структуру варианта. Разберём по пунктам: 1.1 Задача - это основной строительный блок варианта. В `QuizGen` задача представляет собой класс с тремя значениями. Одно обязательные - это вопрос задачи `question`. И два опциональных -- ответ к задаче `answer` и теги `tags` (про которые позже) ```{python} from modules.task import QTask from modules.tag import Tags task = QTask( question="Посчитайте дисперсию для следующего ряда: 5, 6, 7, 8, 9", answer="2", # можно опустить или не давать ответ: answer = None tags=Tags( ("тема", "дисперсия"), ("сложность", "лёгкая"), ... ) # теги можно определять любые. Первое значение - это категория, второе - это значение в этой категории. ) ``` 1.2 Генератор задач - это класс, с функцией generate(), которая при вызове генерирует задачу `QTask`: ```{python} from moduels.task.factory.default import QTaskFactoryDefault from modules.task import QTask from modules.tag import Tags #Сначала определим функцию, которая будет использоваться для генерации задач def task_generator_function(): # генерируем два случайных целых числа от 1 до 9 alpha = random.randint(1, 9) beta = random.randint(1, 9) # Используем сгенерированные числа, чтобы составить задачу question = f"Чему равна дисперсия величины V({alpha} * X + {beta} * Y), если X и Y подчинены стандартному нормальному закону распределения и независимы друг от друга?" answer = f"{alpha ** 2 + beta ** 2}" return QTask( question, answer, ) # С её помощью создадим генератор задач variance_task_factory = QTaskFactoryDefault(task_generator_function) # Получаем генератор, который умеет производит задачи с разными числами, каждый раз, когда мы вызываем фукнцию generate(): variance_task_factory.generate() # => Чему равна дисперсия величины V(3 * X + 5 * Y), если X и Y подчинены стандартному нормальному закону распределения и независимы друг от друга? Ответ: 34 variance_task_factory.generate() # => Чему равна дисперсия величины V(6 * X + 2 * Y), если X и Y подчинены стандартному нормальному закону распределения и независимы друг от друга? Ответ: 40 ``` 2. Пул задач. Пул - это массив задач и генераторов задач, из которых составляются варианты. ```{python} from modules.variant_builder.task_pool import QTaskPool from modules.task import QTask tasks = [ QTask( question="Текст задачи 1" ), QTask( question="Текст задачи 2" ), QTask( question="Текст задачи 3" ), variance_task_factory # каждый раз, когда в вариант отбирается генератор, он генерирует для этого варианта новую задачу с уникальными значениями ] # Инициируем пул задач task_pool = QTaskPool(tasks) ``` 3. Описание структуры варианта. Для описания структуры варианта используется специальный класс `VariantFactory`. Чтобы его создать, из скольки задач будут состоять варианты, пул задач из которых подбираются задачи и (опционально) правило отбора задач. Если последнее не указать, то будет использоваться правило, которые старается минимизировать число пересечений между любыми двумя вариантами и по возможности равномерно распределить задачи. Чтобы понять, как определяется структура варианта, рассмотрим простой пример. Допустим, мы хотим сделать вариант, состоящий из трёх задач и у каждой задачи есть две вариации. ```{python} from modules.variant_builder import VariantFactory # Сначала создадим пул задач task_pool = QTaskPool([ # Задача 1 QTask( question="1.1" tags=Tag("order", "first") # Тег, чтобы отличать первую задачу от второй и третий ), QTask( question="1.2" tags=Tag("order", "first") ), # Задача 2 QTask( question="2.1" tags=Tag("order", "second") ), QTask( question="2.2" tags=Tag("order", "second") ), # Задача 3 QTask( question="3.1" tags=Tag("order", "third") ), QTask( question="3.2" tags=Tag("order", "third") ), ]) # Инициируем генератор вариантов vf = VariantFactory(number_of_tasks=3, task_pool = task_pool) # Теперь самое главное - укажем, что первая задача в варианте должна быть задачей один, вторая - задачей два, а третья - задачей три vf.task[0].must.include_tag("order", "first") # первая задача должна быть задачей с пометкой order = first vf.task[1].must.include_tag("order", "second") # вторая задача должна быть задачей с пометкой order = second vf.task[2].must.include_tag("order", "third") # первая задача должна быть задачей с пометкой order = third # доступные методы include_all_tags() - должна включать все теги из списка, include_any_tag() - должна включать хотя один тег из списка, be_one_of() - должна быть одной из задач или должна быть сгенерирована определённым генератором, not(lambda b: b.must...) - логическое отрицание, or(lambda b: b.must..., lambda b: b.must...) - логическое или. # Сгенерируем 10 вариантов: variants = vf.generate_variants(number_of_variants=10) # можем указать любое число ``` Генератор вариантов сгенерирует 10 вариантов так, чтобы они были максимально уникальны относительно друг друга. Варианты, которые составляет `VariantFactory` представлены классом `QVariant`, который есть просто собрание задач и по сути представляет собой обычный массив: ```{python} first_variant = variants[0] # первый вариант first_task_of_first_variant = first_variant[0] # первая задача первого варианта print(first_task_of_first_variant.question) # => 1.2 ```