Arduino – Simon game / Part 1

A few days ago, I had a bit of downtime so I decided to use it wisely and started playing with the brand new Arduino kit we’ve got in the office. You’d have guessed, I’m sure, that Arduino is right up my street. Every time a LED lights up on the breadboard, it takes me back to the magic moment when I started coding a few years ago. I’m like a kid in a candy shop with this thing. Anyway, enough with the digression. Had a bit of a downtime so I decided to build a Simon ( you know, that game when you need to repeat a given sequence); thought it was simple enough for a first assignment (not quite the first, but let’s say it is).

Simon game Arduino

How to build a Simon game with Arduino and BreakoutJS

Components needed:

  • Arduino UNO
  • Jump wires
  • 3 buttons
  • 3 10KOhm resistors
  • 2 560Ohm resistors
  • 1 green LED
  • 1 red LED

And obviously, you need a computer running a Breakout server and some coding skills (but quite basic, not to worry).
All set? Go!

So, let’s break down that game in a few steps;

  1. Add 3 buttons to the board and make them detectable in the browser
  2. Create a random colour sequence
  3. Enable buttons once the sequence has played/ disable them when sequence is playing
  4. Compare played sequence and user sequence
  5. If good, go to next level
  6. Additional features

a) For each level, update existing sequence instead of generating a new random one
b) Switch colour on and off between two light ups (avoids confusion if there’s the same colour twice in a row)
c) Use red and green LEDs to validate level
d) Design web page screen

————————————————————————-
So, here’s my basic HTML page template.

<!DOCTYPE html>
<html>
<head>
	<title>Arduino  | Simon game by Lily</title>
	<script src="/dist/Breakout.js" type="text/javascript"></script>


	<script type="text/javascript">

		window.onload = function() {
			var host = "localhost",
				port = 8887,
				arduino;

			// Enable debug output
			BO.enableDebugging = true;

			arduino = new BO.IOBoard(host, port);
			arduino.addEventListener(BO.IOBoardEvent.READY, function(evt) {
				//Most of the coding will happen in this function
			});
		}

	</script>
</head>
<body>
</body>
</html>

To preview all the steps, just go to your localhost on port 8887 and add the path to your index.html

1. Add 3 buttons to the board and make them detectable in the browser
So, I’ll start by adding my three buttons to the board, wired to pins 2, 4 and 7 with coloured jumpwires (respectively orange, blue and yellow – colours are important for the next steps).
And this is what my Javascript looks like:

var btn1 = new BO.io.Button(arduino, arduino.getDigitalPin(2), BO.io.Button.PULL_UP);
var btn2 = new BO.io.Button(arduino, arduino.getDigitalPin(4), BO.io.Button.PULL_UP);
var btn3 = new BO.io.Button(arduino, arduino.getDigitalPin(7), BO.io.Button.PULL_UP);

btn1.addEventListener(BO.io.ButtonEvent.PRESS, onButtonPressed);
btn2.addEventListener(BO.io.ButtonEvent.PRESS, onButtonPressed);
btn3.addEventListener(BO.io.ButtonEvent.PRESS, onButtonPressed);

function onButtonPressed(evt) {

	switch(evt.target.pinNumber) {
		case 2:
			document.getElementById("one").value = 'orange';
			document.getElementById("two").value = '';
			document.getElementById("three").value = '';
		break;

		case 4:
			document.getElementById("one").value = '';
			document.getElementById("two").value = 'blue';
			document.getElementById("three").value = '';
		break;

		case 7:
			document.getElementById("one").value = '';
			document.getElementById("two").value = '';
			document.getElementById("three").value = 'yellow';
		break;
	}
}

And in the body, add 3 input tags with respective ids ‘one’, ‘two’ and ‘three’.

2. Create a random colour sequence

Here we want the computer to generate a colour sequence that the user will have to repeat (using the same three colours as before orange, blue, yellow).
We want the first sequence to have a length of three. So we’ll start by defining a level variable with a value of three, and then create an empty array called ‘sequence‘.
We then want to generate a random sequence, therefore we’ll call a createSequence function:

function createSequence() {
	for (var i = 0; i<level; i++) {
		sequence.push(Math.floor(Math.random()*3));
	}

	playSequence(sequence);
}

function playSequence (seq) {
	var j = 0;

	var lightTimer = setInterval(function(){
		if(j < seq.length)
		{
			lightUpColor(seq[j]);
			j++;
		} else {
			clearInterval(lightTimer);
		}

	}, 800);

}

