Created
April 29, 2015 08:07
-
-
Save classicemi/1aa5e102982d59ff036d to your computer and use it in GitHub Desktop.
hangman solver
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var fs = require('fs'), | |
request = require('request'), | |
inquirer = require('inquirer'); | |
var sessionId = '', | |
playerId = 'username', | |
options = { | |
headers: {"Connection": "close"}, | |
url: 'http://www.hangman.com/game/on', | |
method: 'POST', | |
json: true, | |
body: {} | |
}; | |
// 字典文件 | |
var dict = fs.readFileSync('words.txt', 'utf-8'); | |
// 保存所有单词的数组 | |
var wordArr = dict.split('\r\n'); | |
// 保存符合某个长度的单词 | |
var wordsMatchLength = []; | |
// 记录字母的出现频率 | |
var letterFrequency = {}; | |
// 上次猜错次数 | |
var wrongNum = 0; | |
// 记录已猜过的单词 | |
var lettersGuessed = ''; | |
// 备用字母频率列表 | |
var letterArr = | |
['E', 'T', 'A', 'O', 'I', 'N', 'S', 'H', 'R', 'D', 'L', 'U', 'C', 'M', 'F', 'W', 'Y', 'P', 'V', 'B', 'G', 'K', 'Q', 'J', 'X', 'Z']; | |
// 根据传入字符串生成对应的正则对象 | |
function generatePattern(word) { | |
var patternStr = ''; | |
var starNum = 0; | |
for (var i = 0, len = word.length; i < len; i++) { | |
if (word[i] == '*') { | |
starNum = starNum + 1; | |
} else { | |
patternStr = patternStr + (starNum ? '\\w{' + starNum + '}' : '') + word[i]; | |
starNum = 0; | |
} | |
} | |
// 修正结尾的星号 | |
patternStr = patternStr + (starNum ? '\\w{' + starNum + '}' : ''); | |
return new RegExp(patternStr, 'i'); | |
} | |
function filter(word, wrong, letter) { | |
var l = '', frequency = 0; | |
// 第一次执行时,筛选出所有符合长度条件的单词 | |
if (!wordsMatchLength.length) { | |
for (var i = 0, len = wordArr.length; i < len; i++) { | |
if (wordArr[i].length === word.length) { | |
wordsMatchLength.push(wordArr[i]); | |
} | |
} | |
} | |
// 若上次猜错,筛去所有包含上次所猜字母的单词 | |
if (wrong > wrongNum) { | |
for (var i = 0, len = wordsMatchLength.length; i < len; i++) { | |
if (wordsMatchLength[i] && | |
(wordsMatchLength[i].indexOf(letter.toLowerCase()) > -1 || wordsMatchLength[i].indexOf(letter.toUpperCase()) > -1)) { | |
wordsMatchLength.splice(i, 1); | |
i--; | |
len--; | |
} | |
} | |
// 若上次猜对,对现有模式进行正则匹配,筛选出符合条件的单词 | |
} else { | |
for (var i = 0, len = wordsMatchLength.length; i < len; i++) { | |
if (wordsMatchLength[i] && !generatePattern(word).test(wordsMatchLength[i])) { | |
wordsMatchLength.splice(i, 1); | |
i--; | |
len--; | |
} | |
} | |
} | |
// 筛选完成后,对剩下字母的频率进行统计 | |
for (var i = 0, len = wordsMatchLength.length; i < len; i++) { | |
for (var j = 0, innerLen = wordsMatchLength[i].length; j < innerLen; j++) { | |
letterFrequency[wordsMatchLength[i][j].toLowerCase()] == undefined | |
? letterFrequency[wordsMatchLength[i][j].toLowerCase()] = 1 | |
: letterFrequency[wordsMatchLength[i][j].toLowerCase()]++; | |
} | |
} | |
for (var key in letterFrequency) { | |
if (letterFrequency[key] > frequency && lettersGuessed.indexOf(key) < 0) { | |
frequency = letterFrequency[key]; | |
l = key; | |
} | |
} | |
console.log('dict remaining: ' + wordsMatchLength.length + ' words'); | |
// 若单词不在词典中,根据备用频率表进行选择 | |
if (!wordsMatchLength.length) { | |
for (var i = 0, len = letterArr.length; i < len; i++) { | |
if (lettersGuessed.indexOf(letterArr[i]) < 0) { | |
l = letterArr[i]; | |
break; | |
} | |
} | |
} | |
lettersGuessed = lettersGuessed + l; | |
wrongNum = wrong; | |
letterFrequency = {}; | |
return l; | |
} | |
function guess(word, wrongNum, letter) { | |
var letterToGuess = filter(word, wrongNum, letter); | |
options.body = { | |
"sessionId": sessionId, | |
"action": "guessWord", | |
"guess": letterToGuess.toUpperCase() | |
}; | |
request(options, function(err, res, data) { | |
if (err) { | |
console.log(err); | |
} else if(data.message) { | |
console.log(message); | |
} else { | |
console.log('your guess: ', letterToGuess.toUpperCase()); | |
console.log('current word: ', data.data.word); | |
console.log('current word count: ', data.data.totalWordCount); | |
console.log('wrong guess: ', data.data.wrongGuessCountOfCurrentWord + ' times'); | |
} | |
setTimeout(function() { | |
auto(data, letterToGuess); | |
}, 0); | |
}); | |
} | |
function auto(data, letterToGuess) { | |
if (data == 'start') { | |
options.body = { | |
"playerId": playerId, | |
"action": "startGame" | |
}; | |
request(options, function(err, res, data) { | |
if (!err && res.statusCode == 200) { | |
console.log(data) | |
console.log('game restarted,your sessionId is: ', data.sessionId); | |
sessionId = data.sessionId; | |
setTimeout(function() { | |
auto(data); | |
}, 0); | |
} else { | |
console.log(err); | |
} | |
}); | |
return; | |
} | |
// game start | |
if (data.message && data.message == 'THE GAME IS ON') { | |
sessionId = data.sessionId; | |
setTimeout(nextWord, 0); | |
return; | |
} | |
if (data.message && data.message == 'No more word to guess.') { | |
setTimeout(getResult, 0); | |
return; | |
} | |
// unfinished situation | |
if (data.data.word.indexOf('*') > -1 | |
&& data.data.wrongGuessCountOfCurrentWord < 10 | |
&& data.data.totalWordCount <= 80) { | |
setTimeout(function() { | |
guess(data.data.word, data.data.wrongGuessCountOfCurrentWord, letterToGuess); | |
}, 0); | |
} else if (data.data.word.indexOf('*') == -1 | |
|| data.data.wrongGuessCountOfCurrentWord >= 10) { // guess finished | |
// 猜词完毕后,复原辅助变量 | |
wordsMatchLength = []; | |
letterFrequency = {}; | |
wrongNum = 0; | |
lettersGuessed = ''; | |
setTimeout(nextWord, 0); | |
} else if (data.data.totalWordCount >= 80 && data.data.wrongGuessCountOfCurrentWord >= 10) { | |
setTimeout(getResult, 0); | |
} | |
} | |
function startGame() { | |
inquirer.prompt( | |
[{ | |
type: "input", | |
name: "startGame", | |
message: "please enter 'y' to automatically play the game, or enter session id to continue: " | |
}], function(answers) { | |
if (answers.startGame.toLowerCase() != 'y') { | |
sessionId = answers.startGame; | |
nextWord(); | |
return; | |
} | |
setTimeout(function() { | |
auto('start'); | |
}, 0); | |
} | |
); | |
} | |
function nextWord() { | |
options.body = { | |
"sessionId": sessionId, | |
"action": "nextWord" | |
}; | |
request(options, function(err, res, data) { | |
if (err) { | |
console.log(err); | |
} else if(data.message) { | |
console.log(data.message); | |
} else { | |
console.log('current word: ', data.data.word); | |
console.log('current word count: ', data.data.totalWordCount); | |
console.log('wrong guess: ', data.data.wrongGuessCountOfCurrentWord + ' times'); | |
index = 0; | |
} | |
auto(data); | |
}); | |
} | |
function getResult() { | |
options.body = { | |
"sessionId": sessionId, | |
"action": "getResult" | |
}; | |
function submitDicide() { | |
inquirer.prompt( | |
[{ | |
type: "input", | |
name: "submitDicision", | |
message: "enter 'y' to submit your score or enter 'n' to restart: " | |
}], function(answers) { | |
if (answers.submitDicision.toLowerCase() != 'y' && answers.submitDicision.toLowerCase() != 'n') { | |
console.log('illegal command, please reenter: '); | |
submitDicide(); | |
return; | |
} | |
switch (answers.submitDicision.toLowerCase()) { | |
case 'y': | |
submit(); | |
break; | |
case 'n': | |
startGame(); | |
break; | |
default: | |
break; | |
} | |
} | |
); | |
} | |
request(options, function(err, res, data) { | |
if (err) { | |
console.log(err); | |
} else if(data.message) { | |
console.log(message); | |
} else { | |
console.log(data); | |
console.log('current word: ', data.data.word); | |
console.log('current word count: ', data.data.totalWordCount); | |
console.log('wrong guess: ', data.data.wrongGuessCountOfCurrentWord + ' times'); | |
console.log('current score: ', data.data.score); | |
submitDicide(); | |
} | |
}); | |
} | |
function submit() { | |
options.body = { | |
"sessionId": sessionId, | |
"action": "submitResult" | |
}; | |
request(options, function(err, res, data) { | |
if (err) { | |
console.log(err); | |
} else { | |
console.log('player: ', data.data.playerId); | |
console.log('session id: ', data.data.sessionId); | |
console.log('total word count: ', data.data.totalWordCount); | |
console.log('correct word count: ', data.data.correctWordCount); | |
console.log('total wrong guess count: ', data.data.totalWrongGuessCount); | |
console.log('total score: ', data.data.score); | |
console.log('submit time: ', data.data.datetime); | |
} | |
}); | |
} | |
startGame(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment