Tutorial: Black Box Testing

Leave a comment Standard
equivalence_partitioning

What Is Testing?

Testing is a way to check if your software is running properly by purposefully trying to find errors so they can be corrected or prevented from happening in the future.

Why Should You Test?

One thing that’s important to understand is that software testing cannot prevent all bugs or errors. Instead, it can identify bugs and errors so they can be corrected. If testing is used in conjunction with software development it can quickly and easily identify when and where new changes to the software have caused issues or problems so they may be corrected. However, since testing uses a specific set of conditions to test with, it will not cover all cases and prevent all bugs — but it can often prevent introducing new bugs  for those specific conditions when new or additional software changes are made.

Downsides of Testing?

This is kind of a glass half full, glass half empty question. While testing is helpful in finding bugs it is also a tedious process and it cannot prevent all bugs from occurring. In addition, good testing conditions are hard to establish especially with highly complex and multi-variable software.

Black Box Testing

Tests the input and outputs of the software and focuses on the software behavior and it’s performance efficiency. In black box testing there is no knowledge of how the internal system works, only that when given an input you get the correct output.

Tester Inputs    -> Software
(internals unknown)
->    Software Outputs

Equivalence Partitioning

Test conditions are divided into groups of functionality that exhibit similar behaviors. Instead of testing the functionality individually, which may take a long time, you can test one section of functionality from the group because the other functionality is likely to exhibit the same behavior given the same conditions.

equivalence_partitioning

In the image above you can see an example of equivalence partitioning. Each 9 block square of the Sudoku puzzle is a smaller component of code that behaviors similarly to the others. Therefore if we wrote an equivalence test to pass in a number to one of the boxes on the Sudoku board it would return true/false if a duplicate number was found in that section of the box. This test would work exactly the same way for the other colored partitions, therefore there’s no need to write a test for each of the individual partitions.

Boundary Value Analysis Testing

Often times a problem arises with a piece of software when the input value is at the boundary of the acceptable input values. With boundary value testing you identify the valid and input partitions and then test the high and low values of that boundary.

Let’s go back to our original Sudoku puzzle. In this game we allow the numbers 1-9 in each of the squares. That means numbers below 1 and above 9 are invalid. So we can separate our input partition into three partitions, two invalid and one valid:input-boundary-partitions.jpg

In this case we test the value before and right after the ends of our valid partitions. That means testing 0 and 1 and then 9 and 10.

boundary_value

Another approach to boundary testing is to only test the upper and lower values of the valid partition and the upper and lower boundaries of the invalid partitions. For example, testing to make sure 0, 10 are invalid and 1,9 are valid.

boundary_value_minmax

Another way to boundary test is to include one number after the boundary and one number before the boundary, as well as the boundary itself. That would mean testing 0, 1, 2 where 1 is the lower boundary and 8, 9, 10 where 9 is the upper boundary.

boundary_value_all_pairs

Decision Table Testing

This allows you to take a complex rule set and and translate it to it’s corresponding actions. Each rule goes in the top section of the table and each action goes in the bottom. Then you create a grid with different rules selected in the conditions section and the corresponding action that should happen when those conditions are met.

Let’s take our Sudoku for example and make a simple decision table for it.

Conditions Rules
User enters valid number Y Y Y Y N N N N
Duplicate number in that grid section Y Y N N Y Y N N
Grid  has no more empty spaces Y N Y N Y N Y N
Actions
Highlight the grid square  X  X  X  X  X  X
Validate the user input X  X X  X  X  X  X  X
Check for duplicate numbers X  X X  X X  X X  X
Show an error X X X X  X  X
Check for a winning game  X

In our decision table we added some of the possible game conditions and then outcomes we expect if those conditions are or are not met. Now we can test our game for each of these conditions and assert that the predicted outcomes have been met successfully.

State Transition Table Testing

This table uses the different states of the software and what they should transition to in order to develop tests. First you start with a state diagram, then you translate that into a state transition table. Let’s continue with our Sudoku example where we have a few major states of the game: drawing the board, validating input, showing an error message, checking to see if the game is won or not, handling a winning game, showing a final score and then clearing the board to start a new game.

sudoku-state-transition-diagram-1

To make our state transition table we put our state down one column and user inputs across the top rows. Then we fill in the table according to the input to indicate what states the software can transition to once the input is given. So, when Sudoku validates the user’s input after they enter a number it will either find valid input and check the game status to see if they won, or it will recognize an invalid or duplicate input and show them an error message.

Input
State
Enter A Number Press Clear Submit Score
Draw Board Validate Input Clear Board
Validate Input Check Game Status
Validate Input Show Error Message
Show Error Message Draw Board
Clear Board Draw Board
Show Score  Draw Board
Check Game Status Draw Board
Check Game Status Game Over
Game Over Show Score

Use Case Testing

This kind of testing approaches the different interactions that an actor will  typically use in order to accomplish their goals when they are using the software. An actor is anyone who will be interacting with the software.

usecase

If we refer back to our Sudoku example we have only one actor, the person playing the game. Then we define all of the different goals our user will need to accomplish as it’s own use case. Now we can tailor our tests to ensure that all of these different use cases are present and working in the final version of our software.

Fuzz Testing

With fuzz testing you enter values that are outside of the expected input, as well as longer and shorter than the expected input.

fuzz_testing.jpgSince our Sudoku expects a single integer that means we would perform fuzz testing with non-integer values, as well as empty values and more than the maximum characters expected. In the example below we test floats, strings, characters and values with more than 1 character.

Exploratory Testing

This is a by-product of running other black box testing. As a tester, as you write tests for the software you will, by your own creativity, observation or personal experience, think of other good tests that you want to include during the testing of your software.

For instance, if you’re familiar with Cross Site Scripting  Injections (XSS) and while you’re doing Fuzz testing you realize you can enter more than a single character into the Sudoku input box you may then decide to run additional XSS injection tests to make sure the software cannot be compromised in this way.

Grey Box Testing

This is just like black box testing except the tester does have some knowledge of the internal data structures or algorithms used in the software while they are running their black box tests. The tester may only have knowledge of the data structures or a limited access to the code base while they are performing their black box tests.

Tester Inputs    -> Software
(internals partially known)
->    Software Outputs

Testing In Practice

Generally you find three schools of thought when it comes to testing in a real development situation, each have their own reasons for using or not using tests.

No Testing

Testing is extremely time consuming and if you’re developing software that changes often and in a large way the tests you’ve written may not even be relevant anymore. For this reason in rapid development and prototyping you’re less likely to include any kind of testing.

Some Testing

This school of thought is that it’s good to have tests for your software but they don’t need to be exhaustive. Generally if you’re doing some testing you’ll set a threshold for the amount of testing you must have in order for the testing to be considered “good enough”. This is usually found in legacy software systems or systems that are so large and didn’t have tests before than adding in tests to the existing code base would be an enormous and/or exhaustive effort. These tend to be developers that recognize the benefit of testing however, they also realize that testing will not stop or prevent all bugs from ever happening and the software is changing fast enough that tests need not provide 100% coverage on the code base. Also, some things are much harder or impossible to test so achieving tests for 100% of the software may not be possible.

Test Driven Development

In this practice all tests are written before the code has been developed and the test should describe what the code will do. Generally in test driven development you don’t see a lot of documentation in the code base because the tests are representative of that documentation (or should be). Software created with test driven development tends to have fewer bugs but the amount of time invested on creating and modifying tests as the code base changes is a large part of the development cycle for the software. In addition, there are times when it’s impossible to test a piece of code that’s been written which leaves you to question if the code should be re-designed or the test needs to be re-written causing a lot of circling back during the development process.

The Game Plan: I’m Not a Programmer

Leave a comment Standard

If you’ve been following my Game Plan series then you’ve already put your game idea to paper and have a game design document done along with a set of small, easy to complete tasks to get you started working on a MVP or minimum viable product.

But What If You Can’t Do It?

If you lack the skills to do something during this game design journey then it really boils down to these two options:

  1. You outsource the work to someone who knows how to do it. If you go this route then you have to account for what it would cost to hire a knowledgeable person. Don’t expect that you will be able to find someone to do the work for free as this is often not the case, no matter how awesome your game idea is.
  2. Resign yourself to learning a new skill. You don’t have to be an expert programmer to make a game, just an adequate one. If you’re going to invest time into learning a new skill then don’t dwell on it for too long. Learn enough that you feel confident to complete the task at hand and then move on. Investing too much time in learning a skill will start you down a path further and further from a working game.

Outsourcing The Work

