Во второй части я показал, как js‑движок qb выводит на экран инвентарь английского вопроса и правила его построения: по зонам карточек ученик видит, из каких структур состоит вопрос и из какой зоны берётся каждый элемент. Однако вопрос в qb ученик строит от русской опоры, и тип вопроса уже задан ею: «Кто преподавал химию и физику…?» сам сообщает, что это вопрос к подлежащему. Утвердительного английского предложения, из которого вопрос получается, ученик в qb не видит, а значит, не видит и отношения между предложением и вопросом. Он не видит, к какому члену предложения ставится вопрос, что вопросительное слово замещает этот член целиком, вместе с зависимыми словами, и что остальное предложение остаётся на месте: меняется только порядок слов, а при необходимости добавляется вспомогательный глагол. Нет в qb и ответа на вопрос.
Эти два пробела закрывает js‑движок qt. В нём ученику дано английское предложение, разрезанное на карточки по членам предложения, и красным выделено то, что замещает вопросительное слово. Ученик берёт карточку целиком, меняет красное на вопросительное слово, остальные карточки ставит как есть и получает вопрос. Затем он даёт на этот вопрос краткий ответ и возвращает в нём то, что заменил вопросительным словом. Так qt закрепляет навык, которого в qb нет совсем, — навык построения кратких ответов. Краткий ответ на вопрос к подлежащему состоит из подлежащего и вспомогательного глагола, который несёт время, число и отрицание: Who examined the ships in his group carefully? — The admiral did. Ответ на вопрос к предложной группе сохраняет предлог: From the deck of whose ship…? — From the deck of his ship.
Вместе два js‑движка выводят на экран грамматику английского вопроса с двух сторон. qb показывает, из чего вопрос строится: инвентарь и правила. qt показывает, из чего вопрос получается: члены утвердительного предложения, замену члена вопросительным словом и в кратком ответе обратную замену.
Какими обходными путями ученик подменяет построение вопроса к члену предложения
Когда задание требует поставить вопрос к выделенному члену готового предложения, у ученика есть несколько способов получить вопрос, не выполняя этой замены.
Куцый вопрос. Ученик выбрасывает часть предложения и пишет What did the judge do? вместо вопроса, в котором стоят все слова предложения.
Замена не того куска. Ученик заменяет вопросительным словом одно слово и отрывает его от группы, к которой оно относится, или, наоборот, захватывает лишнее.
Подсмотренный ответ. Ученик ищет верный вопрос в самом упражнении.
Перебор вариантов. Ученик меняет вопрос наугад, пока упражнение его не примет.
Как эти пути закрыты в упражнении и какие из них остаются открытыми, видно по тому, что ученик видит на экране и что он делает.
Как устроено упражнение Question Transformer и как в нём закрыты обходные пути
Когда ученик открывает страницу Question Transformer и выбирает набор, он видит предложение, разрезанное на карточки, одна из которых выделена красным, два поля — для вопроса и для краткого ответа — и под ними четыре постоянные зоны: вопросительные слова, вспомогательные и модальные глаголы с not, местоимения по разрядам и предлоги. Вопрос ученик набирает с клавиатуры или вставляет в поле карточки предложения и карточки из зон.
Каждая карточка — член предложения со всеми зависимыми словами, и граница карточки для ученика значима: карточку он переносит в вопрос целиком. Красное — ровно те слова, которые замещает вопросительное слово. Поэтому ключ ученик может вывести с экрана: убрать красное, поставить вопросительное слово и вспомогательный глагол, а всё не красное оставить на месте и в той же форме.
По этой рамке закрыты три первых обходных пути:
куцый вопрос не принимается, потому что ключ содержит все слова предложения, а проверка требует полного совпадения с ключом;
замена не того куска не принимается, потому что вопросительное слово замещает ровно выделенное красным, а карточка неделима;
подсмотреть ответ негде: js‑движок не показывает ни верный вопрос, ни верный ответ, а Skip только откладывает задание.
Четвёртый путь, перебор вариантов, js‑движок не закрывает: каждое изменение он проверяет и сразу засчитывает совпадение, а штрафа за перебор нет.
Трудность, которую ученик не может преодолеть сам, снята подсказкой. Она лежит в спойлере, и открывает её сам ученик: в ней названы тип вопроса и формула, по которой он строится, а там, где алгоритм ученика расходится с английским, — примечание с правилом. С формулой задание сводится к подстановке, поэтому подсказка — помощь, которую ученик включает сам, так же как замедление записи в js‑движке dub из первой части.
Как предложение, поля ввода и проверка устроены в коде js‑движка qt
Всё, что ученик видит на экране и делает с карточками, реализовано в js‑движке qt. Как и qb, упражнение состоит из HTML‑страницы, XML‑наборов заданий и самого js‑движка — JS‑файла qt‑script.js, написанного с использованием jQuery, и CSS‑файла qt‑styles.css. Наборы лежат в папке qt_data/, и список, из которого ученик выбирает набор, js‑движок строит по реестру qt_data/index.json, так же как в qb.
Как составитель набора описывает предложение и вопросы к его членам в XML
Предложение задаётся один раз, а вопросов к нему столько, сколько в нём членов, к которым составитель ставит вопрос. Каждый вопрос — отдельное задание.
<sentence chunks="The admiral|examined|the ships in his group|carefully">
<q target="The admiral" qtype="subject">
<answer>Who examined the ships in his group carefully</answer>
<short>The admiral did</short>
</q>
<q target="carefully" qtype="special">
<answer>How did the admiral examine the ships in his group</answer>
<short>Carefully</short>
</q>
</sentence>
В атрибуте chunks через | перечислены карточки, то есть члены предложения со всеми зависимыми словами: in his group стоит в одной карточке с the ships, потому что относится к этому существительному. Атрибут target — слова, которые замещает вопросительное слово, <answer> — вопрос, <short> — краткий ответ; верные варианты в обоих тегах перечисляются через |. Функция readXML() превращает каждый <q> в отдельный шаг упражнения, и все шаги одного предложения получают одни и те же карточки:
$(xml).find('sentences sentence').each(function() {
var $s = $(this);
var chunks = $s.attr('chunks').split('|');
$s.children('q').each(function() {
var $q = $(this);
STEPS.push({
chunks: chunks,
target: $q.attr('target'),
chunk: $q.attr('chunk') || '',
answer: $q.children('answer').text().trim(),
short: $q.children('short').text().trim(),
qtype: ($q.attr('qtype') || '').toLowerCase()
// а также type, hint и note для подсказки
});
});
});
Красным js‑движок выделяет либо всю карточку, если target с ней совпадает, либо часть карточки, если вопрос ставится, например, к определению внутри группы. Если выделяемое слово встречается в нескольких карточках, составитель указывает нужную атрибутом chunk, и js‑движок выделяет слово только в ней.
Почему в js‑движке qt нет зоны Words и что лежит в постоянных зонах
В qb слова конкретного вопроса лежат в зоне Words. В qt эта зона не нужна: словами служат карточки самого предложения. Постоянные зоны заданы в js‑движке так же, как в qb, и от набора не зависят. Отличие одно: в зоне местоимений qt есть ещё there.
var ZONE3 = [
{label: 'subject', words: ['I','you','he','she','it','we','they']},
{label: 'object', words: ['me','him','her','us','them']},
// demonstrative, possessive, absolute possessive, reflexive
{label: 'there', words: ['there']}
];
Как ученик набирает вопрос с клавиатуры, щелчком по карточке и перетаскиванием
Из карточек предложения и зон ученик составляет вопрос в обычном текстовом поле. Щелчок по карточке или по слову из зоны вставляет его в активное поле, в то место, где стоит курсор, а пробелы вокруг вставки js‑движок расставляет сам:
function insertAtCursor(inputId, text) {
var el = document.getElementById('qt-input-' + inputId);
if (el.readOnly) return;
var start = el.selectionStart;
var end = el.selectionEnd;
var before = el.value.substring(0, start);
var after = el.value.substring(end);
var spaceBefore = (before.length > 0 && before[before.length - 1] !== ' ') ? ' ' : '';
var spaceAfter = (after.length > 0 && after[0] !== ' ') ? ' ' : '';
el.value = before + spaceBefore + text + spaceAfter + after;
// курсор встаёт за вставкой, затем запускается проверка
scheduleAutoCheck();
}
Карточку можно и перетащить в поле, а выделенный фрагмент самого поля — перетащить на другое место внутри того же поля: так ученик переставляет вспомогательный глагол или предлог, не стирая набранное.
Как js‑движок проверяет вопрос и краткий ответ в два этапа
Кнопки «Проверить» в упражнении нет. Через 400 мс после последнего изменения в поле функция doAutoCheck() сравнивает набранное со всеми вариантами ключа. Функция norm() приводит текст к нижнему регистру, отбрасывает всё, кроме букв, цифр, апострофа и пробелов, и схлопывает пробелы, поэтому ни регистр, ни знаки препинания на проверку не влияют:
function norm(s) {
return s.toLowerCase().replace(/[^a-z0-9'’\s]/g, '').replace(/’/g, "'")
.replace(/\s+/g, ' ').trim();
}
function matchesAny(studentText, answerField) {
var sNorm = norm(studentText);
var variants = answerField.split('|');
for (var i = 0; i < variants.length; i++) {
if (sNorm === norm(variants[i])) return true;
}
return false;
}
Задание проходит два этапа. На первом js‑движок сравнивает поле вопроса с <answer>. Если вопрос совпал, js‑движок ставит заглавную букву и вопросительный знак, закрывает поле для правки и переводит курсор в поле ответа. На втором этапе он сравнивает поле ответа с <short>, и только совпавший краткий ответ засчитывает задание: ответ получает точку, пара «вопрос — ответ» уходит в банк ответов, и js‑движок переходит к следующему заданию. Поэтому задание нельзя закрыть одним вопросом: краткий ответ ученик строит каждый раз. Если набранное не совпало ни с одним вариантом, js‑движок ничего не сообщает и ждёт следующего изменения.
Что показывает блок «Тип вопроса» и почему выбор типа не влияет на результат
В спойлере с подсказкой есть блок «Тип вопроса». В нём ученик может выбрать, какой вопрос он строит: к подлежащему, специальный или общий, — и получить объяснение, а при ошибке — объяснение с правилами. Тип js‑движок берёт из атрибута qtype. Выбор типа на результат не влияет: засчитывают задание только совпавшие вопрос и краткий ответ.
Как Skip сохраняет черновик обоих полей
Skip откладывает задание, и функция skipStep() сохраняет в результатах всё набранное в обоих полях и этап, на котором ученик остановился:
results[curStep] = {
status: 'skip',
// q и a — черновик для банка ответов
savedQ: $q.value,
savedA: $a.value,
savedPhase: phase
};
Функция nextStep() ищет следующее несданное задание, а дойдя до конца списка, начинает с начала. Когда отложенное задание возвращается в следующем цикле, js‑движок восстанавливает черновик: если вопрос уже был принят, ученик сразу продолжает с краткого ответа. Прогресс хранится в localStorage под составным ключом из пути страницы и имени набора, как в qb.
Общий принцип, на котором построены js‑движки e‑repa.ru
Карточки‑члены предложения в js‑движке qt выводятся из того же принципа, что зоны в qb и визуальная структура синтагмы в dub. Js‑движок переводит правила и инвентарь из абстрактно‑понятийной формы в наглядно‑действенную, и это позволяет ученику совершать конкретные действия: назначать каждому элементу функцию, его структурную роль. В qt такое действие — замена члена предложения вопросительным словом: ученик берёт карточку целиком, решает, каким вопросительным словом заменить красное и куда поставить эту карточку в вопросе, а в кратком ответе возвращает красное на место вопросительного слова.
В абстрактно‑понятийной форме этого действия не совершить: в голове ученика нет ни отдельного члена предложения, который можно взять, ни места в вопросе, куда его поставить, — грамматика построения вопроса существует там целиком и расплывчато. Наглядно‑действенная форма позволяет абстрактно‑понятийной форме:
Получить границы, то есть телесность и структурность. Член предложения становится карточкой, а граница карточки показывает, где кончается группа, которую замещает вопросительное слово: the ships in his group — одна карточка, и замещается она целиком.
Превратиться в решение. Чтобы построить вопрос, ученик каждый раз определяет, каким членом предложения служит красное и какое вопросительное слово его замещает, а чтобы построить краткий ответ — что из вопроса вернуть и нужен ли вспомогательный глагол.
Стать видимой самому ученику. Вопрос лежит в поле перед глазами рядом с карточками предложения, и ученик видит, какую карточку он заменил, какие оставил на месте и где поставил вспомогательный глагол.
Повторяться до автоматизма. К одному предложению ученик ставит вопросы ко всем выделенным членам по очереди и каждый раз даёт краткий ответ, закрепляя последовательность решений. Из внешнего действия вырастает внутреннее, и опора становится ненужной.

Комментарии 0