patternjavascriptMinor
Hangman learning AI
Viewed 0 times
learninghangmanstackoverflow
Problem
I have been learning AngularJS and have written my first app. It's a Hangman AI which learns words and guesses the solution based on the words it knows.
Please look over my code and provide some pointers towards better practices, techniques and overall criticism.
Here is a CodePen demo, as the Stack Snippet may have cross-site AJAX issues.
`var app = angular.module("HangManAI", []);
app.controller('HangManController', ['$scope', '$http', function($scope, $http){
$scope.step = 0;
$scope.theWords = new Array();
$scope.wordCount = 0;
$scope.wordLetters = new Array();
$scope.myGuess = "None";
$scope.testString = "";
$scope.attempts =10;
$scope.letterFound = false;
$scope.myMouth = "G'Day. I am a hangman AI written with AngularJS. I can win a game of hangman against you if I know the words you use. Click New Game to begin.";
$scope.error = "";
var availableLetters = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"];
var knownWords = [];
//Functions
$scope.startAGame = function(){
$scope.theWords = new Array();
$scope.wordCount = 0;
$scope.attempts = 10;
$scope.error = "";
availableLetters = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"];
$scope.myMouth = "Alright! First tell me how many words there are and how many letters for each word.";
$scope.step = 1;
var req = {
method: 'GET',
url: 'http://www.hott-source.com/hangman/getMemory.php',
data: { }
}
$http(req).then(function(response){
knownWords = response.data;
$scope.testString = knownWords;
}, function(response){
$scope.error = "I could not get my memory. Try reloading the page.";
});
}
$scope.checkWords = function(){
//Loop through each typed word
var i = $scope.theWords.length;
var wordKnown = false;
var newWords = "";
var whatToSay = "";
Please look over my code and provide some pointers towards better practices, techniques and overall criticism.
Here is a CodePen demo, as the Stack Snippet may have cross-site AJAX issues.
`var app = angular.module("HangManAI", []);
app.controller('HangManController', ['$scope', '$http', function($scope, $http){
$scope.step = 0;
$scope.theWords = new Array();
$scope.wordCount = 0;
$scope.wordLetters = new Array();
$scope.myGuess = "None";
$scope.testString = "";
$scope.attempts =10;
$scope.letterFound = false;
$scope.myMouth = "G'Day. I am a hangman AI written with AngularJS. I can win a game of hangman against you if I know the words you use. Click New Game to begin.";
$scope.error = "";
var availableLetters = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"];
var knownWords = [];
//Functions
$scope.startAGame = function(){
$scope.theWords = new Array();
$scope.wordCount = 0;
$scope.attempts = 10;
$scope.error = "";
availableLetters = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"];
$scope.myMouth = "Alright! First tell me how many words there are and how many letters for each word.";
$scope.step = 1;
var req = {
method: 'GET',
url: 'http://www.hott-source.com/hangman/getMemory.php',
data: { }
}
$http(req).then(function(response){
knownWords = response.data;
$scope.testString = knownWords;
}, function(response){
$scope.error = "I could not get my memory. Try reloading the page.";
});
}
$scope.checkWords = function(){
//Loop through each typed word
var i = $scope.theWords.length;
var wordKnown = false;
var newWords = "";
var whatToSay = "";
Solution
Here are a few general feedbacks:
Have a coherent code style
You're mixing multiple code styles
-
sometimes you put braces on same line
Coherent code style improves readability, some IDEs have reformatting tools to help with this issue.
Avoid extending Javascript's classes
Prefer a function
over extending Array.prototype
Who knows what will happen in future releases of Javascript? That may break your code, or you may break another library's code.
Avoid writing initialization values at multiple places
You can extract the value in a constant, and clone it to initialize the variable.
Learn about character code and character comparison
That will probably help you simplify your algorithms. For example, you can rewrite
Some documentation can be found on MDN: charCodeAt, fromCharCode
Comment intended empty blocks
It seems like you have a bug or unfinished stuff there:
If you intend it to be empty, you can inverse the condition to avoid the else:
Or you can add a comment:
If it's unfinished code, add a TODO
Have a coherent code style
You're mixing multiple code styles
- sometimes you put spaces around operators
ng-show='step == 0', sometimes you don'tng-show='step==2'
-
sometimes you put braces on same line
$scope.checkWords = function(){, sometimes you don't$scope.nextLetter = function()
{Coherent code style improves readability, some IDEs have reformatting tools to help with this issue.
Avoid extending Javascript's classes
Prefer a function
function deleteElem(array, val) {
var index = array.indexOf(val);
if (index >= 0) array.splice(index, 1);
return array;
}over extending Array.prototype
Array.prototype.deleteElem = function(val) { /*...*/ }Who knows what will happen in future releases of Javascript? That may break your code, or you may break another library's code.
Avoid writing initialization values at multiple places
["A", "B", "C", "D", "E", "F", "G", "H" ... is a big initialization value. If it contains an error, you don't want to have to fix it at multiple places.You can extract the value in a constant, and clone it to initialize the variable.
var ALL_AVAILABLE_LETTERS = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"];
var availableLetters = ALL_AVAILABLE_LETTERS.concat(); //clone the arrayLearn about character code and character comparison
That will probably help you simplify your algorithms. For example, you can rewrite
fixLetter like this:$scope.fixLetter = function(letterIndex, wordIndex) {
var aWord = this.theWords[wordIndex].word;
var aLetter = aWord[letterIndex];
if(aLetter >= 'A' && aLetter < 'Z') {
aLetter = String.fromCharCode(aLetter.charCodeAt(0) + 1);
} else if(aLetter === 'Z') {
aLetter = 'A';
} else { //default
aLetter = 'A';
}
aWord = aWord.replaceAt(letterIndex, aLetter);
this.theWords[wordIndex].word = aWord;
}Some documentation can be found on MDN: charCodeAt, fromCharCode
Comment intended empty blocks
It seems like you have a bug or unfinished stuff there:
if(typeof knownWords[currentWord.length-1] === 'undefined')
{
}If you intend it to be empty, you can inverse the condition to avoid the else:
if(!(typeof knownWords[currentWord.length-1] === 'undefined'))
{
var innerLoop = ...
}Or you can add a comment:
if(typeof knownWords[currentWord.length-1] === 'undefined')
{
//Do nothing (on purpose)
}If it's unfinished code, add a TODO
if(typeof knownWords[currentWord.length-1] === 'undefined')
{
//TODO [Describe what you need to code here]
}Code Snippets
$scope.nextLetter = function()
{function deleteElem(array, val) {
var index = array.indexOf(val);
if (index >= 0) array.splice(index, 1);
return array;
}Array.prototype.deleteElem = function(val) { /*...*/ }var ALL_AVAILABLE_LETTERS = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"];
var availableLetters = ALL_AVAILABLE_LETTERS.concat(); //clone the array$scope.fixLetter = function(letterIndex, wordIndex) {
var aWord = this.theWords[wordIndex].word;
var aLetter = aWord[letterIndex];
if(aLetter >= 'A' && aLetter < 'Z') {
aLetter = String.fromCharCode(aLetter.charCodeAt(0) + 1);
} else if(aLetter === 'Z') {
aLetter = 'A';
} else { //default
aLetter = 'A';
}
aWord = aWord.replaceAt(letterIndex, aLetter);
this.theWords[wordIndex].word = aWord;
}Context
StackExchange Code Review Q#121742, answer score: 7
Revisions (0)
No revisions yet.