If you’ve decided to outsource the work here are a few things you should consider when hiring someone.

  1. Be prepared to pay — nothing in life is free!
  2. Ask for current examples of their work
  3. Communication is key, make sure you can easily understand each other
  4. Setup a timeline and consequences for BOTH parties not sticking to it
  5. Be available to answer questions and be flexible to suggested adjustements, changes and/or improvements
  6. Put everything in writing and set all expectations up front

Learning It Yourself

If you’ve decided to learn how to do it yourself then find a good resource that you like and understand and dig in until you can complete the task at hand. Try not to go above and beyond the task you’re trying to complete — remember that this will steer you away from delivering a minimum viable product. Here’s some good resources to get you pointed in the right direction:

Programing

Art

Music & Sound

Animation

HTML5 Game Tutorial: Alien Invasion

Leave a comment Standard
alieninvasion_screenshot

alieninvasion_screenshotThis is a little side project I did this week that I would like to share. It’s forked from another project I found on gitHub and liked it so much I decided to spend some time adding new features to brush up on my HTML5 skills. It uses the Canvas and Audio with JS to create multiple levels and bosses and power ups and different types of enemies and fire power. It’s still a work in progress but I’m not going to hand out the final version here but there’s plenty in the code base for you to take it and make it your own or continue to improve upon it. Click the Remix button to fork it and view the source on Thimble.

Here’s a video of the game if you’re too lazy to try it out yourself:

Sample Angular Website

Leave a comment Standard
AngularJS

So I’ve seen a lot of people using AngularJS but I see very few examples of a website made using it. That’s why I decided to post an example website to give you an idea of what a full website looks like using AngularJS. It has samples of some of the things you’ll commonly find in a website made entirely with Angular:

  •  Navigation & Routing
  • Providers & Directives
  • Controllers & Config Blocks
  • Data Calculations
  • Filtering

Sorry if you’re looking for Angular 2.0, this was made with Angular 1.5.8. View, fork and/or edit the files on Plunker!

The Game Plan: Getting Started

Leave a comment Standard
file0001764062159

Your game design can run fairly smoothly or it can be a continuous cesspool of hardships and setbacks and pain points. In the next few series of posts I’m going to try and help walk you through the process of getting your game up and off the ground, from what you’re envisioning in your head to an actual working version. So, let’s get started.

1. Get It Out Of Your Head

It’s time you pull out a pencil, pen, or open your laptop to a writing program. First thing’s first, you have to get your game out of your head. Write it down and put it somewhere you can reference it later.

2. Writer’s Block

So if you’ve opened a text editor or you have a pen in your hand you’ve successfully completed step one. Now, what do you write? I like to start with the five W’s:

Whom?

  • Does your game appeal to a specific age range or interest group or gender or even ethnic background?
  • Will you have a large audience your game will appeal to or a small audience?
  • What are the benefits and downsides of the audience you’ve identified?

What?

  • What kind of game are you trying to make?
  • What programming language best suits this kind of game?
  • Does it fit into a specific genre of game or does it span multiple genres?
  • Does it embody a completely new genre?
  • Can you find other games that are similar to the game you are trying to make? If so, what do these games do well and where do fall short?
  • Are there lots of other games on the market similar to the type of game you’re trying to make?
  • What will your charge for your game?
  • What do other, similar games of this type charge?
  • What are the benefits and downsides of the type of game you’re trying to make?

Where?

  • Where does your game take place?
  • What kind of maps or features or environment are unique to your game?
  • What are the benefits and downsides of where your game takes place?

When?

  • When will you have time to work on this game?
  • When can you start this game?
  • When can you fund the development of this game?
  • What are the benefits and downsides of developing this game?

Why?

  • Why are you making this game?
  • Why is your game unique?
  • Why will your game stand out from the crowd?
  • Why will people choose to play your game over other similar games?
  • Why will people pay for your game?
  • What are the benefits and downsides of making this game?

3. Make A Design Document

Your design document is a refined version of everything you’ve written down in step 2. Go back and really analyze what your goals for the game are and if what you’ve written down makes sense in the larger picture. Sometimes a good idea you have for one area of the game will conflict or make another part of the game tedious, uninspired or downright frustrating. For a game design document I like to use the following format:

  1. Intro
    • What is the vision for your game and a short description of how the game is played
  2. Audience, Platform & Marketing Strategies
    • Who the game is for, what platforms you’re making it for and what sets your game apart that will make it marketable and different from others
  3. Core Gameplay & Mechanics
    • How the game is played including physics, rules and limitations
  4. Characters
    • What characters are in your game including what they look like, their names and backgrounds and personalities
  5. Story, Themes & Twists
    • If your game has an overarching story then you’ll outline your plot and how the game progresses with the story line
  6. World
    • Describe the world your game is set in, including maps and locations and their purpose or importance
  7. Assets
    • All the different images, music, animations, etc that you will need to have a fully functional game
  8. Technical Specs
    • What language you’re using, how games are loaded/saved, where games are stored, the number of servers you’ll need and anything else relating to the technical setup of your game
  9. Interface
    • What the game interface looks like and how the player will interact with it
  10. Outside References
    • Articles, links, design inspriations, or anything else that you’re using as a reference for the game you’re making
  11. Appendix
    • Code style guidelines, dictionary of terms, and anything else that is important for understanding your design document that may not necessarily relate to your game directly

Once you’ve fully fleshed out your game design by going into depth about the features, physics, economy, weapons, characters and how the game works it’s time to break it down. Start by creating lots of of small, easy tasks you can accomplish in order to see your core game mechanics to completion enough that you could play a simple version of your game without any extra bells and whistles. Set yourself up to do as little as you have to but as much as you need to in order to get a really simplified, yet completed, version of your game.

JS Tutorial: Recursive Promise Calls

Leave a comment Standard

The Reason

So in trying to help a co-worker I was looking for an example of how you can do recursive promise calls. To my surprise I didn’t find any soooo now you get this post🙂 In a typical scenario you would chain your promises one after the other, however in real world situations the solution is not always so cut and paste. For instance you may need to ping a crappy device and wait for the results of the first ping to come back before you can ping the device again. If that’s the case upgrade your device, but if that’s not an option then you can always use this slash and hack solution of recursive promise calls which I would not recommend unless you have to but yeah, real life sucks sometimes. So here you have it, I hope this helps.

Test or fork the working example on Plunker

The Code

//somewhere to store the results of your recursive calls
var results = [];

/**
* Recursive function
*
* @param int val how many times to call this function recursively
* @return null
**/
var promiseMore = function(val) {
  console.log('attempting promise ' + val);

  //defer the promise
  var deferred = Promise.defer();

  //check your recursive conditions, keep looping while true
  if (val > 0) {
    //run your ajax request
    $.ajax({
      method: 'post',
      url: 'https://api.random.org/json-rpc/1/invoke',
      data: JSON.stringify({
        "jsonrpc": "2.0",
        "method": "generateSignedStrings",
        "params": {
          "apiKey": "4e69c4a7-4e47-4811-b110-6c7bfce079db",
          "n": 1,
          "length": 4,
          "characters": "abcdefghijklmnopqrstuvwxyz",
          "replacement": true
        },
        "id": 29970
      }),
      dataType: 'json',
      success: function(response) {
        document.write('Got data for promise ' + val + '<br/>');
        results.push(response.result.random.data[0]);

        //this triggers the recursion
        d = promiseMore(--val);

        //resolve this promise
        return deferred.resolve(d);
      }
    });
  } else {
    doSomethingWithResults();
  }
}

/**
* Whatever you want to do when your recursive promises are done firing
*
* @return null
* @print lots of BS random string results from our promises
**/
var doSomethingWithResults = function() {

  document.write('<br/>============<br/>');
  document.write('Doing something with the results now...');
  document.write('<br/>============<br/><br/>');

  //print out the data we got from the recursive promises
  for (i = 1; i <= results.length; i++) {
    document.write('Results ' + i + ': ' + results[i-1] + '<br/>');
  }
}

//kick off the call to the recrusive promises
promiseMore(10);

 

Html5 Game Tutorial: Pong

Comments 2 Standard
Screen Shot 2016-02-07 at 7.25.28 PM

This is a simple HTML5 version of the classic game of pong. Play against the computer for as many levels as you can. The computer gets faster and more competitive the higher the level gets. The game can easily be customized to grow/shrink the paddles and the computer’s difficulty if you’re looking for a challenge after you’ve finished putting the tutorial together. You’ll need a current version of a browser (Chrome, Firefox) that supports HTML5 in order to complete this tutorial. Enjoy!

Download the Code or Fork on Plunker or Try the Working Version

Create the HTML File

The beauty of html5 is that you can program it using javascript. This makes your html file small and super simple. All we need to do is create a canvas for the game and then include the javascript file:

<html>
<canvas id="battlePong"></canvas>
< script type="text/javascript" src="battlePong.js"></script>
</html>

Create the Javascript File

/**
* File: BattlePong.js
* Purpose: HTML5 pong game
* Author: Design1Online.com, LLC <jade@design1online.com>
* Created: 6/7/2016
**/

//global game variables
var game = {
 debug: true,
 canvas: null,
 canvasContext: null,
 frameRate: 1000,
 framesPerSecond: 30,
 fonts: {
 header: '30px Arial',
 regular: '15px Arial'
 },
 colors: {
 net: 'gray',
 background: 'black',
 header: 'red',
 text: 'white'
 },
 screens: {
 winner: false,
 startGame: true,
 levelUp: false,
 continue: false
 },
 ball: {
 x: 50,
 y: 50,
 speedX: 10,
 speedY: 4,
 threshold: 35,
 radius: 10,
 color: 'blue'
 },
 level: 1,
 pointsPerLevel: 3,
 player: {
 score: 0,
 lives: 5,
 paddle: {
 y: 250,
 thickness: 10,
 height: 100,
 color: 'green'
 }
 },
 computer: {
 score: 0,
 paddle: {
 y: 250,
 thickness: 10,
 height: 100,
 speed: 6,
 color: 'red'
 }
 }
};

/**
* Start the game when the window loads
**/
window.onload = function() {

 //init the canvas
 game.canvas = document.getElementById('battlePong');

 //adjust canvas to window size
 game.canvas.width = window.innerWidth - game.computer.paddle.thickness;
 game.canvas.height = window.innerHeight;

 //create the context
 game.canvasContext = game.canvas.getContext('2d');

 //add event listeners
 game.canvas.addEventListener('mousedown', mouseClickHandler);
 game.canvas.addEventListener('mousemove', mouseMoveHandler);

 //start buffering the screen
 setInterval(function() { buffer(); }, game.frameRate / game.framesPerSecond);
};

/**
* Figure out the player's mouse position
**/
function mouseMoveHandler(e) {
 var mousePos = mousePosition(e);
 game.player.paddle.y = mousePos.y - (game.player.paddle.height / 2);
}

/**
* Return the x,y coordinates of the mouse in
* relation to the screen
**/
function mousePosition(e) {
 var rect = game.canvas.getBoundingClientRect();
 var root = document.documentElement;

 return {
 x: e.clientX - rect.left - root.scrollLeft,
 y: e.clientY - rect.top - root.scrollTop
 };
}

/**
* Handle mouse clicks
**/
function mouseClickHandler(e) {

 if (game.debug) {
 console.log('mouseClickHandler()');
 }

 if (game.screens.startGame) {

 if (game.debug) {
 console.log('Removing start screen');
 }

 game.screens.startGame = false;
 }
 else if (game.screens.continue) {

 if (game.debug) {
 console.log('Removing start screen');
 }

 game.screens.continue = false;
 }
 else if (game.screens.levelUp) {

 if (game.debug) {
 console.log('Removing level up screen');
 }

 game.screens.levelUp = false;
 }
 else if (game.screens.winner) {

 resetGame();

 if (game.debug) {
 console.log('Removing winner screen, showing start screen');
 }

 game.player.score = 0;
 game.computer.score = 0;
 game.screens.winner = false;
 game.screens.startGame = true;
 }
}

/**
* Start the game
**/
function startGame() {

 if (game.debug) {
 console.log('Starting game...');
 }

 if (game.player.lives <= 0) {
 game.screens.winner = true;
 }

 game.ball.speedX = -game.ball.speedX;
 game.ball.x = game.canvas.width / 2;
 game.ball.y = game.canvas.height / 2;
}

/**
* Move the ball and the computer mouse paddle
**/
function move() {

 var deltaY = 0;

 //move computer paddle
 var center = game.computer.paddle.y + (game.computer.paddle.height / 2);

 if (center < game.ball.y - game.ball.threshold) {
 game.computer.paddle.y = game.computer.paddle.y + game.computer.paddle.speed;
 } else if (center > game.ball.y + game.ball.threshold) {
 game.computer.paddle.y = game.computer.paddle.y - game.computer.paddle.speed;
 }

 //move ball
 game.ball.x = game.ball.x + game.ball.speedX;
 game.ball.y = game.ball.y + game.ball.speedY;

 //check for paddle collisions
 hitCollision();

 if (game.ball.y < 0) {
 if (game.debug) {
 console.log('Inverting ball Y speed 1');
 }

 game.ball.speedY = -game.ball.speedY;
 }
 if (game.ball.y > game.canvas.height) {

 if (game.debug) {
 console.log('Inverting ball Y speed 2');
 }

 game.ball.speedY = -game.ball.speedY;
 }
}

/**
* Check for ball/paddle collisions
**/
function hitCollision()
{
 //player paddle check
 if (game.ball.x <= 0) {

 if (game.debug) {
 console.log('player paddle collision check');
 console.log('ball', game.ball);
 console.log('player paddle', game.player.paddle);
 console.log(
 'hit or miss',
 game.ball.y > game.player.paddle.y,
 game.ball.y < (game.player.paddle.y + game.player.paddle.height + game.ball.radius)
 );
 }

 if (game.ball.y > (game.player.paddle.y) &&
 game.ball.y < (game.player.paddle.y + game.player.paddle.height + game.ball.radius)
 ) {
 game.ball.speedX = -game.ball.speedX;

 deltaY = game.ball.y - (game.player.paddle.y + game.player.paddle.height / 2);
 game.ball.speedY = deltaY * 0.35;
 } else {
 game.computer.score++;
 game.player.lives--;
 game.screens.continue = true;
 startGame();
 }
 }

 //computer paddle check
 if (game.ball.x >= game.canvas.width) {

 if (game.debug) {
 console.log('player paddle collision check');
 console.log('ball', game.ball);
 console.log('player paddle', game.computer.paddle);
 console.log(
 'hit or miss',
 game.ball.y > game.computer.paddle.y,
 game.ball.y < (game.computer.paddle.y + game.computer.paddle.height + game.ball.height)
 );
 }

 if (game.ball.y > (game.computer.paddle.y) &&
 game.ball.y < (game.computer.paddle.y + game.computer.paddle.height + game.ball.radius)
 ) {
 game.ball.speedX = -game.ball.speedX;

 deltaY = game.ball.y - (game.computer.paddle.y + game.computer.paddle.height / 2);
 game.ball.speedY = deltaY * 0.35;
 } else {
 game.player.score++; //increase score

 //level up
 if (game.player.score > 0 && game.player.score % game.pointsPerLevel === 0) {
 game.player.lives++; //get another life
 game.level++; //level up
 game.computer.paddle.speed += 1.3; //increase computer paddle speed
 game.screens.levelUp = true;
 } else {
 game.screens.continue = true;
 }

 startGame();
 }
 }
}

/**
* Draw the game board
**/
function drawBoard() {

 //draw the net
 for (var i = 0; i < game.canvas.height; i += 10) {
 drawRectangle(game.canvas.width / 2 - 1, i, 2, 1, game.colors.net);
 }

 //draw the score text
 var offset = 100;

 //set the header text
 var header = "BattlePong!";
 game.canvasContext.fillStyle = game.colors.header;
 game.canvasContext.font = game.fonts.header;
 game.canvasContext.fillText(header, offset, 30);

 //set the colors and font style
 game.canvasContext.fillStyle = game.colors.net;
 game.canvasContext.font = game.fonts.regular;

 //set the score text
 var score = "Score: " + game.player.score;
 game.canvasContext.font = game.fonts.text;
 var scoreSize = game.canvasContext.measureText(score);
 game.canvasContext.fillText(score, offset + 5, 50);

 //set the lives text
 var lives = "Lives: " + game.player.lives;
 var livesSize = game.canvasContext.measureText(lives);
 game.canvasContext.fillText(lives, offset + scoreSize.width + 25, 50);

 //set the copyright text
 var copyright = "Games by design1online.com, LLC";
 var copyrightSize = game.canvasContext.measureText(copyright);
 game.canvasContext.fillText(copyright, game.canvas.width - copyrightSize.width - offset/4, game.canvas.height - offset/4);

 //player paddle
 drawRectangle(
 0,
 game.player.paddle.y,
 game.player.paddle.thickness,
 game.player.paddle.height,
 game.player.paddle.color
 );

 //computer paddle
 drawRectangle(
 game.canvas.width - game.computer.paddle.thickness,
 game.computer.paddle.y,
 game.computer.paddle.thickness,
 game.computer.paddle.height,
 game.computer.paddle.color
 );

 //ball
 drawBall(game.ball.x, game.ball.y, game.ball.radius, game.ball.color);
}

