Last active
December 24, 2015 09:08
-
-
Save jiggliemon/6774775 to your computer and use it in GitHub Desktop.
This file contains 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
(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