Людям свойственно ошибаться. При наборе, к примеру, мы частенько делаем опечатки. В этом случае текстовые процессоры подчеркивают неизвестные слова, а поисковая система Google предлагает вариант исправления для неправильного слова.
Интерфейс всех парсерных игр основан на вводе текста, причем количество введенного игроком текста за всю игру может быть весьма существенным. Естественно, не обходится без ошибок. «К сожалению, слово "деференциал" мне неизвестно.» Довольно странным выглядит то, что эта проблема никак не решается в этой абсолютно текстовой среде, где, вроде бы, сам бог велел (а ведь сейчас проверку орфографии встраивают даже в браузеры), тем более, что никаких словарей для проверки таскать за собой не надо – словарь, вот ведь он, заботливо объявленный автором в самой игре!
Поэтому я решил написать нечто вроде spellchecker для RTADS.
Он исправляет опечатки следующих типов:
1) пропустили букву
>о холдильник
2) набрали лишнюю букву
>о холодлильник
3) перепутали буквы местами (частенько случается при наборе)
>о холдоильник
4) ошиблись в букве
>о халодильник
После того, как вы нажмете Энтер, на экране, вместо раздражающего«К сожалению, слово "халодильник" мне неизвестно.»
вы увидитеВозможно, вы имели в виду «холодильник».
Высокий белый холодильник. На боковую стенку налеплен магнит в виде головы панды (довольно дурацкий, верно?).
Мой spellchecker исправляет только одну ошибку на слово (т.е. «халодильник» он исправит, а «халадильник» уже нет). Это связано с объемом вычислений. Для слова из 7 букв выполняется 478 проверок на одну ошибку, соответственно, для проверки на 2 ошибки необходимо производить 478^2 = 228484 проверок, что конкретно затормаживает игру. К тому же, по статистике Google, из всех ошибок при вводе ошибки в одну букву составляют более 90% случаев, так что большинство опечаток мой spellchecker исправит.
Спелчекер универсален – он использует активный словарь текущей игры, обеспечивая тем самым 100% релевантность исправлений и минимум ложных срабатываний :-).
Чтобы подключить spellchecker к вашей игре на RTADS, сделайте следующее (процесс описан для файлов 24 релиза библиотек, но, скорее всего, заработает и на более ранних):
1. Откройте файл advr.t, найдите там функцию preparse и в самый ее конец, но перед “return comStr;” воткнитеglobal.prevCommand := comStr;
2. Откройте файл erroru.t и в самый конец файла добавьтеparseErrorParam: function(errornum, string, ...)
{
local correct, pos, newstr;
if (errornum != 2)
return parseError(errornum, string);
correct := spellcheck(getarg(3));
if (correct)
{
pos := reSearch(getarg(3), global.prevCommand);
newstr := substr(global.prevCommand, 1, pos[1] - 1) + correct + substr(global.prevCommand, pos[1] + pos[2], length(global.prevCommand));
"Возможно, вы имели в виду <b>«<<correct>>»</b>.<br><br>";
parserReplaceCommand(newstr);
}
return parseError(errornum, string);
}
spellcheck: function(word)
{
local ruslet := 'абвгдежзиклмнопрстуфхцчшщьыъэюя';
local englet := 'abcdefghijklmnopqrstuvwxyz';
local curlet := ruslet;
local i, j;
local variants = [];
local found;
//узнаем, английский ли это текст или нет
for (i := 1; i <= length(word); i++)
{
for (j := 1; j <= length(englet); j++)
{
if (substr(word, i, 1) = substr(englet, j, 1))
{
curlet := englet;
goto next;
}
}
}
next: ;
//пропущенные буквы
for (i := 1; i <= length(curlet); i++)
{
for (j := 0; j <= length(word); j++)
{
variants += substr(word, 1, j) + substr(curlet, i, 1) + substr(word, j + 1, length(word));
}
}
//лишние буквы
for (i := 0; i < length(word); i++)
{
variants += substr(word, 1, i) + substr(word, i + 2, length(word));
}
//неправильные буквы
for (i := 1; i <= length(curlet); i++)
{
for (j := 0; j < length(word); j++)
{
variants += substr(word, 1, j) + substr(curlet, i, 1) + substr(word, j + 2, length(word));
}
}
//перепутанные местами буквы
for (i := 0; i < length(word) - 1; i++)
{
variants += substr(word, 1, i) + substr(word, i + 2, 1) + substr(word, i + 1, 1) + substr(word, i + 3, length(word));
}
for (i := 1; i <= length(variants); i++)
{
found := parserDictLookup([] + variants[i], [PRSTYP_NOUN]);
if ( length(found) > 0)
return variants[i];
}
for (i := 1; i <= length(variants); i++)
{
found := parserDictLookup([] + variants[i], [PRSTYP_VERB]);
if ( length(found) > 0)
return variants[i];
}
for (i := 1; i <= length(variants); i++)
{
found := parserDictLookup([] + variants[i], [PRSTYP_ADJ]);
if ( length(found) > 0)
return variants[i];
}
return nil;
}
Все! Компилируйте игру и можете пробовать.
Из недостатков спелчекера стоит отметить то, что он не занимается подбором форм слов, поэтому возможно неграмотное с точки зрения русского языка исправление написания, например «осмотреть сантехникв» (хотели написать «осмотреть сантехника») будет исправлено на «осмотреть сантехник». К сожалению, это никак не исправить.
Просьба протестировать работу на имеющихся у вас проектах RTADS. Пожелания и предложения приветствуются.
И напоследок, может кто-нибудь знает, как убрать вывод сообщения [TADS-1014: 'abort' statement executed] при каждом вызове функции parserReplaceCommand?
RTADS – лучшая платформа!
Неактивен
Класс, потестировал, на первый взгляд вроде хорошо работает, думаю использовать
только сообщение 1014 надо както убрать, почему оно возникает не понял
Неактивен
Ошибка очень странная, единственное что нашел, это примечания к версии 2.5.2 в tads revision history:
If the preparse() or preparseCmd() functions executed an exit, exitobj, or abort, the interpreter displayed an error message (such as "'abort' statement executed"). This was mostly harmless; these types of statements are generally not needed within preparse() and preparseCmd(), because these functions use return codes rather than exit and the like to control further processing. However, certain built-in functions perform abort operations implicitly; in particular, the parserReplaceCommand() function uses abort to start processing the new command immediately. To enable the use of such built-ins in preparse() and preparseCmd(), the interpreter no longer displays an error message when exit, exitobj, or abort are used in these user functions.
Однако из примечаний, насколько я понял, следует, что данного сообщения наоборот не должно появляться начиная с версии 2.5.2.
Неактивен
uux, твой вариант ошибку 1014 конечно исправляет, но теперь при вводе просто существительного (без глаголов) возникает "стек оверфлоу"
Неактивен
uux, не знаю, уж закончим ли мы когда-нибудь
Для глаголов твой вариант работает замечательно, но при попытке реализации parseUnknownDobj (модифицировать я пытался deepverb), возникает все та же ошибка 1014
Неактивен
Есть проблемы с новым спелчекером, исправляются не все предметы, и не во всех падежах, и даже не все глаголы (например не исправляется глагол "дать") причем пока не вполне понятно по какому принципу, вот кусок лога:
спойлер…
Когда те предметы, которые исправляются, помещаются за пределы досягаемости, их спелчекер больше не исправляет (спойлеров таким образом нет).
Факт в руках ли предмет или нет не влияет никак (питу хоть бери хоть не бери, хоть прячь, чекер ее не исправляет, а хазету исправляет).
В предыдущей версии чекера все это работало ("осм плуд" я 100% пробовал).
Кстати, как ни странно, не у всех включен хтмл, что видно из лога, себе я версию конечно сам поправлю, но вообще это надо проверять в самом чекере.
И fireton прав, лучше использовать replace.
Неактивен
тьфу блин, не обратил внимания что 4 буквы чекер не проверяет, сорри
Неактивен