/**
* Draw the ball
**/
function drawBall(centerX, centerY, radius, color) {
 game.canvasContext.fillStyle = color;
 game.canvasContext.beginPath();
 game.canvasContext.arc(centerX, centerY, radius, 0, Math.PI * 2, true);
 game.canvasContext.fill();
}

/**
* Draw paddle
**/
function drawRectangle(leftX, topY, width, height, color) {
 game.canvasContext.fillStyle = color;
 game.canvasContext.fillRect(leftX, topY, width, height);
}

/**
* Reset for a new game
**/
function resetGame()
{

 if (game.debug) {
 console.log('Resetting game...');
 }

 game.level = 1;
 game.computer.paddle.speed = 6;
 game.player.score = 0;
 game.computer.score = 0;
 game.player.lives = 5;
}

/**
* Draw the winner screen
**/
function screenWinner() {
 var center = game.canvas.width / 2;
 var height = game.canvas.height / 2;
 var header = "Game Over!";
 var score = "Score: " + game.player.score;

 //set the header text
 game.canvasContext.fillStyle = game.colors.header;
 game.canvasContext.font = game.fonts.header;
 var headerSize = game.canvasContext.measureText(header);
 game.canvasContext.fillText(header, center - headerSize.width/2, height);

 //set the score text
 game.canvasContext.fillStyle = game.colors.text;
 game.canvasContext.font = game.fonts.regular;
 var scoreSize = game.canvasContext.measureText(score);
 game.canvasContext.fillText(score, center - scoreSize.width/2, height + 25);
}

/**
* Draw the continue screen
**/
function screenContinue() {
 var center = game.canvas.width / 2;
 var height = game.canvas.height / 2;

 //set the header text
 var header = "Missed Ball!";
 game.canvasContext.fillStyle = game.colors.header;
 game.canvasContext.font = game.fonts.header;
 var headerSize = game.canvasContext.measureText(header);
 game.canvasContext.fillText(header, center - headerSize.width/2, height);

 //set the info text
 var info = "Click anywhere to start the next ball";
 game.canvasContext.fillStyle = game.colors.text;
 game.canvasContext.font = game.fonts.regular;
 var infoSize = game.canvasContext.measureText(info);
 game.canvasContext.fillText(info, center - infoSize.width/2, height + 25);
}

/**
* Draw the level up screen
**/
function screenLevelUp() {
 var center = game.canvas.width / 2;
 var height = game.canvas.height / 2;

 //set header
 var header = "Level " + game.level;
 game.canvasContext.fillStyle = game.colors.header;
 game.canvasContext.font = game.fonts.header;
 var headerSize = game.canvasContext.measureText(header);
 game.canvasContext.fillText(header, center - headerSize.width/2, height);

 //set the regular text color and font
 game.canvasContext.fillStyle = game.colors.text;
 game.canvasContext.font = game.fonts.regular;

 //set the level text
 var info = "Click anywhere to start the next ball";
 var infoSize = game.canvasContext.measureText(info);
 game.canvasContext.fillText(info, center - infoSize.width/2, height + 25);
}

/**
* Draw the start screen
**/
function screenStartGame() {
 var center = game.canvas.width / 2;
 var height = game.canvas.height / 2;

 //set the header text
 var header = "BattlePong!";
 game.canvasContext.fillStyle = game.colors.header;
 game.canvasContext.font = game.fonts.header;
 var headerSize = game.canvasContext.measureText(header);
 game.canvasContext.fillText(header, center - headerSize.width/2, height);

 //set the info text
 var info = "Click anywhere to start playing";
 game.canvasContext.fillStyle = game.colors.text;
 game.canvasContext.font = game.fonts.regular;
 var infoSize = game.canvasContext.measureText(info);
 game.canvasContext.fillText(info, center - infoSize.width/2, height + 25);
}

/**
* Buffer the screen
**/
function buffer() {

 //black out the screen
 drawRectangle(0, 0, game.canvas.width, game.canvas.height, game.colors.background);

 //draw one if the screens if they're active
 if (game.screens.winner) {
 screenWinner();
 return;
 }
 else if (game.screens.continue) {
 screenContinue();
 return;
 }
 else if (game.screens.levelUp) {
 screenLevelUp();
 return;
 }
 else if (game.screens.startGame) {
 screenStartGame();
 return;
 }

 //playing the game
 move();
 drawBoard();
}

Test Your File

Open your html file in a browser. Make sure that your javascript file is located in the same place. Voila! Now you can tweak and refine it to your hearts content.