2015-11-30 84 views
0

我想創建一個簡單的英語遊戲,檢查某人的句子。他們能夠使用詞庫中固定的單詞構造他們的句子。簡單的語法檢查程序 - 最佳數據結構

的詞庫可能是炒的東西,如:

hi I want to eat.

我問這個問題上English SO爲:

[want, eat, I, hi, to]

然後,他們會以正確的順序創建自己的句子它最初涉及到語法問題 - 這個問題已經演變成更多的數據結構問題。您可以在該鏈接閱讀更多關於它的內容。我最初的想法是使用一套通用的英語規則來檢查句子語法,似乎它可能會很快變得太複雜。建議我只使用硬編碼的檢查,如下所示。

在我進一步定義這些檢查之前,我想知道是否有更好的數據結構/方法來檢查語法。

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

這是真棒,右側管線與我所期待的。其實,我發佈哈哈後,我開始通過詞類通過詞類傳遞。這太棒了! – Growler

+0

因此,我不會將'validators'中的每個驗證器初始化爲函數,而是使用'makeValidator'動態創建它們? – Growler

+0

差不多,是的。它使得工作/理解驗證器是否爲無狀態函數更容易:它們接受所有參數併爲相同輸入返回相同的結果。 'makeValidator'助手只是允許你輕鬆地重用驗證器,同時也基本上將它們的參數硬編碼到每個個案中,但是在個案的基礎上。 您可以通過選擇不同的語法來放棄'makeValidator'邏輯,例如使用驗證器的名字,做論證邏輯在'驗證method' 任務:{驗證:[ [第一,「喜」], } ,然後做在'validate' – Stefan