Как сделать тест с рандомными вопросами
Перейти к содержимому

Как сделать тест с рандомными вопросами

  • автор:

Пишем генератор тестов на Python

Пишем генератор тестов на Python

Здравствуйте!В данной статье я хотел бы показать пример программы на Python,которая генерирует билеты на основе вопросов из текстового файла.

Текстовый файл с вопросами:
Внизу на рисунке представлена Excel-форма (файл TicketTemplate.xlsx):

Python Contest Generator

Скрипт ticketgenerator.py:

import random
import openpyxl

# читает файл в список
def read2list(file):
# открываем файл в режиме чтения utf-8
file = open(file, 'r', encoding='utf-8')

# читаем все строки и удаляем переводы строк
lines = file.readlines()
lines = [line.rstrip('\n') for line in lines]

# возвращает 5 случайных вопросов
def get_questions():
answers = read2list('answers_data.txt')
items = random.choices(population=answers, k=5)
return items

# класс шаблон билета
class TicketTemplate:

def __init__(self, my_book='./TicketTemplate.xlsx'):
self.book_name = my_book
self.book = None
self.sheet = None

def open(self):
self.book = openpyxl.load_workbook(self.book_name)
self.sheet = self.book.active

def get_cell_value(self, row, column):
return self.sheet.cell(row=row, column=column).value

def set_cell_value(self, row, column, value):
self.sheet.cell(row=row, column=column).value = value

def get_rows(self):
rows = [self.get_cell_value(1, 1), self.get_cell_value(3, 1),
self.get_cell_value(4, 1), self.get_cell_value(5, 1),
self.get_cell_value(6, 1), self.get_cell_value(7, 1)
]

def set_ticket_number(self, number):
self.sheet.cell(row=1, column=1).value = 'Билет №' str(number)

def set_questions(self, questions):
for row, question in enumerate(questions):
question_number = row 1
self.set_cell_value(row 3, 1, '<0>. <1>'.format(question_number, question.strip()))

def flush(self):
self.book.save(self.book_name)

def save(self, file_name):
self.book.save(file_name)

Используется следующим образом:

from tiсketgenerator import *

tt = TicketTemplate()
tt.open()

for ticket in range(1, 31):
tt.set_ticket_number(ticket)
tt.set_questions(get_questions())
tt.save('./Билеты/Билет №<0>.xlsx'.format(ticket))

Копирование материалов разрешается только с указанием автора (Михаил Русаков) и индексируемой прямой ссылкой на сайт (http://myrusakov.ru)!

Добавляйтесь ко мне в друзья ВКонтакте: http://vk.com/myrusakov.
Если Вы хотите дать оценку мне и моей работе, то напишите её в моей группе: http://vk.com/rusakovmy.

Если Вы не хотите пропустить новые материалы на сайте,
то Вы можете подписаться на обновления: Подписаться на обновления

Если у Вас остались какие-либо вопросы, либо у Вас есть желание высказаться по поводу этой статьи, то Вы можете оставить свой комментарий внизу страницы.

Порекомендуйте эту статью друзьям:

Если Вам понравился сайт, то разместите ссылку на него (у себя на сайте, на форуме, в контакте):

Она выглядит вот так:

Комментарии ( 0 ):

Для добавления комментариев надо войти в систему.
Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.

Moodle 3.x. Случайные (тематические) вопросы в тесте

Еще одна интересная фишка Moodle 3 – создание случайных или тематических вопросов. Например, можно сделать так, чтобы из 30 вопросов теста студенту показывались только произвольные 10. Такой механизм обычно применяется в итоговом тестировании чтобы снизить вероятность списывания правильных ответов. Такой же механизм используется и для создания итогового теста, когда этот самый тест складывается из нескольких вопросов по изученным ранее темам (пройдённым ранее тестам). В этом случае нам надо создавать категории вопросов Moodle 3.

Moodle — веб-приложение, позволяющее создать кастомизированную систему управления обучением. Первые прототипы системы были созданы в 1999 году Мартином Дугиамасом (Martin Dougiamas), на тот момент студентом Университета Кертин, Австралия. Первый сайт на базе Moodle был создан в 2001 году, а сейчас число сайтов на Moodle перевалило за 1 миллион по всему миру. За это время вокруг Moodle сформировалось большое и сильное сообщество, которое разрабатывает плагины (модули) и делится ими в сети. C помощью плагинов можно создать уникальную систему управления обучением, которая по функционалу будет не хуже современных СДО. Платформа хорошо подходит как для задач образовательных учреждений, учебных центров, так и для корпоративного обучения. Но платформа требует обслуживания и настройки — от установки на хостинг, до настройки системы и обновления ее.

Рандомные вопросы в тесте

На деле на каждый вопрос — одна функция true и одна false . Это необходимо, вопрос в другом. Как сделать, чтобы выдавалось лишь, например, 8 рандомных вопроса? И соответственно сохранились бы все запросы по id , т.е. если вопрос 2 вызывал функцию false_2 и true_2 , то и должен вызывать.

Виктор's user avatar

Для каждого вопроса делаем тег div и помечаем классом question

По умолчанию класс question скрыт

Получаем массив всех вопросов и показываем случайные 6.

Дмитрий Полянин's user avatar

Предполагая, что на странице присутствует n -ное количество вопросов, а необходимо оставить случайные m из них, можно поступить следующим образом.

Сначала дожидаемся загрузки контента DOM, далее получаем список всех вопросов и скрываем n — m из них (комментарии будут в коде):

Единственное только что я здесь удаляю именно тело вопроса (сам вопрос), варианты ответов при этом остаются. Решение — обернуть каждый вопрос в отдельный тег и работать уже и ними:

Создание APP для самотестирования (Python)

На базе GUI библиотеки Tkinter

На базе GUI библиотеки Tkinter

Недавно от знакомых прилетела задачка написать программу для самотестирования. Порылся в инете, думал в лёгкую найду наработки, но ничего кроме платных и бесплатных конструкторов тестов не нашёл (может плохо искал, кто знает…). Мне показалось, что устанавливать какие-то инородные проги, а потом ещё туда все вопросы ручками забивать — совсем некрасиво. Так родилось приложение для самотестирования, написанное на Python с помощью GUI библиотеки Tkinter.

В первую очередь нужно было составить требования к структуре файла, чтобы не пришлось писать всеобъемлющий парсер на регулярках.

Я обозначил следующие требования:

Каждый вопрос должен начинаться с числа и точки (метка для идентификации вопросов)

Каждый ответ может начинаться с любого символа, но затем обязательно должна идти скобка (метка для идентификации ответов)

Правильные варианты ответа должны быть отмечены знаком «+» (метка для идентификации правильных ответов)

Вариантов ответа должно быть ровно 5:
!Если ответов меньше ПЯТИ, то их НУЖНО добить пустыми, например, если их три то добавить 4) и 5)
!Если вариантов ответа более ПЯТИ, то приложение не будет корректно работать

Ограничения по количеству ответов можно обойти, если при запуске программы попросить пользователя ввести максимальное кол-во ответов в вопросе и в автомате добивать недостающие ответы пустышками посредством алгоритмических ухищрений. Однако пока я не стал этого реализовывать, ибо не увидел великой надобности 🙂

Пример содержимого txt файла:

Пример файла с тестом

Пример файла с тестом

Напомню, что построение программы с помощью Tkinter основывается на СОП (событийно-ориентированном программировании). При таком подходе в коде явным образом выделяется главный цикл приложения, тело которого состоит из двух частей: выборки события и обработки события.

В моём случае главный цикл представляет из себя class Block, который вызывается в mainloop():

Выборки события представляют из себя интерфейс взаимодействия с пользователем, т.е. виджеты (кнопки, чекбоксы и т.п.). Обработчиками событий являются функции класса (методы), которые вызываются, когда произошло то или иное событие, например, пользователь нажал кнопку.

Для большего понимания происходящего пробежимся по алгоритму работы программы, а потом рассмотрим каждый этап в отдельности:

