8.1 KiB
Основные понятия
Для того чтобы составить варианты, вам сперва нужно: 1) написать все задачи/генераторы задач, 2) составить из них пул задач и 3) описать структуру варианта. Разберём по пунктам:
1.1 Задача - это основной строительный блок варианта. В QuizGen задача представляет собой класс с тремя значениями. Одно обязательные - это вопрос задачи question. И два опциональных -- ответ к задаче answer и теги tags (про которые позже)
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:
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
- Пул задач. Пул - это массив задач и генераторов задач, из которых составляются варианты.
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)
- Описание структуры варианта. Для описания структуры варианта используется специальный класс
VariantFactory. Чтобы его создать, из скольки задач будут состоять варианты, пул задач из которых подбираются задачи и (опционально) правило отбора задач. Если последнее не указать, то будет использоваться правило, которые старается минимизировать число пересечений между любыми двумя вариантами и по возможности равномерно распределить задачи.
Чтобы понять, как определяется структура варианта, рассмотрим простой пример. Допустим, мы хотим сделать вариант, состоящий из трёх задач и у каждой задачи есть две вариации.
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, который есть просто собрание задач и по сути представляет собой обычный массив:
first_variant = variants[0] # первый вариант
first_task_of_first_variant = first_variant[0] # первая задача первого варианта
print(first_task_of_first_variant.question) # => 1.2