function lightUpColor(slotNumber) {
    if (slotNumber === 0) {
		$('#one').val("orange");
        $('#two').val("");
	    $('#three').val("");

	} else if (slotNumber === 1) {
		$('#two').val("blue");
        $('#one').val("");
        $('#three').val("");

	} else if (slotNumber === 2) {
		$('#three').val("yellow");
        $('#one').val("");
	    $('#two').val("");

	}
}

At this point, don’t forget to include a link to jQuery in your html and refactor the onButtonPressed function so that it calls the lightUpColor function with either 0, 1, or 2 as arguments.

3. Enable/Disable the buttons when computer sequence has played/is playing
For this we’ll just need a good old boolean variable called btnEnabled defaulted to false.
Move all the buttons’ event listeners to a function called enableButtons in which btnEnabled will be set to true.
Duplicate the previous function, call the copy disableButtons, remove the event listeners instead of adding them; e.g.

btn1.removeEventListener(BO.io.ButtonEvent.PRESS, buttonPress);

and set btnEnabled back to false.
In playSequence call disableButtons if the boolean is true. Call enableButtons if the boolean is false and the lightTimer is done running.

4. Compare played sequence and user sequence
Create an empty array call user_sequence in onButtonPressed, for each case push user_sequence with either 0, 1 or 2.
Once the length of the user array matches the length of the initial sequence array, call compareSequences.

function compareSequences() {
	var cumulator = 0;

	for(var k = 0 ; k <sequence.length; k++) {
		if(sequence[k] === user_sequence[k]) {
			cumulator++;
		}

		if(k === sequence.length - 1) {
			if(cumulator === sequence.length) {
				return true;
			} else {
				return false;
			}
		}
	}
}

A quick look at what happens in this function :
Every time an item of user_sequence matches sequence, cumulator is increased by one. Once we’ve reached the end of the array if cumulator matches the length of sequence (i.e. if all the items match), then it’s a win; if not, user has lost.

5. If good, go to next level

If compareSequences returns true, increase level by one, reset sequence and run createSequence again.

6. Additional features
a)For each level, update existing sequence instead of generating a new random one
Instead of increasing level by one every time and re-generating an array of random 0s, 1s and 2s; rename createSequence into initSequence and call this function on load, after having defined all the variables. Then, create a new createSequence function which should reset user_sequence, push sequence with a new random number between 0 and 2 and call playSequence.
We end up with the following:

function initSequence() {
	for (var i = 0; i<level; i++) {
		sequence.push(Math.floor(Math.random()*3));
	}

	playSequence(sequence);
}
function createSequence() {
	user_sequence = [];
	sequence.push(Math.floor(Math.random()*3));

	playSequence(sequence);
}

b) Switch colour on and off between two light ups

The problem we’re facing currently is that if two yellows come up in a row, the screen won’t say that you have to press yellow twice. The yellow input will stay completed until another colour comes up. In order to empty the field between two items of the sequence, just amend the lightUpColor function so that all the fields are reset after 600ms.
In other words,

setTimeout(function(){
	$('#one').val("");
	$('#two').val("");
	$('#three').val("");
},600);

c) Use red and green LEDs to validate level

If the user has repeated the sequence correctly, a green light will light up. If not, a red one will.
Connect a green LED(+ 560KOhm resistor) to pin 5 on the board and a red LED (+ 560KOhm resistor) to pin 6.
Add them to your code,

var led_green = new BO.io.LED(arduino, arduino.getDigitalPin(5, BO.Pin.PWM));
var led_red = new BO.io.LED(arduino, arduino.getDigitalPin(6, BO.Pin.PWM));

All we need to do now is to switch them on when the sequence has been validated. (Note that I’ve set them as PWM pins to be able to control the intensity of the light).
So, in onButtonPressed, checking the sequence should look like this:

if(user_sequence.length === sequence.length) {
	if(btnEnabled)	disableButtons();

	if(compareSequences()) {
		led_green.intensity = 0.2;
			setTimeout(function(){
				led_green.off();
				createSequence();
			}, 1000);

	} else {
		led_red.on();
		console.log('you\'ve lost :(');
	}
}

d) Design web page screen
Feel free to design your own Simon. Just a quick tip on the colour light ups: I’ve designed an on and off state for each, both on the same PNG. This PNG is used as a background for an li tag, and I just move the background position and reset it in lightUpColor

Arduino board

That’s about it for now. I realise this first post is huge, but I wanted everyone to be able to follow. Let me know for future posts if it’s too much/not enough.
As the title suggests, this is only the first part and I’ve got a list of improvements that can be made in the future. Hopefully, I’ll get to implement them soon.

Further reading:

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s