1. Пользователь указывает путь к txt файлу с тестом.

Окно выбора файла

Окно выбора файла

2. Производится парсинг содержимого теста, т.е. формируются список вопросов и список ответов.

3. Пользователь выбирает режим работы (Рандомный порядок вопросов vs обычный порядок).

Окно выбора режима

Окно выбора режима

4. Генерируется список с порядком вопросов.

5. «Правильные ответы» пользователь отмечает в чекбоксах.

Пользователь отметил ответы

Пользователь отметил ответы

6. Затем пользователь нажимает кнопку «Ответить». После данного события система переходит в состояние проверки, где:

Истинно-правильные ответы подсвечиваются зелёным

Изменяется статус индикатора. Если ошибок НЕТ, то индикатор примет значение «Всё верно», иначе «Есть ошибки»

Если «Всё верно», то увеличивается счётчик верных ответов на единицу

7. После того, как пользователь проанализировал свой ответ, он нажимает кнопку «Следующий». После данного события система переходит в состояние смены вопроса, где:

Счётчик вопросов увеличивается на единицу

Меняется вопрос и ответы

Статус индикатора изменяется на исходный «Выберите ответы:»

8. Когда пользователь ответил на последний вопрос и нажал «Следующий», то высвечивается кол-во правильных ответов за весь тест.

 Пользователь ответил на последний вопрос и нажал кнопку "Следующий"

Пользователь ответил на последний вопрос и нажал кнопку «Следующий»

А теперь немного поподробнее:

1. Пользователь указывает путь к txt файлу с тестом.

2. Производится парсинг содержимого теста, т.е. формируются список вопросов, список ответов и вектор меток.

Далее проходимся по ответам и создаём отдельный вектор с метками правильных ответов формата [1 0 0 0 1 0…], как раз для этого и были нужны «+» при разметке файла.

После данного шага получаем список вопросов Test_q, список ответов БЕЗ меток Test_a и вектор меток flags.

3. Пользователь выбирает режим работы (Рандомный порядок вопросов vs обычный порядок).

Здесь главным действующим лицом выступает CheckButton (Чекбокс). Если пользователь ставит в боксе галочку, то переменная RandomState примет значение 1, иначе будет равна 0.

Как только пользователь поставил галку – окно закрывается, а RandomState=1. Если же нам НЕ нужен рандомный режим, то просто можно закрыть всплывающее окно.

4. Генерируется список с порядком вопросов.

При выборе рандомного режима order_list будет вида [2 0 3 1 5 4].

5. «Правильные ответы» пользователь отмечает в чекбоксах.

Тут комментарии излишни.

6. Затем пользователь нажимает кнопку «Ответить». Система переходит в состояние проверки.

Кратко опишу структуру class Block, который вызывается в главном цикле mainloop().

Метод __inite__ выполняется единожды при создании объекта класса, т.е. в нём происходит инициализация всех объектов, создаются виджеты и все необходимые привязки событий.

Вот основные привязки:

При нажатии кнопки «Ответить» вызовется метод show_res:

Главное на что стоит обратить внимание — за индекс мы берём значение из списка order_list. Например, ели мы на втором вопросе (self.qc=1), а order_list = [2 0 3 1 5 4], то индекс будет равен 0.

При нажатии кнопки «Следующий» вызовется метод next_q. О нём в следующем пункте.

7. Пользователь нажимает кнопку «Следующий». Система переходит в состояние смены вопроса и вызывается метод next_q.

Первый важный момент:

Затем удаляем подсветку боксов и обновляем поля вопросов и ответов:

И не забываем про index!

8. Пользователь ответил на последний вопрос и нажал «Следующий» — высвечивается кол-во правильных ответов за весь тест.

С логикой работы разобрались)

Подытожим:

Были обозначены требования к структуре файлов, для их корректной обработки приложением

Рассмотрены принципы событийно-ориентированного программирования

Написан GUI на базе библиотеки Tkinter

Описана логика работы приложения

Всем успехов в написании собственных интересных и полезных APP. Делитесь ими, и кто-то обязательно их заценит 😉

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *