Simon Game -- Right-Click and select Open in New Tab.
Build a simple single-player memory game inspired by Simon. Check out this short video and Wikipedia entry to understand the rules of the game.
Provide details in your README.md of the logic you have used to build your game as well as an explanation of how you tested your logic.
I intend to use two ways to build this game:
- based on modifying the shapes of divs
- use of svg
With regards to the logic I will use jQuery and will test using jasmine.
I might use Bootstrap, but I have not made a final decision on this yet.
Version control will be taken care of by using git and GitHub.
The overall layout of the game will resemble the original physical game.
One thing that I would like to have is the ability to use different sets of
sounds and pitches. This will have the effect of creating different
tonalities and melodies, resulting in a simple form of algorithmic
melodic composition.
Colors of pads where chosen to imitate old plastic.
Remember to link to jQuery CDN.
- Once the user starts game, the board starts a list sequence
- user replicates the sequence
- If correct board adds another item to the list sequence -- Go to step 2
- If wrong an error sound and the game stops
Features:
- When a pad is played by the computer or the user, the pad lights up and a sound is emitted
- I want to be able to use different sets of sounds
- I will start with pre-recorded sounds but later I want to syntehsise the sound in real time
- I want to be able to keep track of best scores, at least for the session.
The code starts when the document is ready
- Main function of the program:
$(document).ready(function() {
});
Inside the main function I need an event listener to target the start button.
$(".start").click(function(){
level++;
doGameList();
});
This should trigger a function that will . . . .
function doGameList(){
//display the level
$(".level").text(level);
//generate random number and add it to gameList
giveMeRandomNumber();
}
I will need a few global variables that I will place at the very top of the file
userList = []; // holds the user input
gameList = []; // holds the computer randomly-generated list
var pad, level = 0, sound = 1;
// Sounds
var gameSounds = []; // I need to find some sources
// Later on I will have more than one set of sounds which can be selected by the user.
// At a later stage I will just store parameter values to create sounds in real time.
//TESTING 1
$(document).ready(function() {
var random = Math.random();
console.log(random);
console.log(random * 4);
console.log(Math.floor(random * 4));
//gives output 0, 1, 2, 3
});
//TESTING 2
var random;
var anArray = [];
$(document).ready(function() {
// build list of 10 random numbers
for (var i = 0; i < 100; i++) {
random = Math.random();
anArray.push(Math.floor(random * 4));
}
console.log(anArray);
});
//generate random number
function giveMeRandomNumber(){
var randomNum = Math.floor(Math.random() * 4);
//add generated number to the gameList array.
gameList.push(randomNum);
//Test -display last generated number in the sound display
//$(".soundSet").text(randomNum);
//console.log(gameList);
}
After testing the increments of level, the random generation of numbers and the building of the gameList Array, I need to make sure that I can change the color of the selected pad for a set time and revert back to the original color. I will also need to think about the sounds.
I need to identify the pads. I will use IDs pad1, pad2, pad3, pad4. I will add a class with a lighter color for the selected pad and remove the original class, then after a set time (use setInterval function), I will remove the lighter class and reset the original class.
The following code will turn pad one to light green and back again after 700ms.
// set lighter color class for pad
$("#pad1").addClass("lightgreen").removeClass("green");
// reset color for pad
setInterval(function() {
$("#pad1").addClass("green").removeClass("lightgreen");
}, 700); // Do this after 700ms
Now I need to dynamically select the pad depending on the last generated number.
padId = gameList[gameList.length - 1];
console.log("#pad"+padId);
I renumbered the pads to pad0, pad1, pad2, pad3. This will avoid having to do the maths in the code. I will switch case statements to select which set of classes need to be changed.
switch(gameList[gameList.length - 1]) {
case 0:
// set lighter color class for pad
$("#pad0").addClass("lightgreen").removeClass("green");
// reset color for pad
setInterval(function() {
$("#pad0").addClass("green").removeClass("lightgreen");
}, 700); // Do this after 700ms
break;
case 1:
// set lighter color class for pad
$("#pad1").addClass("lightred").removeClass("red");
// reset color for pad
setInterval(function() {
$("#pad1").addClass("red").removeClass("lightred");
}, 700); // Do this after 700ms
break;
case 2:
// set lighter color class for pad
$("#pad2").addClass("lightyellow").removeClass("yellow");
// reset color for pad
setInterval(function() {
$("#pad2").addClass("yellow").removeClass("lightyellow");
}, 700); // Do this after 700ms
break;
case 3:
// set lighter color class for pad
$("#pad3").addClass("lightblue").removeClass("blue");
// reset color for pad
setInterval(function() {
$("#pad3").addClass("blue").removeClass("lightblue");
}, 700); // Do this after 700ms
break;
default:
console.log("Nothing to do.")
}
I can replace the above switch if I can automatically extract the color which is the same as the class of the pad.
// get the color
color = $("#pad"+padId).attr("class").split(" ")[1];
console.log("#pad"+padId+" : "+color);
// set lighter color class for pad
$("#pad"+padId).addClass("light"+color).removeClass(color);
// reset color for pad
setInterval(function() {
$("#pad"+padId).addClass(color).removeClass("light"+color);
}, delayTime); // Do this after time set by delayTime.
Now I need to loop throught the array and do the above for each number stored in the gameList array.
I had a few issues with refactoring but now it is working.
I added four temporary sounds and got them to play with their respective pad.
var soundSet = [
"assets/A1.mp3",
"assets/C1.mp3",
"assets/E1.mp3",
"assets/A2.mp3"
]
function padAction(ndx, padId, color) {
. . . .
playSound(padId);
. . . .
}
function playSound(padId) {
$.playSound(soundSet[padId]);
}
Next step is to work on the user input of a sequence to match.
I need an array to hold the user's list:
var userList = [];
A listener is created in the document.ready function
// User List input
$(".pad").click(function(){
var id = $(this).attr("id").slice(3,4);
console.log(id);
userList.push(id);
console.log(userList);
userAction(id);
});
The console.log lines are for testing purposes. They will be removed later. This triggers a userAction function:
function userAction(id, color) {
color = $("#pad"+id).attr("class").split(" ")[1];
// set lighter color class for pad
$("#pad"+id).addClass("light"+color).removeClass(color);
playSound(id);
// reset color for pad
setTimeout(function() {
$("#pad"+id).addClass(color).removeClass("light"+color);
}, delayTime); // Do this after time set by delayTime.
}
Notice that the same playSound function is used. Later I will see if I can refactor the userAction function and the padAction function.
Before proceeding to making the comparison between the computer list and the user list, I want to be publish the page on GitHub Pages. I will add a link to the repository on the index page and a link to the GitHub Page at the top of this README.md.
I am trying to add target="_blank" but it does not work. I read that
I can use plain HTML but it does not seem to work either. I will revert
to markdown.
I wrote an instruction to right-click.
The following code is for testing. It uses console logs to track conditions.
function userAction(id, color) {
color = $("#pad"+id).attr("class").split(" ")[1];
// set lighter color class for pad
$("#pad"+id).addClass("light"+color).removeClass(color);
playSound(id);
// reset color for pad
if (checkForError(id)) {
setTimeout(function() {
$("#pad"+id).addClass(color).removeClass("light"+color);
}, delayTime); // Do this after time set by delayTime.
checkIfEndOfList();
} else {
console.log("ERROR: End of Game");
}
}
function checkForError(id) {
var lastUserInputNdx = userList.length - 1;
console.log(lastUserInputNdx);
if (userList[lastUserInputNdx] == gameList[lastUserInputNdx]) {
return (1>0); // return True
} else {
return (1<0); // return False
}
}
function checkIfEndOfList() {
if (userList.length == gameList.length) {
console.log("End of List: Press Start again");
} else {
console.log("Next Input");
}
}
I will next enable the code to move on to the computer adding a new pad without having to press Start.
Udated code and the final Error Display:
function checkIfEndOfList() {
if (userList.length == gameList.length) {
console.log("End of List: Press Start again");
setTimeout(function() {
level++;
doGameList();
},1000); //Delay before starting the computer List
} else {
console.log("Next Input");
}
}
function errorDisplay() {
userList = [];
gameList = [];
level=0;
$(".level").text("Err");
// All Pads Light Up
console.log("Change Collors");
$("#pad0").addClass("lightgreen").removeClass("green");
$("#pad1").addClass("lightred").removeClass("red");
$("#pad2").addClass("lightyellow").removeClass("yellow");
$("#pad3").addClass("lightblue").removeClass("blue");
console.log("Play 1 notes");
playSound(0);
setTimeout(function() {
console.log("Play 2 notes");
playSound(1);
playSound(2);
}, 500);
setTimeout(function() {
console.log("Play All notes");
playSound(0);
playSound(1);
playSound(2);
playSound(3);
}, 1500);
setTimeout(function() {
console.log("Revert the colors");
$("#pad0").addClass("green").removeClass("lightgreen");
$("#pad1").addClass("red").removeClass("lightred");
$("#pad2").addClass("yellow").removeClass("lightyellow");
$("#pad3").addClass("blue").removeClass("lightblue");
}, 2300);
}
I will clean out the console.logs. After Commit before removing console.logs, the page is not wroking on GitHub Pages. It might need some time to update. I will recommit.
I am speeding up the game when the level goes up:
function checkLevelSpeed() {
switch (true) {
case (level >= 30):
delayTime = 350;
break;
case (level >= 20):
delayTime = 400;
break;
case (level >= 15):
delayTime = 450;
break;
case (level >= 10):
delayTime = 500;
break;
case (level >= 5):
delayTime = 600;
break;
default:
delayTime = 700;
}
console.log("Delay Time: " +delayTime);
}
When levels go up the Title changes color. It applies new classes and remove the old ones. If the game is restarted, the default kicks in which will not only reset the delayTime but will also remove any color classes applied to the title.
function checkLevelSpeed() {
switch (true) {
case (level >= 30):
delayTime = 350;
break;
case (level >= 20):
delayTime = 400;
$(".title").addClass("titleColor4").removeClass("titleColor3");
break;
case (level >= 15):
delayTime = 450;
$(".title").addClass("titleColor3").removeClass("titleColor2");
break;
case (level >= 10):
delayTime = 500;
$(".title").addClass("titleColor2").removeClass("titleColor1");
break;
case (level >= 5):
delayTime = 600;
$(".title").addClass("titleColor1");
break;
default:
delayTime = 700;
$(".title").removeClass("titleColor1").removeClass("titleColor2").removeClass("titleColor3");
}
console.log("Delay Time: " +delayTime);
}
Removed all console.logs
Next is to add another set of sounds and a way to select which of the sets to use. Second set of sounds uploaded and implemented.
The use of the end button is to abort a game. It will take you straight to the end of the game and play the Error function. This button is not strictly necessary for the game because the user can easily just play a wrong pad but I wanted to implement it just the same to give an elegant way to abort even while the computer may be playing a long list of pads.
End button implemented
// End Button
$(".end").click(function() {
errorDisplay();
});
There is a bug in line 140 when called from line 58. When the End button interrupts this, there is nothing to split. I will need to do a try and catch.