2015-11-30 3 views
0

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

Слово банк может быть что-то вскарабкался как:

[want, eat, I, hi, to]

Тогда они создали бы свое предложение в правильном порядке:

hi I want to eat.

Я задал этот вопрос на English SO, как он первоначально относился к грамматическим вопросам - вопрос превратился в вопрос о структуре данных. Вы можете узнать больше об этом по этой ссылке. Моя оригинальная мысль о проверке грамматики предложений с использованием набора общих правил английского языка казалась такой, что она могла быстро стать слишком сложной. Было рекомендовано, чтобы я просто совпадал с использованием жестко закодированных проверок, показанных ниже.

Прежде чем я буду определять эти проверки, мне было интересно узнать, была ли лучшая структура данных/метод проверки грамматики для этой цели.

if (input === the_answer) { 
    msg = correct! 
    } else { 
    msg = 'Try again: ' + this.grammarRules(input, the_answer)); 
    } 

Language_System.prototype.grammarRules = function(input, answer) { 

    var grammar_hints = { 
    quest1 : { 
     task1 : [ 
     'The subject, Bob, needs to be first', 
     'The phrase is Hello there' 
     ] 
    } 
    }; 

    var grammar_rules = { 

    quest1 : { 
     task1 : function (input, answer) { 
     var error = -1; 
     if (input[0] !== answer[0]) { 
      error = 0; 
     } else if (input.indexOf('hello') > input.indexOf('there')) { 
      error = 1; 
     } 
     return grammar_hints.quest1.task1[error]; 
     } 
    } 

    }; 

    return grammar_rules.Lee.quest1.task1(input, answer);  

}; 

ответ

1

Было бы намного проще, если бы рассмотреть более декларативный подход: - определить стандартную quest структуры - определить стандартную task структуры с родовыми входными форматами - определить общие валидатор и повторно использовать их

Вы начали по правому пути с объектом grammar_hints, но я бы на самом деле положил все свойства, изображающие одну задачу в одном и том же объекте.

Предложение:

var quests = [ 
    { 
     name: 'Quest 1', 
     tasks: [ 
      { 
       name: 'Task 1', 
       solution: 'hi I want to eat', 
       validators: [ 
        validators.first('hi'), 
        validators.verbAfterNoun('want', 'I'), 
       ] 
      } 
     ], 
    }, 
]; 

Вы сможете повторно использовать много валидаторов в нескольких задачах, так что вы хотите, чтобы они были максимально стандартизованы, вот один пример:

var validators = { 
    first: function (input, term) { 
     if (input[0] !== term) { 
      return 'The sentence needs to start with: ' + term; 
     } 
    }, 

    verbAfterNoun: function (input, verb, noun) { 
     if (input.indexOf(verb) < input.indexOf(noun)) { 
      return 'The verb, ' + verb + ', needs to come after the noun ' + noun; 
     } 
    } 
}; 

Теперь, поскольку вы хотите иметь декларативный формат (я пошел с фактической инициализацией валидаторов с их вводом и передачей результата в массиве validators), нам понадобится фабрика валидатора, которая принимает общий валидатор и возвращает вспомогательный метод, который может быть повторно использован w с только входом.Это поможет нам вниз линии, поэтому наша система тестирования не нужно будет знать, сколько входов, чтобы перейти к каждому из валидатора обратных вызовов

// This is a factory method that applies the given callback (with the given arguments) 
function makeValidator (fn) { 
    return function inputFN() { 
     var args = [].slice.call(arguments); 
     return function validate (input) { 
      return fn.apply(null, [input].concat(args)); 
     } 
    } 
} 

// Apply the makeValidator() method on all the validators 
for (var key in validators) { 
    validators[key] = makeValidator(validators[key]); 
} 

И, наконец, мы также хотим, стандартный способ проверки наших задач на входе:

// This method provides the generic validation framework for any task given any input 
function validate (task, input) { 
    var wordList = input.split(' '); 

    if (input === task.solution) return {success: true, errors: []}; 

    var errors = []; 
    task.validators.forEach(function (fn) { 
     var error = fn(wordList); 
     if (error) errors.push(error); 
    }); 
    return {success: false, errors: errors}; 
} 

И некоторые примеры:

var task = quests[0].tasks[0]; 
console.log(validate(task, 'hi I want to eat')); 
console.log(validate(task, 'I want to eat hi')); 
console.log(validate(task, 'hi want I to eat')); 
console.log(validate(task, 'want I to eat hi')); 

Собираем все вместе:

// This is a factory method that applies the given callback (with the given arguments) 
 
function makeValidator (fn) { 
 
    return function inputFN() { 
 
     var args = [].slice.call(arguments); 
 
     return function validate (input) { 
 
      return fn.apply(null, [input].concat(args)); 
 
     } 
 
    } 
 
} 
 

 
var validators = { 
 
    first: function (input, term) { 
 
     if (input[0] !== term) { 
 
      return 'The sentence needs to start with: ' + term; 
 
     } 
 
    }, 
 

 
    verbAfterNoun: function (input, verb, noun) { 
 
     if (input.indexOf(verb) < input.indexOf(noun)) { 
 
      return 'The verb, ' + verb + ', needs to come after the noun ' + noun; 
 
     } 
 
    } 
 
}; 
 

 
// Apply the makeValidator() method on all the validators 
 
for (var key in validators) { 
 
    validators[key] = makeValidator(validators[key]); 
 
} 
 

 
var quests = [ 
 
    { 
 
     name: 'Quest 1', 
 
     tasks: [ 
 
      { 
 
       name: 'Task 1', 
 
       solution: 'hi I want to eat', 
 
       validators: [ 
 
        validators.first('hi'), 
 
        validators.verbAfterNoun('want', 'I'), 
 
       ] 
 
      } 
 
     ], 
 
    }, 
 
]; 
 

 
// This method provides the generic validation framework for any task given any input 
 
function validate (task, input) { 
 
    var wordList = input.split(' '); 
 

 
    if (input === task.solution) return {success: true, errors: []}; 
 

 
    var errors = []; 
 
    task.validators.forEach(function (fn) { 
 
     var error = fn(wordList); 
 
     if (error) errors.push(error); 
 
    }); 
 
    return {success: false, errors: errors}; 
 
} 
 

 
function printTask (input) { 
 
    var task = quests[0].tasks[0]; 
 
    var result = validate(task, input); 
 
    document.body.innerHTML += '<div><b>checking:</b> ' + input + '<pre>' + JSON.stringify(result, null, 4) + '</pre><hr />'; 
 
} 
 

 
// Lets look at some examples 
 
printTask('I want to eat hi'); 
 
printTask('hi want I to eat'); 
 
printTask('want I to eat hi'); 
 
printTask('hi I want to eat');

+1

Это является удивительным и право рядный с тем, что я искал. На самом деле, я начал делать родовые слова, передавая часть речи сразу после того, как я опубликовал LOL. Это круто! – Growler

+0

Итак, вместо инициализации каждого валидатора в 'validators' как функции я бы динамически создавал их с помощью' makeValidator'? – Growler

+0

почти все, да. это облегчает работу/понимание, если валидаторы являются функциями без состояния: они принимают все аргументы и возвращают один и тот же результат для одного и того же ввода. Помощник 'makeValidator' позволяет вам просто повторно использовать валидаторы, а также в основном жестко кодировать свои аргументы для каждого отдельного случая, но в каждом конкретном случае. Вы можете отказаться от логики 'makeValidator', выбрав другой синтаксис, например. используя имена валидатора и сделать логику аргументов в 'VALIDATE method' задачу: {валидаторов: [ [первая,«привет»], } , а затем делает аргумент сплайсинг в' validate' – Stefan

Смежные вопросы