From d6eeae13236147e44567d15805d98f955c9e5302 Mon Sep 17 00:00:00 2001 From: Andrew Zhang Date: Sat, 1 Apr 2017 17:50:33 +0800 Subject: [PATCH] #18: Improve the back end algorithm by adding the position information of the word. --- server/controllers/createTrainController.js | 52 +++++------ server/controllers/tellMeController.js | 97 ++++++++++++++------- server/resource/wordList.js | 2 +- src/actions/autoPlayAction.js | 9 +- 4 files changed, 99 insertions(+), 61 deletions(-) diff --git a/server/controllers/createTrainController.js b/server/controllers/createTrainController.js index fc8248e..5cf6753 100644 --- a/server/controllers/createTrainController.js +++ b/server/controllers/createTrainController.js @@ -1,53 +1,53 @@ -import Express from 'express' -import fs from 'fs' -import mongoose, { Schema } from 'mongoose' +import Express from 'express'; +import fs from 'fs'; +import mongoose, { Schema } from 'mongoose'; -import Train from '../models/Train' +import Train from '../models/Train'; export default () => { - createTrainCollection() + createTrainCollection(); } const createTrainCollection = () => { fs.readFile('./server/resource/train.txt', 'utf8', (err, data) => { - if (err) throw err - const wordList = data.split('\n') + if (err) throw err; + const wordList = data.split('\n'); - console.log('start building train documents ') - const trainDocuments = buildTrainDocuments(wordList) - console.log('end building train documents') + console.log('start building train documents '); + const trainDocuments = buildTrainDocuments(wordList); + console.log('end building train documents'); - saveTrainDocuments(trainDocuments) + saveTrainDocuments(trainDocuments); }) -} +}; const buildTrainDocuments = (wordList) => { - const trainDocuments = {} + const trainDocuments = {}; for (let i = 0; i < wordList.length; i++) { - const word = wordList[i] - const length = word.length - trainDocuments[length] = trainDocuments[length] || [] + const word = wordList[i]; + const length = word.length; + trainDocuments[length] = trainDocuments[length] || []; //new word Schema - const wordSchema = { word } - word.split('').forEach((letter) => { - wordSchema[letter] = 1 - }) + const wordSchema = { word }; + word.split('').forEach((letter, index) => { + wordSchema[letter] = index + 1; + }); - trainDocuments[length].push(wordSchema) + trainDocuments[length].push(wordSchema); } - return trainDocuments + return trainDocuments; } const saveTrainDocuments = (trainDocuments) => { for (let key in trainDocuments) { - console.log(key + ' ' + trainDocuments[key].length) + console.log(key + ' ' + trainDocuments[key].length); const trainModel = new Train({ trainList: trainDocuments[key], wordLength: key - }) + }); trainModel.save(err => { if (err) throw err console.log('save') - }) + }); } -} +}; diff --git a/server/controllers/tellMeController.js b/server/controllers/tellMeController.js index b948345..03e36ab 100644 --- a/server/controllers/tellMeController.js +++ b/server/controllers/tellMeController.js @@ -1,8 +1,8 @@ -import Express from 'express' -import fs from 'fs' -import mongoose, { Schema } from 'mongoose' +import Express from 'express'; +import fs from 'fs'; +import mongoose, { Schema } from 'mongoose'; -import Train from '../models/Train' +import Train from '../models/Train'; /* Request: @@ -10,6 +10,7 @@ Request: "include": ["a", "b"], "exclude" : ["c", "d"], "length": 5 + "position": 1 //first letter, optional } Response: { @@ -18,54 +19,84 @@ Response: */ export default (req, res) => { - const body = req.body - const include = body.include || [] - const exclude = body.exclude || [] - const length = body.length - Train.aggregate(getAggregateQuery({ length, include, exclude }), (err, group) => { - if (err) throw err - const freObj = group[0] - let letter, max = 0 + const body = req.body; + const include = body.include || []; + const exclude = body.exclude || []; + const length = body.length; + const position = body.position || 0; + Train.aggregate(getAggregateQuery({ length, position, include, exclude }), (err, group) => { + if (err) throw err; + const freObj = group[0]; + let letter, max = 0; for (let key in freObj) { if (freObj[key] > max) { - max = freObj[key] - letter = key + max = freObj[key]; + letter = key; } - console.log(key + ': ' + freObj[key]) + console.log(key + ': ' + freObj[key]); } res.json({ - letter: letter - }) - }) + letter: letter || 'z' + }); + }); } -const getAggregateQuery = ({ length, include, exclude }) => { +const getAggregateQuery = ({ length, position, include, exclude }) => { return [ { $match: { wordLength: length } }, { $unwind: '$trainList' }, { $match: getMatchQuery({ include, exclude }) }, + { $project: getProjectQuery([...include, ...exclude], position) }, { $group: getGroupQuery([...include, ...exclude]) } - ] -} - + ]; +}; +/* + { + 'trainList.a': { $gt: 0 }, + 'trainList.b': 0 + } +*/ const getMatchQuery = ({ include, exclude }) => { return exclude.reduce((a, b) => { - a[`trainList.${b}`] = 0 - return a + a[`trainList.${b}`] = 0; + return a; }, include.reduce((a, b) => { - a[`trainList.${b}`] = 1 - return a - }, {})) -} - + a[`trainList.${b}`] = { $gt: 0 }; + return a; + }, {})); +}; +/* + { + 'trainList.a': { $gt: 0 }, + 'trainList.b': 0 + } +*/ +// depends on whether front-end has position in payload +const getProjectQuery = (ignoreArr, position) => { + const ALPHABET = 'abcdefghijklmnopqrstuvwxyz'; + return ALPHABET.split('') + .filter(c => ignoreArr.indexOf(c) < 0) + .reduce((a, b) => { + a[b] = { + $cond: position ? [{ $eq: [`$trainList.${b}`, position] }, 1, 0] : [{ $gt: [`$trainList.${b}`, position] }, 1, 0] + }; + return a + }, {}); +}; +/* + { + _id: null, + b: { $sum: '$trainList.b' } + } +*/ const getGroupQuery = (ignoreArr) => { - const ALPHABET = 'abcdefghijklmnopqrstuvwxyz' + const ALPHABET = 'abcdefghijklmnopqrstuvwxyz'; return ALPHABET.split('') .filter(c => ignoreArr.indexOf(c) < 0) .reduce((a, b) => { a[b] = { - $sum: `$trainList.${b}` + $sum: `$${b}` } return a - }, { _id: null }) -} + }, { _id: null }); +}; diff --git a/server/resource/wordList.js b/server/resource/wordList.js index ae579a4..fd1f4cf 100644 --- a/server/resource/wordList.js +++ b/server/resource/wordList.js @@ -35,7 +35,7 @@ export default [ "inform", "showtime", "believe", - "relife", + "relief", "mother", "father", "family", diff --git a/src/actions/autoPlayAction.js b/src/actions/autoPlayAction.js index 1d095a4..e4bc149 100644 --- a/src/actions/autoPlayAction.js +++ b/src/actions/autoPlayAction.js @@ -18,9 +18,16 @@ export const autoPlay = async function() { if (word.indexOf('*') < 0 || exclude.length >= numberOfGuessAllowedForEachWord) { await dispatch(nextWord(sessionId)); } else { - const letter = await guessFetch({ length: word.length, include, exclude }); + const payload = { length: word.length, include, exclude }; + // Only add position info when the number of * is less than 1/3 of the word length + if (word.length / getNumberOf(word, '*') >= 3) payload.position = word.lastIndexOf('*') + 1; + const letter = await guessFetch(payload); await dispatch(guessWord(sessionId, letter)); } } while ((totalWordCount < numberOfWordsToGuess)) }; }; + +const getNumberOf = (str, char) => { + return str.split('').filter(c => c === char).length; +}