Forum.iFiction.Ru

iFiction.Ru · ifHub · FAQ · IFWiki · QSP · URQ · INSTEAD · AXMA

форум об interactive fiction, текстовых приключенческих играх и всём таком...

Вы не зашли.

0    0    #1
05.12.2007 12:55

Flint
Участник
Зарегистрирован: 06.09.2007
Сообщений: 148

---

Универсальный spellchecker для RTADS

Людям свойственно ошибаться. При наборе, к примеру, мы частенько делаем опечатки. В этом случае текстовые процессоры подчеркивают неизвестные слова, а поисковая система 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>&laquo;<<correct>>&raquo;</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 – лучшая платформа!

Неактивен

0    0    #2
05.12.2007 14:58

GrAndrey
папа RTADS и Бяка (+49, -2)
Откуда: Москва
Зарегистрирован: 15.09.2002
Сообщений: 1198
Вебсайт

меньше слов

Re: Универсальный spellchecker для RTADS

Прикольно. Как вариант решения проблемы с выбором формы слова - проверить его на схожесть с sdesc, rdesc, vdesc....
Если совпадает - использовать подходящую форму. Правда, в них может быть существительное с прилагательным.

Неактивен

0    0    #3
05.12.2007 15:04

goraph
Участник (+647, -223)
Зарегистрирован: 16.04.2007
Сообщений: 531

Основная добродетель гражданина есть недоверие.

Re: Универсальный spellchecker для RTADS

Класс, потестировал, на первый взгляд вроде хорошо работает, думаю использовать smile
только сообщение 1014 надо както убрать, почему оно возникает не понял sad

Неактивен

0    0    #4
05.12.2007 17:02

GrAndrey
папа RTADS и Бяка (+49, -2)
Откуда: Москва
Зарегистрирован: 15.09.2002
Сообщений: 1198
Вебсайт

меньше слов

Re: Универсальный spellchecker для RTADS

Потестировал. Ощибка появляется внутри parseErrorParam при вызове parserReplaceCommand(newstr);
Почему - не знаю.
Также обнаружил мощный спойлерный потенциал spellcheckerа. Великолепно выявляет любые присутствующие в игре вещи, включая те, о которых игрок и не догадывался (и не должен был).

Неактивен

0    0    #5
05.12.2007 17:50

- VampirE -
Участник (+3)
Зарегистрирован: 22.06.2006
Сообщений: 101

Re: Универсальный spellchecker для RTADS

Почитал код.

В принципе есть что сказать по оптимизации. Во-первых, функцию определения языка ввода можно сократить до строчки, проверяя только первую букву ИМХО. Все равно ведь она ищет хотя бы одно вхождение. А люди обычно, если пишут английское слово, то пишут его полностью на английском.

Правда, я не в курсе различает ли тадс "а" нашу, от "а" латинской.

Во-вторых, все-таки длину слова лучше занести один раз в переменную и потмо получать значение. Хотя, это не так существенно.

А так очень хорошо. smile

Отредактировано - VampirE - (05.12.2007 17:51)

Неактивен

0    0    #6
05.12.2007 18:43

goraph
Участник (+647, -223)
Зарегистрирован: 16.04.2007
Сообщений: 531

Основная добродетель гражданина есть недоверие.

Re: Универсальный spellchecker для RTADS

Ошибка очень странная, единственное что нашел, это примечания к версии 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.

Неактивен

0    0    #7
05.12.2007 19:49

Nex
Участник (+120, -130)
Зарегистрирован: 11.06.2007
Сообщений: 2053

---

Re: Универсальный spellchecker для RTADS

Замечательная идея!

Неактивен

0    0    #8
05.12.2007 23:28

GrAndrey
папа RTADS и Бяка (+49, -2)
Откуда: Москва
Зарегистрирован: 15.09.2002
Сообщений: 1198
Вебсайт

меньше слов

Re: Универсальный spellchecker для RTADS

Ещё оптимизация.

Код:

    //узнаем, английский ли это текст или нет
    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: ;

легко заменяется на

Код:

    //узнаем, английский ли это текст или нет
    if (reSearch('[a-zA-Z]',word))  curlet := englet;

Проверяются все буквы до первого вхождения.

Неактивен

0    0    #9
06.12.2007 05:43

uux
Участник (+884, -80)
Откуда: Москва
Зарегистрирован: 02.12.2006
Сообщений: 1624

Re: Универсальный spellchecker для RTADS

goraph написал:

Класс, потестировал, на первый взгляд вроде хорошо работает, думаю использовать smile
только сообщение 1014 надо както убрать, почему оно возникает не понял sad

Гор, ты копал в правильном направлении: это, похоже, недоизжитый глючок TADS - видимо, Майкл Робертс не предполагал, что кто-то будет вызывать parserReplaceCommand из функции обработки ошибки;).

Есть вариант обхода: вынести спелл-чек в специально предназначенные для этого функции parseUnkownVerb,  parseUnknownDobj и parseUnknownIobj. Подробнее см. в мануале. Пример кода для parseUnkownVerb (естественно, бессовестный плагиат у Flint'а):

Код:

parseUnknownVerb: function(actor, wordlist, typelist, errornum)
{
    local correct, pos, newstr;
    
 //   if (errornum != 2)
 //       return nil;
    
    correct := spellcheck(wordlist[1]);
    if (correct)
    {
        pos := reSearch(wordlist[1], global.prevCommand);
        newstr := substr(global.prevCommand, 1, pos[1] - 1) + correct + substr(global.prevCommand, pos[1] + pos[2], length(global.prevCommand));
        
        "Возможно, вы имели в виду \(\<<<correct>>\>\).\b\b";
        parserReplaceCommand(newstr);
    }
    
    return nil;
}

В таком варианте разбираются ошибки только в глаголе, ошибка TADS-1014 не возникает (вроде бы). Для существительных, как я уже говорил, надо будет добавить функции parseUnknownXobj.

И еще чуть-чуть про оптимизацию (точнее, мелкая придирка). Если заменить строчку

"Возможно, вы имели в виду <b>&laquo;<<correct>>&raquo;</b>.<br><br>";

на

"Возможно, вы имели в виду \(\<<<correct>>\>\).\b\b";

то все будет корректно отображаться даже в том случае, если в игре отключен HTML-вывод;).

Неактивен

0    0    #10
06.12.2007 13:39

goraph
Участник (+647, -223)
Зарегистрирован: 16.04.2007
Сообщений: 531

Основная добродетель гражданина есть недоверие.

Re: Универсальный spellchecker для RTADS

uux, твой вариант ошибку 1014 конечно исправляет, но теперь при вводе просто существительного (без глаголов) возникает "стек оверфлоу" smile

Неактивен

0    0    #11
06.12.2007 13:44

Flint
Участник
Зарегистрирован: 06.09.2007
Сообщений: 148

---

Re: Универсальный spellchecker для RTADS

А нельзя ошибку просто как-нибудь заныкать? У нее же есть код.
То есть что-то вроде:

Код:

parseErrorParam: function(errornum, string, ...)
{
...

if (errornum = 1014)
    return ''; //пустая строка

}

Я так пробовал, но почему-то не заработало (наверное, потому что номер больше 100).

Отредактировано Flint (06.12.2007 13:45)

Неактивен

0    0    #12
06.12.2007 18:32

fireton
некто с бородой (+354, -92)
Откуда: Москва
Зарегистрирован: 22.08.2005
Сообщений: 1103
Вебсайт

Тон

Re: Универсальный spellchecker для RTADS

Боюсь, ошибка выдается не игровой программой, а самим проигрывателем...

Неактивен

0    0    #13
06.12.2007 19:47

uux
Участник (+884, -80)
Откуда: Москва
Зарегистрирован: 02.12.2006
Сообщений: 1624

Re: Универсальный spellchecker для RTADS

goraph написал:

uux, твой вариант ошибку 1014 конечно исправляет, но теперь при вводе просто существительного (без глаголов) возникает "стек оверфлоу" smile

Исправленная версия (измененные строки выделены зеленым):


parseUnknownVerb: function(actor, wordlist, typelist, errornum)
{
    local correct, pos, newstr;
   
   if (((typelist[1] & PRSTYP_UNKNOWN)=0) and ((typelist[1] & PRSTYP_VERB)=0))
        return nil;
   
    correct := spellcheck(wordlist[1]);
    if (correct)
    {
        pos := reSearch(wordlist[1], global.prevCommand);
        newstr := substr(global.prevCommand, 1, pos[1] - 1) + correct + substr(global.prevCommand, pos[1] + pos

[2], length(global.prevCommand));
       
        "Возможно, вы имели в виду \(\<<<correct>>\>\).\b\b";
        parserReplaceCommand(newstr);
    }
   
    return nil;
}


"Зеленое" условие означает: если первое слово не является глаголом и не является неизвестным, проверку не делаем.

UPD.: на самом деле проверка

Код:

(typelist[1] & PRSTYP_VERB)=0

избыточна - если первое слово - знакомый игре глагол, то parseUnknownVerb вообще не будет вызываться.

Отредактировано uux (07.12.2007 00:46)

Неактивен

0    0    #14
07.12.2007 14:20

goraph
Участник (+647, -223)
Зарегистрирован: 16.04.2007
Сообщений: 531

Основная добродетель гражданина есть недоверие.

Re: Универсальный spellchecker для RTADS

uux, не знаю, уж закончим ли мы когда-нибудь smile
Для глаголов твой вариант работает замечательно, но при попытке реализации parseUnknownDobj (модифицировать я пытался deepverb), возникает все та же ошибка 1014 sad

Неактивен

0    0    #15
08.12.2007 21:27

uux
Участник (+884, -80)
Откуда: Москва
Зарегистрирован: 02.12.2006
Сообщений: 1624

Re: Универсальный spellchecker для RTADS

goraph написал:

uux, не знаю, уж закончим ли мы когда-нибудь smile
Для глаголов твой вариант работает замечательно, но при попытке реализации parseUnknownDobj (модифицировать я пытался deepverb), возникает все та же ошибка 1014 sad

Гор, ты прав. Боюсь, что не закончим;). Гневное письмо Майку Робертсу буду писать (тем более, что в ходе перевода TADSовского референс-гайда и тестирования описанных в нем функций наткнулся еще на пару глючков).

Могу представить, почему так происходит: Робертс считал, что методы parseUnknownXobj должны не заменять всю команду, а сами осуществлять подбор нужного объекта в игре с использованием имеющихся слов (и, соответственно, не тестировал вызов parserReplaceCommand из них). В связи с этим к проблеме можно попытаться подойти с другой стороны.

Писать код прямо сейчас у меня возможности нет (если совсем край - пиши на форум, постараюсь в течение недели что-нибудь сделать), но могу подсказать общий план действий: после вызова спелл-чекера в parseUnknownXobj замени в исходном списке слов неправильное на правильное и выполни подбор объекта сам. Описание необходимых функций - в главе 4.2 мануала, "Более сложные технические приемы синтаксического анализа", подраздел "Обработка введенной строки непосредственно из игры". Обрати внимание на функции parseNounList, parserResolveObjects. Единственное - parseNounList глубоко параллельны специфические моменты русскозяычной обработки, так что, возможно, придется перенести туда часть обработки из preparseCmd...

Как сложно-то все это, блин;(. Кстати, использование parserReplaceCommand в preparseCmd и parseNounPhrase также вызывает нашу любимую ошибку 1014, чему вообще никакого логического объяснения подобрать нельзя... Учитесь делать меньше опечаток, господа игроки;).

Отредактировано uux (08.12.2007 21:28)

Неактивен

0    0    #16
10.12.2007 09:52

uux
Участник (+884, -80)
Откуда: Москва
Зарегистрирован: 02.12.2006
Сообщений: 1624

Re: Универсальный spellchecker для RTADS

