Skip to content

Instantly share code, notes, and snippets.

@jiggliemon
Last active December 24, 2015 09:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jiggliemon/6774775 to your computer and use it in GitHub Desktop.
Save jiggliemon/6774775 to your computer and use it in GitHub Desktop.
(function() {
function Game() {
this.reset();
}
Game.prototype = {
reset: function reset() {
this.count = 0;
this.guesses = [];
this.answer = Math.round(Math.random() * 99 + 1);
},
isGuessValid: function isGuessValid(guess) {
/**
* It's considered best practice, and in most cases
* mandatory to add the radix param when using parseInt.
* there's different implementations of JavaScript that
* in the past would produce unusual results. For example:
* // in ECMA3
* parseInt('08') // 0
*
* The long form rule is very annoying and complicated[1]. The
* Short form is this: "Almost always supply the number 10
* as a second paramater of parseInt."
*
* If infact you do need a radix other than 10, write down
* the date and time. You just unlocked an achievment.
*/
var g = parseInt(guess); // parseInt(guess, 10)
/**
* There's no need to check if guess is a number. This is
* redundant due to parseInt returning `NaN` (Not a Number)
* if infact no-number was passed. Checking for truthiness
* will do just fine.
*/
return Boolean(guess.match(/^\s*\d+\s*$/)) && 1 <= g && g <= 100; // return g && (g > 1) && (g < 100)
},
addGuess: function addGuess(guess) {
this.guesses.push(guess);
if (this.guesses.length > 1) {
return this.guesses[this.guesses.length - 2];
} else {
return null;
}
},
makeGuess: function makeGuess(guess) {
var guessDifference = Math.abs(this.answer - guess),
prevGuessDifference = 0,
closenessFactor = 0,
previousGuess = null;
/**
* Let's not increment until after we've validated.
*/
//this.count++;
// Check guess validity
if (!this.isGuessValid(guess)) {
return [closenessFactor, "Invalid guess"];
}
/**
* Now's a great time to increment our guess count.
*/
this.count++;
closenessFactor = Math.round(Math.pow(2, ((100 - guessDifference) / 10)) / 10 );
/**
* You're kind of cheating here. `guess` is a String and `this.answer` is a Number.
* So in reality, `guess` cannot ever equal `this.answer`, the reason that it *does*
* is because JavaScript is really inconsistant with opporators. So while:
* guess == this.answer // Can be true
* guess === this.answer // Can never be true
*
* They say you should never use the "double equal" opperator[2]. I say you should always be
* aware of which comparison opperator you're using. In this case you need to either cast
* `guess` as a Number, or `this.answer` into a String; in order to get a legitimate comparison.
*/
if (guess == this.answer) { // if (guess == String(this.answer)) {
return [closenessFactor, "Correct in " + this.count + " guesses"];
}
previousGuess = this.addGuess(guess);
/**
* A good rule of thumb for functions is to only have 1-return statement.
* This does 2-things;
* 1) It makes your function easier to read. You always want to optimize what
* you write for readability.
* 2) It helps enforce consistancy on the functions return value.
* If you can eliminate type checking for your user, you've done
* a good thing. Increasing predictibility is also a good thing.
*/
if (!previousGuess) {
return [closenessFactor, (this.answer - guess > 0) ? "Too low" : "Too high"];
}
prevGuessDifference = Math.abs(this.answer - previousGuess);
if (guessDifference <= prevGuessDifference) {
return [closenessFactor, "Getting warmer"];
} else {
return [closenessFactor, "Getting colder"];
}
}
};
// UI elements
var guessResult = $('#result'),
recentGuesses = $('#recent_guesses'),
choiceInput = $('#choice'),
choiceButton = $('#go');
var game = new Game();
var gameplay = function() {
// If we are resetting the game
if (choiceButton.text() === "Reset") {
game.reset();
recentGuesses.empty();
guessResult.text('').removeClass('correct');
choiceInput.show().val('').focus();
choiceButton.text('Take a guess');
return;
}
// Check guess and add guess info to screen
var guess = choiceInput.val(),
result = game.makeGuess(guess),
closenessFactor = result[0],
text = result[1],
direction = "",
newGuess = null;
// Update guess result text
guessResult.text(text);
// Choice class for guess direction (warmer or colder
if (text === "Getting warmer") {
direction = "warmer";
} else if (text === "Getting colder") {
direction = "colder";
}
// Add valid guess to recent guesses
if (text !== "Invalid guess") {
newGuess = $('<p>'+guess+'</p>');
newGuess.addClass(direction);
recentGuesses.prepend(newGuess);
newGuess.animate({'font-size': closenessFactor+'px'});
}
// Reset choice input and give it focus
choiceInput.val('').focus();
// If the game has been won
if (text.match(/^Correct/i)) {
newGuess.removeClass().addClass('correct');
recentGuesses.html(newGuess);
choiceInput.hide();
choiceButton.text('Reset').focus();
guessResult.addClass('correct');
// Or, if needed, trim the recent guesses
} else if (recentGuesses.children().length > 4) {
$('#recent_guesses p:last-child').remove();
}
};
$(document).ready(function() {
choiceButton.click(gameplay);
choiceInput.keydown(function (e) {
if (e.keyCode == 13) {
e.preventDefault();
gameplay();
}
});
choiceInput.focus();
});
// Export game and gameplay for experimentation
window.game = game;
window.gameplay = gameplay;
}());
/**
* 1. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt
* 2. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Sameness
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment