This is a game of Simon using plain Javascript. I would welcome any comments, suggestions,
insights or ideas for improvement. One choice that I made was to have the player's turn
compare values against a game array ( simonSays
) by using the increment
variable.
If there is a better way to do this I would be very interested. This program also makes extensive use of the
setTimeout
function, if there are other ways to achieve this effect I would also be
very interested.
Also when I was refactoring and trying to cut unnecessary code I was unable to re-use the call
to the mute(color)
function from the playSound(soundValue, i)
and was forced to
use a separate function, changeColorOff(i)
in this one place. I left the commented code
in to show what I tried. I am not clear why this was necessary. Any insights would be appreciated.
The working game is on CodePen.
var $game = document.getElementById('game');
var $sound = document.getElementById('sound');
var $display = document.getElementById('display');
var $displayText = document.getElementById('displayText');
var youWin = null, winnerText = null;
var $yellow = document.getElementById("yellow");
var $red = document.getElementById("red");
var $green = document.getElementById("green");
var $blue = document.getElementById("blue");
var $gameOnBtn = document.getElementById('gameOnBtn');
var $startBtn = document.getElementById('startBtn');
var $strictModeBtn = document.getElementById('strictModeBtn');
var powerSound = "http://soundbible.com/grab.php?id=19&type=mp3";
var redSound = " https://s3.amazonaws.com/freecodecamp/simonSound2.mp3";
var blueSound = "https://s3.amazonaws.com/freecodecamp/simonSound4.mp3";
var greenSound = "https://s3.amazonaws.com/freecodecamp/simonSound1.mp3";
var yellowSound = "https://s3.amazonaws.com/freecodecamp/simonSound3.mp3";
var wrongAnsSound = "http://soundbible.com/grab.php?id=1501&type=mp3";
var clickSound = "http://soundbible.com/grab.php?id=1705&type=mp3";
var victorySound = "http://soundbible.com/grab.php?id=1947&type=mp3";
var powerOn = false;
var gameInPlay = false;
var strictMode = false;
var victory = false;
var buttonTimeInterval = 1000;
var simonSays = [];
var currentValue = null;
var increment = 0;
var soundOptions = {
0: yellowSound,
1: redSound,
2: greenSound,
3: blueSound
};
var colorOptions = {
0: $yellow,
1: $red,
2: $green,
3: $blue
};
function flash(color){
color.style.opacity = 1;
}
function mute(color){
color.style.opacity = 0.6;
}
function flashBoard(i, l){
if (i == l) return;
setTimeout("flash($yellow)", 500);
setTimeout("flash($red)", 500);
setTimeout("flash($green)", 500);
setTimeout("flash($blue)", 500);
setTimeout("mute($yellow)", 750);
setTimeout("mute($red)", 750);
setTimeout("mute($green)", 750);
setTimeout("mute($blue)", 750);
i += 1;
setTimeout("flashBoard(" + i + "," + l + ")", 500);
}
function gameReset(){
flashBoard(0, 3);
justSound(powerSound);
$displayText.textContent = '-- --';
}
function powerOnGame(){
if (!powerOn){
$gameOnBtn.style.fill = "rgb(250, 0, 20)";
powerOn = true;
gameReset();
} else {
gameOff();
}
}
function startGame(){
if (!powerOn){
return;
}
justSound(clickSound);
if (!gameInPlay){
$startBtn.style.fill = "rgb(20, 200, 50)";
} else {
$startBtn.style.fill = "rgb(0, 0, 0)"
setTimeout(function(){ return $startBtn.style.fill = "rgb(20, 200, 50)";}, 200);
}
resetDisplay();
buttonTimeInterval = 1100;
simonSays = [];
playGame();
}
function useStrictMode(){
if (!powerOn){
return;
}
justSound(clickSound);
if (!strictMode){
$strictModeBtn.style.fill = "rgb(250, 250, 250)";
strictMode = true;
} else {
$strictModeBtn.style.fill = "rgb(0, 0, 0)";
strictMode = false;
}
}
//general button handler that take values from color buttons
function colorPress(colorNum){
if (!powerOn){
return;
}
var colorNo = colorNum; //not sure why this was needed but it was...
if (currentValue !== colorNum){
setTimeout(function(){fail()}, 500);
} else {
increment += 1;
currentValue = simonSays[increment];
}
flash(colorOptions[colorNum]);
setTimeout(function(colorNo){
justSound(soundOptions[colorNum]);
mute(colorOptions[colorNum]);
}, 100);
if (increment === simonSays.length){
setTimeout(function(){playGame()}, 1000);
}
}
function pressYellow(){
colorPress(0);
}
function pressRed(){
colorPress(1);
}
function pressGreen(){
colorPress(2);
}
function pressBlue(){
colorPress(3);
}
function justSound(soundValue){
$sound.src = soundValue;
$sound.load();
$sound.play();
}
//this is the computer's sound function, incorporates the general sound function and an end to the color flash
//not sure why muteColor does not work...
function playSound(soundValue, i){
justSound(soundValue);
// var muteColor = colorOptions[simonSays[i]];
// setTimeout('mute(' + muteColor + ')', buttonTimeInterval - 300);
setTimeout('changeColorOff('+ i + ')', buttonTimeInterval - 200);
}
function changeColorOff(i){
colorOptions[simonSays[i]].style.opacity = 0.6;
}
function displayProgress(arrLen){
$displayText.setAttribute('font-size', '50');
$displayText.textContent = arrLen;
if (arrLen < 10){
$displayText.setAttribute('x', '227');
} else {
$displayText.setAttribute('x', '213');
}
}
//iterates through the computer's moves
function startPlaying(i, l){
if (i == l) return;
increment = 0;
currentValue = simonSays[0];
var callSound = soundOptions[simonSays[i]];
playSound(callSound, i);
var flashColor = colorOptions[simonSays[i]];
flash(flashColor);
i += 1;
setTimeout("startPlaying("+ i + ", " + l + ")", buttonTimeInterval);
};
function playGame(){
gameInPlay = true;
victory = false;
if (simonSays.length === 20){
return gameVictory();
}
var simonMove = Math.floor(Math.random() * 4);
simonSays.push(simonMove);
startPlaying(0, simonSays.length);
var simonProgress = simonSays.length;
if ((simonProgress === 5) || (simonProgress === 9) ){
buttonTimeInterval -= 250;
}
if (simonProgress === 15){
buttonTimeInterval -= 100;
}
displayProgress(simonProgress);
}
function fail(){
justSound(wrongAnsSound);
$display.setAttribute("fill", "rgb(200, 0, 0)");
setTimeout(function(){$display.setAttribute("fill", "rgb(70, 70, 70)");
}, 1500);
if (strictMode){
simonSays = [];
setTimeout(function(){playGame()}, 2000);
} else {
setTimeout(function(){startPlaying(0, simonSays.length)}, 2000);
}
}
function gameVictory(){
flashBoard(0, 3);
justSound(victorySound);
victory = true;
$display.setAttribute('fill', 'rgb(5, 17, 142)');
$displayText.setAttribute('fill', 'rgb(250, 250, 250)');
$displayText.textContent = "Win!";
$displayText.setAttribute('font-size', '20');
winnerText = document.createElementNS("http://www.w3.org/2000/svg", 'text');
winnerText.setAttribute('x', '220');
winnerText.setAttribute('y', '290');
winnerText.setAttribute('fill', 'rgb(250, 250, 250)');
winnerText.setAttribute('font-size', '20');
youWin = document.createTextNode("You");
winnerText.appendChild(youWin);
$game.appendChild(winnerText);
}
function resetDisplay(){
$display.setAttribute('fill', 'rgb(70, 70, 70)');
$displayText.setAttribute('fill', 'rgb(0, 0, 0)');
if (victory){
winnerText.parentNode.removeChild(winnerText);
}
gameInPlay = true;
}
function gameOff(){
justSound(clickSound);
resetDisplay();
$displayText.textContent = "Off";
$displayText.setAttribute('font-size', '20');
$gameOnBtn.style.fill = "rgb(0, 0, 0)";
$strictModeBtn.style.fill = "rgb(0, 0, 0)";
$startBtn.style.fill = "rgb(0, 0, 0)";
simonSays = [];
victory = false;
gameInPlay = false;
strictMode = false;
powerOn = false;
}
window.onload = gameOff();
body {
background-color: rgb(145, 163, 193);
}
#gameShell {
position: absolute;
top: 75px;
margin: auto;
width: 100%;
}
#inner {
margin: auto;
width: 70%;
text-align: center;
}
#yellow {
opacity: 0.5;
}
#red {
opacity: 0.5;
}
#green {
opacity: 0.5;
}
#blue {
opacity: 0.5;
}
<!doctype html>
<html>
<head>
<title>Draft 1 Simon Shell</title>
<link rel="stylesheet" href="styles.css" >
</head>
<body>
<audio id="sound"></audio>
<div id="gameShell" >
<div id="inner">
<svg id="game" width="600" height="600" viewBox="0 0 600 600">
<circle cx="300" cy="300" r="270" fill="black" />
<path id="yellow" d="M300 50 A250 250, 0, 0,1, 550 300
L 300 300 Z" stroke="black" stroke-width="9" fill="yellow"
onClick="pressYellow()" />
<path id="red" d="M550 300 A250 250, 0, 0,1, 300 550
L 300 300 Z" stroke="black" stroke-width="9" fill="red"
onClick="pressRed()" />
<path id="green" d="M300 550 A250 250, 0, 0,1, 50 300
L 300 300 Z" stroke="black" stroke-width="9" fill="green"
onClick="pressGreen()" />
<path id="blue" d="M50 300 A250 250, 0, 0,1, 300 50
L 300 300 Z" stroke="black" stroke-width="9" fill="blue"
onClick="pressBlue()" />
<circle id="innerBackground" cx="300" cy="300" r="120" fill="rgb(244, 244, 20)" stroke="black" stroke-width-"15" />
<text x="255" y="235" font-family="arial" font-size="30" font-weight="bold" >Simon</text>
<text x="290" y="320" font-family="arial" font-size="20" >Start</text>
<text x="350" y="320" font-family="arial" font-size="20" >Strict</text>
<text x="270" y="395" font-family="arial" font-size="20" >On/Off</text>
<circle id="startBtn" cx="315" cy="285" r="10" fill="black" stroke="black" stroke-width="5"
onClick="startGame()" />
<circle id="strictModeBtn" cx="375" cy="285" r="10" fill="black" stroke="black" stroke-width="5"
onClick="useStrictMode()" />
<circle id="gameOnBtn" cx="300" cy="360" r="10" fill="black"
stroke-width="5"stroke="black" onClick="powerOnGame()" />
<rect id="display" x="205" y="260" rx="10" ry="20" width="70" height="70" fill="rgb(70, 70, 70)" stroke="black" />
<text id="displayText" x='225' y='310' font-size='20' >Off</text>
</svg>
</div>
</div>
<h1>Simon</h1>
<script src="logic.js" ></script>
</body>
</html>