Появилась свежая мысль, как подойти к решению проблемы совсем с другой стороны (через ж..., извиняюсь за грубость;): оставить все так, как изначально было у Flint'а (т. е. вызов спелл-чекера осуществлять в parseErrorParam), но перехватывать выводимый текст при помощи outcapture (ее описание см. в непереведенной части мануала - "Справочник по языку программирования") и безжалостно вырезать из него сообщение об ошибке. Практическое воплощение этой идеи постараюсь запостить до конца недели.

UPD: "свежая" идея не сработает;(. Сообщения о системных ошибках outcapture и outhide не перехватывают. Так что придется вернуться к варианту "А".

Отредактировано uux (10.12.2007 11:01)

Неактивен

0    0    #17
31.12.2007 15:48

uux
Участник (+884, -80)
Откуда: Москва
Зарегистрирован: 02.12.2006
Сообщений: 1624

Re: Универсальный spellchecker для RTADS

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


Код:

modify deepverb
parseUnknownDobj(actor, prep, iobj, wordlist)=
{
    local nounlist, adjlist, wordlistlen, i, pos, newstr, correct, newwordlist, newTypeList, finalobj,
          retobj, j, sublist;
    wordlistlen:=length(wordlist);
    i:=1;
    newwordlist:=[];
    while(i<=wordlistlen)
      {// Начинаем поиск неизвестных слов
       nounlist:=parserDictLookup([wordlist[i]], [PRSTYP_NOUN]);   
       adjlist:=parserDictLookup([wordlist[i]], [PRSTYP_ADJ]);
       if((nounlist=[]) and (adjlist=[]))  // Т. е. слово отсутствует в словаре
         {correct := spellcheck(wordlist[i]); // Пытаемся исправить его, используя спелл-чекер
          if(correct)
            {// Удалось; выводим сообщение спелл-чекера, заносим исправленное слово в новый список
             //pos := reSearch(wordlist[i], global.prevCommand);
             //newstr := substr(global.prevCommand, 1, pos[1] - 1) + correct + substr(global.prevCommand, pos[1] + pos[2], length(global.prevCommand));
             "\(<<wordlist[i]>>\): возможно, вы имели в виду \(\<<<correct>>\>\).\b\b";

             //parserReplaceCommand(newstr);

             newwordlist:=newwordlist+correct;
            }
          else
            {// Исправить слово не удалось; прерываем обработку
             "Я не понимаю слова \"<<wordlist[i]>>\".";
             return true;
            }
         }
       else
         {// Слово не требует исправления - заносим его в новый список без изменений
          newwordlist:=newwordlist+wordlist[i];
         }
       i:=i+1;
      }
    // Теперь начинаем подбор объектов для исправленного словосочетания
    // Сначала получаем новый список типов лексем
    newTypeList:=parserGetTokTypes(newwordlist);
    // Вызываем встроенную функцию подбора объектов для словосочетания
    finalobj:=parseNounList(newwordlist, newTypeList, 1,
                       true, true, nil);
    if(finalobj=nil)
      {// Некорректное словосочетание; сообщение об ошибке уже выведено, дальнейшей обработки не требуется
       return true;
      }
    else
      {// В противном случае возвращается список хотя бы с одним элементом
       if(length(finalobj)=1)
         {// Список состоит из одного элемента; значит, обработка завершилась неудачно. Анализируем,
          // надо ли выдавать сообщение об ошибке
          if(finalobj[1]=1)
            {// Система не выдавала сообщения об ошибке - его надо сгенерировать самостоятельно
             "Я не понимаю это предложение.";
             return true;
            }
          else
            {// Сообщение уже выдавалось - дальнейших действий не требуется
             return true;
            }
         }
       else
         {// В противном случае подбор завершился успешно - возвращаем список подобранных объектов
          i:=1;
          retobj:=[];
          while(i<=length(finalobj))
            {if(datatype(finalobj[i])=2)
               {// Переносим в возвращаемый список только объекты
        retobj:=retobj+finalobj[i];
               }
             if(datatype(finalobj[i])=7)
               {// Подчиненный список; просматриваем его на наличие объектов
                j:=1;
                sublist:=finalobj[i];
                while(j<=length(sublist))
                  {if(datatype(sublist[j])=2)
                     {retobj:=retobj+sublist[j];
                     }
                   j++;
                  }
               }
             i++;
            }
          return retobj;
         }
      }    
}
;

Описания используемых здесь функций подбора можно посмотреть в русском мануале, раздел 4.2.

Для parseUnknownIobj должно быть примерно то же самое, но если есть какая-то специфика - заняться ею я смогу только в следующем году. Еще раз прошу прощения у всех, кому этот пример нужен был значительно раньше - реально был ужасно занят.

Ну, и конечно всех с Новым годом!

Отредактировано uux (31.12.2007 15:49)

Неактивен

0    0    #18
21.01.2008 02:50

Flint
Участник
Зарегистрирован: 06.09.2007
Сообщений: 148

---

Re: Универсальный spellchecker для RTADS

И снова здравствуйте.

uux, снимаю шляпу. Я бы сам ни за что не полез в эту внутреннюю кухню парсера, потому что практически ничего в ней не понимаю, ограничиваюсь лишь самыми поверхностными слоями.

Мое молчание было обусловлено лишь нехваткой времени из-за подготовки своей игры на КРИЛ, а ни в коем случае не потерей интереса или недооценке сделанного uux-ом. Да и приходить с пустыми руками не хотелось.

Поэтому представляю вашему вниманию обновленную версию spellchecker. Я изменил лишь саму функцию spellcheck, чтобы ничего не поломать в коде uux’а.

Что нового:
- убран спойлерный потенциал, теперь спеллчекер проверяет только видимые персонажу объекты;
- теперь не проверяются слова короче 4-х букв;
- мелкие улучшения;

Прошу любить и жаловать:

Код:

spellcheck: function(word)
{
    local ruslet := 'абвгдежзиклмнопрстуфхцчшщьыъэюя';
    local englet := 'abcdefghijklmnopqrstuvwxyz';
    local curlet := ruslet;
    local i, j, k;
    
    local TYPES = [PRSTYP_NOUN PRSTYP_VERB PRSTYP_ADJ];
    local variants = [];
    local found;
    
    //Если 4 символа или короче, то не обрабатываем
    if (length(word) <= 4)
        return nil;

    //узнаем, английский ли это текст или нет    
    if ( reSearch('[a-z]', word) )
        curlet := englet;
    
    //пропущенные буквы
    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(TYPES); i++)
    {
        for (j := 1; j <= length(variants); j++)
        {
            found := parserDictLookup([] + variants[j], [] + TYPES[i]);
            for (k := 1; k <= length(found); k++)
            {
                if (TYPES[i] = PRSTYP_VERB)
                    return variants[j];
                if ( found[k].isVisible(parserGetMe()) )
                    return variants[j];
            }
        }
    }
    
    return nil;
}

Осилит дорогу идущий!

Неактивен

0    0    #19
21.01.2008 21:03

uux
Участник (+884, -80)
Откуда: Москва
Зарегистрирован: 02.12.2006
Сообщений: 1624

Re: Универсальный spellchecker для RTADS

Flint, спасибо на добром слове. Мое решение - скорее демка (косяки из него я не вылавливал). К сожалению, занятия спеллчекером мне придется отложить как минимум до февраля (так же, как участие в ifwiki.ru) - риал-лайф, сволочь, навалился... Чего говорить - в КРИЛовские игры едва успеваю играть:(

Неактивен

0    0    #20
22.01.2008 01:05

Flint
Участник
Зарегистрирован: 06.09.2007
Сообщений: 148

---

Re: Универсальный spellchecker для RTADS

Сегодня день у меня выдался продуктивный.
Первую половину дня наполнял ifwiki.ru, вторую половину вникал в дао парсера. Путем меганапряжения своего мозга я, кажется, нашел работающее решение для spellchecker.
Вместо того, чтобы идти в атаку глубже, как попробовал uux, я, наоборот, отступил и вставил проверку ЕЩЕ РАНЬШЕ – в функцию preparse. В конце-концов, невелика разница, получаем ли мы уже готовое слово (предоставляемое функцией parseErrorParam) или сами находим его в строке, введенной игроком (по флагу PRSTYP_UNKNOWN).

Поэтому описываю еще раз процесс установки:

0. (если у вас уже стоит спеллчекер)
- в функции preparse (advr.t) удалить строку “global.previousCommand := comStr;”
- в файле errorru.t удалить нафиг функции parseErrorParam и spellcheck

1. В файл errorru.t добавить следующий код:

Код:

checkString: function(str)
{
    local wordlist, typelist;
    local i;
    local correct, pos;
    
    wordlist := parserTokenize(str);
    typelist := parserGetTokTypes(wordlist);
    
    for (i := 1; i <= length(typelist); i++)
    {    
        if ((typelist[i] & PRSTYP_UNKNOWN) != 0)
        {
            correct := spellcheck(wordlist[i]);
            if (correct)
            {
                pos := reSearch(wordlist[i], lower(str));
                str := substr(str, 1, pos[1] - 1) + correct + substr(str, pos[1] + pos[2], length(str));
            
                if (systemInfo(__SYSINFO_HTML) = 1)
                      "Возможно, вы имели в виду <b>&laquo;<<correct>>&raquo;</b>.<br><br>";
                else
                      "Возможно, вы имели в виду \"<<correct>>\"\b";
            }
        }
    }
    
    return str;
}

spellcheck: function(word)
{
    local ruslet := 'абвгдежзиклмнопрстуфхцчшщьыъэюя';
    local englet := 'abcdefghijklmnopqrstuvwxyz';
    local curlet := ruslet;
    local i, j, k;
    
    local TYPES = [PRSTYP_NOUN PRSTYP_VERB PRSTYP_ADJ];
    local variants = [];
    local found;
    
    //Если 4 символа или короче, то не обрабатываем
    if (length(word) <= 4)
        return nil;

    //узнаем, английский ли это текст или нет    
    if ( reSearch('[a-z]', word) )
        curlet := englet;
    
    //пропущенные буквы
    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(TYPES); i++)
    {
        for (j := 1; j <= length(variants); j++)
        {
            found := parserDictLookup([] + variants[j], [] + TYPES[i]);
            for (k := 1; k <= length(found); k++)
            {
                if (TYPES[i] = PRSTYP_VERB)
                    return variants[j];
                if ( found[k].isVisible(parserGetMe()) )
                    return variants[j];
            }
        }
    }
    
    return nil;
}

2. В файле advr.t найдите функцию preparse и в самом конце, но перед return comStr; добавьте

Код:

comStr := checkString(comStr);

3. В файле advr.t найдите функцию preparseExt и в самом конце, но перед строками
if (comStr=str) return true;
return comStr;


добавьте

Код:

comStr := checkString(comStr);

Ура-ура, ошибок 1014 больше нет!

Я очень прошу людей, у которых есть игры на RTADS, найти 20 минут времени, добавить спеллчекер и попробовать пройти с ним собственные игры, чтобы проверить, не дает ли он паразитных наводок на процесс разбора текста и т.п.

Если ошибок не обнаружится, то можно даже будет добавить этот код в стандартную библиотеку (или лучше пусть будет отдельным модулем? ГрАнд, что думаешь?).

Всем спасибо!

Отредактировано Flint (22.01.2008 01:09)

Неактивен

0    0    #21
22.01.2008 02:14

fireton
некто с бородой (+354, -92)
Откуда: Москва
Зарегистрирован: 22.08.2005
Сообщений: 1103
Вебсайт

Тон

Re: Универсальный spellchecker для RTADS

2. В файле advr.t найдите функцию preparse и в самом конце, но перед return comStr; добавьте

Вот если б ты все это проделал с применением чудесной функции replace - от меня было б тебе большое человеческое спасибо... Так, чтобы файлик приинклюдить и все, спелчекер у тебя есть... А менять библиотеку - не слишком хорошо...

Было б клево вот что. Написать статейку на этот счет в вики и приаттачить туда файлик для инклюда (опираясь на текущую 24 версию библиотек).

Неактивен

0    0    #22
22.01.2008 11:41

goraph
Участник (+647, -223)
Зарегистрирован: 16.04.2007
Сообщений: 531

Основная добродетель гражданина есть недоверие.

Re: Универсальный spellchecker для RTADS

Есть проблемы с новым спелчекером, исправляются не все предметы, и не во всех падежах, и даже не все глаголы (например не исправляется глагол "дать") причем пока не вполне понятно по какому принципу, вот кусок лога:

 спойлер…

Когда те предметы, которые исправляются, помещаются за пределы досягаемости, их спелчекер больше не исправляет (спойлеров таким образом нет).
Факт в руках ли предмет или нет не влияет никак (питу хоть бери хоть не бери, хоть прячь, чекер ее не исправляет, а хазету исправляет).
В предыдущей версии чекера все это работало ("осм плуд" я 100% пробовал).
Кстати, как ни странно, не у всех включен хтмл, что видно из лога, себе я версию конечно сам поправлю, но вообще это надо проверять в самом чекере.
И fireton прав, лучше использовать replace.

Неактивен

0    0    #23
22.01.2008 13:29

GrAndrey
папа RTADS и Бяка (+49, -2)
Откуда: Москва
Зарегистрирован: 15.09.2002
Сообщений: 1198
Вебсайт

меньше слов

Re: Универсальный spellchecker для RTADS

Нужно сделать ограничение не на четыре, а три буквы. Три буквы заново набрать не проблема, и не будет путаницы с предлогами и сокращениями глаголов.

Неактивен

0    0    #24
22.01.2008 13:57

goraph
Участник (+647, -223)
Зарегистрирован: 16.04.2007
Сообщений: 531

Основная добродетель гражданина есть недоверие.

Re: Универсальный spellchecker для RTADS

тьфу блин, не обратил внимания что 4 буквы чекер не проверяет, сорри smile

Неактивен

0    0    #25
22.01.2008 22:41

Flint
Участник
Зарегистрирован: 06.09.2007
Сообщений: 148

---

Re: Универсальный spellchecker для RTADS

Готово.
http://ifwiki.ru/index.php/Модуль_прове … _для_RTADS

Отредактировано Flint (22.01.2008 22:43)

Неактивен

0    0    #26
23.01.2008 18:52

fireton
некто с бородой (+354, -92)
Откуда: Москва
Зарегистрирован: 22.08.2005
Сообщений: 1103
Вебсайт

Тон

Re: Универсальный spellchecker для RTADS

Flint, клево!

Неактивен

0    0    #27
04.02.2008 15:17

Gremour
Участник (+1)
Откуда: Беларусь
Зарегистрирован: 09.11.2004
Сообщений: 234

Re: Универсальный spellchecker для RTADS

>осм себя
Возможно, вы имели в виду "себе".

Это <описание персонажа>

>

Похоже, спеллчекер не совсем корректно работает с подходом ГрАнда для обработки ссылки на "себя".

Неактивен

0    0    #28
04.02.2008 16:34

GrAndrey
папа RTADS и Бяка (+49, -2)
Откуда: Москва
Зарегистрирован: 15.09.2002
Сообщений: 1198
Вебсайт

меньше слов

Re: Универсальный spellchecker для RTADS

Это был дефект основной библиотеки, в новой версии исправлено.

Неактивен

2    0    #29
22.07.2019 20:43

Nikita
Модератор (+404, -135)
Зарегистрирован: 29.10.2016
Сообщений: 139

Re: Универсальный spellchecker для RTADS

Обновлённая версия Spellchecker, адаптированная для RTADS, начиная с релиза 25, и доработанная:

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

Библиотека лежит там же на IFВики.

Неактивен

Powered by PunBB
© copyright 2001–2024 iFiction.Ru