5
\$\begingroup\$

I programmed a web adaption of the game Simon for to improving my JavaScript skills. A live version of the results are here.

I got two more ideas which I like to incorporate. Moreover, I'd like to improve the look. But before I go on I would like to make some improvements. I guess there are a few necessary.

function SimonSays( timeLapse,
	                elements,
	                cssClass,
	                messageBoard,
	                display,
                  breakTime,
                  board) {
  var order = [];

  if (!Array.isArray(elements)) {
    // Change nodeList into an real array.
	  elements = Array.prototype.slice.apply(elements);
  }

  // Every round the count 
  //  of the moves is incremented.
  var moves = (function() {
    var moves = 1;

    return function() {
      return moves++;
    }
  })();
   
  var getRounds = (function() {
    var rounds = 1;

    return function() {
      return rounds++;
    }
  })();

  var incrementDisplay = function() {
    var tmp = '000' + getRounds();

    display.innerHTML = tmp.slice(-3);  
  }

  var reactToMove = function() {
    this.classList.add(cssClass);
    var that = this;

    setTimeout(function() {
      that.classList.remove(cssClass);
    }, timeLapse);

    var currentFirst = elements[order.shift()].id;

    if (currentFirst !== this.id) {
      SimonSays.prototype.toggleReact();
      messageBoard.style['display'] = 'block';
    } else if (!order.length) {
      setTimeout(SimonSays.prototype.setUpRound, breakTime);
    }
  }

  SimonSays.prototype.toggleReact = function(direction) {
      
      elements.forEach(function(element) {
        direction === true ?
          element.addEventListener('click', reactToMove) :
          element.removeEventListener('click', reactToMove);
	  });	

  }

  SimonSays.prototype.setUpRound = function() {
    var limit = moves();

    order.length = 0;
    // Update GUI-counter.
    incrementDisplay();

    // Put random numbers into an array. => 
    //   Order of blicking buttons.
    for (var i = 0; i < limit; i++) {
      order.push(Math.floor(Math.random() * 4));
    }
    // Prevent click on the game-board.
    document.body.style['pointer-events'] = 'none';
    var times;

    order.forEach(function(number, i) {
      var tmp = number;
      var step = 2 * +i;
      times = i;
        
      setTimeout(function() {
        elements[tmp].classList.add(cssClass);          	
      }, timeLapse * step)
        

      setTimeout(function() {
          elements[tmp].classList.remove(cssClass);          
        }, timeLapse * (step + 1) );
    });
    // Re-enable clicking on the game-board.
    setTimeout(function() {
      document.body.style['pointer-events'] = 'auto';
    }, (timeLapse * times) + timeLapse); 
  }	
}

window.addEventListener('load', function() {
	var buttons 
    = document.querySelectorAll('.play-button');

	var start
    = document.querySelector('#start-game');

	var reset
    = document.querySelector('#reset-game');

	var display
    = document.querySelector('#rounds-display');

	var gameOverMessage
    = document.querySelector('#game-over');

  var board
    = document.querySelector('#board');

  var game = new SimonSays( 500, 
                            buttons,
                            'active-button',
                            gameOverMessage,
                            display,
                            2000,
                            board );

	reset.addEventListener('click', function() {
		location.reload(true);
	});
   
  start.addEventListener('click', function() {
    game.setUpRound();  
    start.setAttribute('disabled', 'disabled'); 
    document.body.style['cursor'] = 'pointer';

    game.toggleReact(true);
  });	
})
html {
    color: #222;
    font-size: 1em;
    line-height: 1.4;
    background-color: rgba(230, 230, 230, 1.0);
}

#wrap {
    width: 1000px;
    margin: 50px auto;
}

.label-element-group {
    display: flex;
    align-items: center;
    width: 160px;
    justify-content: space-around;
}

.display {
    height: 24px;
    width: 75px;
    background-color: rgba(150, 150, 150, 1.0);
    border-radius: 12px;
    border: 1px solid rgba(200, 200, 200, 0.1);
    box-shadow: inset 3px 3px 1px rgba(100, 100, 100, 0.9);
    font-size: 1.2em;
    text-align: center;
    color: rgba(240, 240, 240, 1.0);
    display: inline-block;
}

nav {
    display: flex;
    width: 420px;
    height: 50px;
    justify-content: space-around;
    align-items: center;
    margin: 0 auto 15px;
}

nav button {
    font-size: 1em;
    border-radius: 16px;
}

#board {
    width: 420px;
    height: 420px;
    margin: 0 auto;
    display: flex;
    background-color: rgba(100, 100, 100, 0.6);
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-around;
    border-radius: 16px;
    border: 2px solid black;
    position: relative;
}

.message {
    width: 320px;
    height: 80px;
    background-color: rgba(100, 100, 100, 1.0);
    color: rgba(240, 240, 240, 1.0);
    text-align: center;
    font-size: 3em;
    line-height: 80px;
    border-radius: 16px;
    position: absolute;
    top: 140px;
    left: 55px;
    border: 3px solid rgba(240, 240, 240, 1.0);
    transform: rotate(-7deg);
    box-shadow: 8px 8px 16px rgba(15, 15, 15, 1.0);
    display: none;
}


.play-button {
    width: 200px;
    height: 200px;
    border: 2px solid black;
}

#green {
    background-color: rgba(0, 240, 0, 0.5);
    border-top-left-radius: 100%;
}

#red {
    background-color: rgba(240, 0, 0, 0.5);
    border-top-right-radius: 100%;
}

#blue {
    background-color: rgba(0, 0, 240, 0.6);
    border-bottom-right-radius: 100%;
}

#yellow {
    background-color: rgba(240, 240, 0, 0.5);
    border-bottom-left-radius: 100%;
}

.active-button {
    background-color: rgba(250, 250, 250, 1.0) !important;
}
<!doctype html>
    <html>
        <head>
            <meta charset="utf-8">
            <title>SimonSays</title>
            <meta name="viewport" content="width=device-width, initial-scale=1">
            <link rel="stylesheet" href="css/main.css">
        </head>
        <body>
            <div id="wrap">
              <nav>
                <button id="start-game">Start</button>
                <div class="label-element-group">
                  <label for="rounds-display">Round: </label>
                  <div class="display" id="rounds-display"></div>
                </div>
                <button id="reset-game">New game</button>
              </nav>
              <div id="board">
                <div id="green" class="play-button"></div>
                <div id="red" class="play-button"></div>            
                <div id="yellow" class="play-button"></div>
                <div id="blue" class="play-button"></div>
    
                <div class="message" id="game-over"
                     title="Hit &lt;New game&gt; to start a new game!">
                     GAME OVER
                </div>
              </div>
    
            </div>
        </body>
    </html>

\$\endgroup\$
  • \$\begingroup\$ You can turn this into an on-site executable snippet by pasting your code into the Stack Snippet editor - just edit and Ctrl+M :-) \$\endgroup\$ – Mathieu Guindon Jan 25 '16 at 16:13
2
\$\begingroup\$

I don't consider myself a javascript expert yet (proof of that is my own attempt at Simon in javascript!), but I see some things that may help you improve your code.

Use responsive design

Unfortunately, the css uses absolute px measurements instead of relative measurements, so the result is that on a small screen, like a phone, this isn't playable because most of the game is off the screen. If you're using the Firefox browser, you can use the built-in responsive design view to see how your page looks at various screen sizes.

Amend the gameplay

Each round starts a brand new sequence. That's not necessarily an error, but the way the original worked was that it would add one to the sequence each time, so if the sequence for round 4 was "RGYB", the sequence for round 5 might be "RGYBG".

Is the + operator needed here?

There is this line in the code:

var step = 2 * +i;

Generally, I understand that +i would give the numeric representation of i, but it doesn't seem possible that i is anything but numeric there. Could be I'm missing something.

Disable input until the sequence is done

Right now, a user can "cheat" by just following the game as it lights each button rather than having to wait for the sequence to be done before replaying. This effectively eliminates the memory aspect of the game. Better would be to disable input until the computer has played the entire sequence once.

Add sound

You probably already have that in mind, but that was an important aspect of the original game.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Thanks a lot. Guess your right with your points. Especially concerning the gameplay. I'll change it. \$\endgroup\$ – bo256 Jan 26 '16 at 7:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.