Skip to content

Instantly share code, notes, and snippets.

@dsoverby1986
Last active February 27, 2018 03:42
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 dsoverby1986/aaecccf76375cb03ebfffbb1a759011c to your computer and use it in GitHub Desktop.
Save dsoverby1986/aaecccf76375cb03ebfffbb1a759011c to your computer and use it in GitHub Desktop.
My JavaScript/jQuery for Edford's random number crystal guessing game
/*
I've wrapped the calls to setRandomNumber() and setCrystalValues() in the window ready function so that
so that they won't be called until the page has completely loaded all elements. I am doing this to because
both of these functions work with DOM elements and I want to make sure that the elements exist before trying
to access them.
Also, have included a jQuery click event handler in the window ready function so that it's bound to the button image
elements only after they are loaded in the DOM.
*/
$(function(){
setRandomNumber();
setCrystalValues();
//Here, I am using the jQuery "starts-with" attribute selector (^=)
//This selector says, "select all elements that have an 'id' attribute with a value that starts with 'button'
//This way I am able to bind this click event hanlder to all of the elements whose 'id' attribute start with 'button':
//button1, button2, button3, button4
//Very handy since I want to have the click event handled in the same way for all of these elements
//Another way to have done this would be to add a class to all of these elements and just use the class selector:
//$('.crystal-button').click(...);
//I could also have used the 'id' attribute values for each of the elements, though it's a bit wordy:
//$('#button1, #button2, #button3, #button4').click(...);
$('[id^="button"]').click(function(){
//When any of the crystal image button elements is clicked, call the handleCrystalClick() function
//and pass to it the jQuery object returned from the selector $(this). $(this) in the scope of this click event handler
//represents the button that was clicked.
handleCrystalClick($(this));
});
});
//I've declared and initialized these variables in the global scope to make them accessible by multiple functions below
var randomNumber = 0;
var currentGuess = 0;
var wins = 0;
var losses = 0;
//The multiple functions below exist in the global scope as well, but access to these functions is initiated through
//their calling from the window ready function above, or the button click event handler above, which is contained within
//the window ready function, itself.
//Created the setRandomNumber function to adhere to DRY design, since this functionality is necessary in more than one instance
function setRandomNumber() {
randomNumber = Math.floor(Math.random() * 101) + 19;
$('#randomNumber').html(randomNumber);
}
//Created the setCrystalValues function to adhere to DRY design, since this functionality is necessary in more than one instance
function setCrystalValues() {
//Again, using the "starts-with" selector here to select all of the elements having an 'id' attribute value that starts with 'button'
var buttons = $('[id^="button"]');
//Using the jQuery .each() method, I am looping through the collection of button elements, accessing the 'data-value' attribute of
//each element (I added the 'data-value' attribute to each of these elementing in the index.html file) and assigning the random
//result of the calculation below to their 'data-value' attribute. This is just to bind the random number to its respective button
//element, so that it may be accessed later when it's needed.
$.each(buttons, function(i, button){
$('#' + button.id).data().value = Math.floor(Math.random() * 12) + 1;
});
}
//The executable code within the handleCrystalClick function below could have just as properly been a part of the buttons' click
//event handler above, but for the sake of clarity I decided to refactor it into it's own function. This is a fairly common thing
//to see with event handlers; keeping them lean and refactoring the executable logic into it's own function.
//The handleCrystalClick function takes the jQuery object passed to it from the click event handler, representing the button that
//was clicked.
function handleCrystalClick($this) {
//I am passing the representation of the clicked button to this function so that I may access it's 'data-value' attribute, as
//below, to use the value of that attribute to increment the currentGuess variable's value,
var value = $this.data().value;
currentGuess += value;
//Update the rendered currentGuess value
$('.currentGuess').html(currentGuess);
//Call the evaluate() function to check whether or not the user has won or lost at this point
evaluate();
}
//The evaluate() function is only called from one place in this codebase, and could have been included in the
//handleCrystalClick function, but I prefer to keep functions fairly lean and not bloat them with multiple
//responsibilities.
function evaluate() {
if(currentGuess === randomNumber) {
$('.wins').html(++wins);
resetCurrentGuess();
} else if (currentGuess > randomNumber) {
$('.losses').html(++losses);
resetCurrentGuess();
}
}
//The name of this function, to me, can seem a little ambiguous, since this function does more than resets the currentGuess values here
//and in the page, but, also, it makes sense to me that when the currentGuess values are reset, obviously a new random target number is
//required and, as you said about your requirements, new random number are needed for the crystal button.
function resetCurrentGuess() {
currentGuess = 0;
$('.currentGuess').html('');
setRandomNumber();
setCrystalValues();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment