Friday, December 23, 2011

Step 1 - Creating the 'Wrong Design' for an HTML5 App

I'm impressed how well JavaScript supports Object Oriented Programming! I'm really starting to understand how HTML5 and JavaScript have the potential to make an awesome generation of mobile apps!

As long as I'm taking the time to learn how to create HTML5 apps, I was thinking I should aim at creating one I could put on my iPod Touch or Color Nook to review Go games.

For me, the easiest way to start a UI design is to throw away my first idea. No matter what I'm initially thinking of, it's wrong in any of a number of ways. I find drawing it out and throwing it away as quickly as possible helps me come up with a better design, faster.

So here goes:

Requirements:
  • HTML5 App that works on different platforms
  • Will play back stored Go game files
  • Uses local storage -- so will work offline
  • Supports the SGF Go game format
  • Supports UTF-8 characters

Because it's one of the few situations where I'm one of the target users, defining my audience and user stories should be pretty easy. ( As I talk to users, I can expand and improve this... )

Users:
  • Beginning Go players who want to view commented Go games 

User stories:
  • As a <beginning Go player> I want to <select a commented Go game to view> so I can <view it on my mobile device>.
  • As a <beginning Go player> I want to <view a commented Go game > so I can <read the expert comments and eventually win more games>.

The wrong design:

What I'm visualizing ( which I'm sure will be completely wrong ) looks something like this:


BTW - I drew this wireframe using the website hotgloo.com . It was really awesome! I'd never tried it before, but it was pretty close to walk-up-and-use usability for their site!

Wednesday, December 21, 2011

My First JavaScript Object...

I thought I'd learn a little more about JavaScript's Object-Oriented programming model by adding in a game object to display player moves to the board from my last post. I've never been a fan of JavaScript in the past, but since it's listed on GitHub as the most popular programming language, it seems like a good idea to become more familiar with it. So here goes!

I started by creating a game object that would store a game record and would return each individual move. Since SGF is, by far, the most common record for storing Go games I wanted to make my object compatible with this format. My JS object looked like this:


// The Game Object has the metadata about the game, the moves, and a method to access the moves
function Game( name, moves )
{
 this.name = name;
 this.moves = moves;
 this.currMove = 0;
 
 // getNextMove() gets the current move and then increments the counter to point to the next move
 this.getNextMove = function()
 {
  var nextMove = this.moves[this.currMove];
  this.currMove++;
  return nextMove;
 }

}

One thing to note is that the header for the SGF record contains a LOT  more metadata about the game. It contains information like the player's names, their level, the komi, etc. So if I pursue this in the future, I would change this object to contain all of this information.

Next, I used the following code to create an instance of this object. This is the record for an example game record with 17 moves:

var theGame = new Game("Test Game", [";B[pd]",
          ";W[dd]",
          ";B[pg]",
          ";W[qo]",
          ";B[cg]",
          ";W[fg]",
          ";B[pl]",
          ";W[co]",
          ";B[eg]",
          ";W[ep]",
          ";B[fp]",
          ";W[gp]",
          ";B[dg]",
          ";W[er]",
          ";B[dp]",
          ";W[dr]",
          ";B[gg]"]);

Since the method getNextMove( ) returns the sgf-format for each move, in order to use this on the game board, I wrote a function to convert the sgf format to the real screen coordinates:

// sgfToXy() converts this sgf format to a canvas x,y coordinate
function sgfToXy(theMove)
{
 // get the unicode value for the character 
 virtual_x = theMove.charCodeAt(3);
 virtual_y = theMove.charCodeAt(4);
 
 // subtract out 97 to transform the unicode number to the board position
 // NOTE: it would be nice if JavaScript had constants :-(
 virtual_x = virtual_x - 97;
 virtual_y = virtual_y - 97;
 
 // transform the virtual board value into a real screen coordinate
 real_x = 10 + virtual_x * 20;
 real_y = 10 + virtual_y * 20;
 
 // return an array with the points
 var theResult = {
   x: real_x,
   y: real_y
 }
 return theResult;

}

Now I can draw the game pieces with the canvas  x,y screen point provided by sgfToXy. I can also get the piece color from the B or W character in the move:

//draws the move (in sgf format) on the game board
function drawPiece(theMove)
{
 // first convert the move into an actual location to draw the piece
 var theConvertedValue = sgfToXy(theMove);
 
 // figure out the color of the piece
 if(theMove.charAt(1)== "B")
 {
  theColor = "black";
 } else
 {
  theColor = "white";
 }
 
 // use jCanvas to draw the piece
 $("canvas").drawArc({
    fillStyle: theColor,
    strokeWidth: 1,
    x: theConvertedValue.x, y: theConvertedValue.y,
    radius: 10
  });
}

In order to see the moves on the board, I created a button with a small onClick event handler. Here's the HTML I added to go.html:

<button onclick="drawNextMove()">Next Move</button>

And here's the actual event handler:

function drawNextMove()
{
 var theMove = theGame.getNextMove();
 drawPiece(theMove);
}

So at the end of this, what I have is a simple board and a button:



Looking over the code at this point, it's apparent the board should also be its own object as well. In the next post I'll tidy up the board code so it's its own object. I'll also make some other changes so it will be re-sizable, etc.

Following that, I wanted to experiment with using HTML5's offline storage. With 5 MB of storage and the average Go game taking up about 10K, it should be possible to store around 500 commented games!

Saturday, December 17, 2011

Drawing a Game Board with jCanvas and HTML5

I had been learning recently about the HTML5 Canvas and its JavasScript API's. It was a lot of fun playing around with it, but the API's were pretty low-level. So I was really happy when I found a great jQuery plugin that supported the canvas tag - jCanvas !

I thought I'd share what I learned about jCanvas by giving an example of how I learned to use it in drawing out a Go game board.

Step 1 - Create the Canvas

This file go.html is just plain-vanilla HTML5 markup to provide the canvas to draw on.

<!doctype html>
<head>
     <meta charset="utf-8" />

 <script src="jquery.min.js"></script>
 <script src="jcanvas.min.js"></script>
 <script src="go.js"></script>

        <title>HTML5 Go Board</title>
</head>
<body>
 <canvas width="400" height="400" id="goBoard">
  <p>This example requires a browser that supports the
  HTML5 canvas.</p>
 </canvas>
</body>

Step 2 - Draw the Board Background

The file go.js has the code for drawing the game board on the canvas. The first step was to give the board a wood-grain background. This jCanvas code selects the canvas tag, and then draws the image "board.jpg" at the point (10,10) on the canvas.

One interesting part here is that since it takes a while to load the image, and I want the image to be drawn first, I use the load property to set a callback. Essentially what this is doing is saying "Go ahead and draw this image, and when you're done call the function drawBoardLines( )".

When I left this out initially, the image kept showing up on top of everything else because all of the other operations would complete before the image loaded :-(

 // load the image first 
 $("canvas").drawImage({
   source: "board.jpg",
   x: 10, y: 10,
   width: 360,
     height: 360,
          fromCenter: false,
          load: drawBoardLines //after image is loaded draw the lines on top
 });

Step 3 - Draw the Edge


The next part is just a simple border for the game board. You can either use strokeStyle to create just a rectangular outline or fillStyle for a filled shape. I thought it was cool that the canvas supports rounded corners so I took advantage of the cornerRadius property to round them off a bit.

// draw the border
 $("canvas").drawRect({
   strokeStyle: "#000",
   x: 0, y: 0,
   width: 380,
   height: 380,
   fromCenter: false,
   cornerRadius: 5
 });

Step 4 - Draw the Lines


The next part was drawing the actual board lines. The Go board is a simple grid of 19 x 19 lines. jCanvas made it super easy to draw the lines by just specifying the beginning and ending points of each line inside two loops.

 // draw horizontal lines
 for(i=0; i<19; i++)
 {
  var px1 = 10;
  var px2 = 370;
  var py1 = (i * 20) + 10;

  $("canvas").drawLine({
    strokeStyle: "#000",
    strokeWidth: 2,
    x1: px1, y1: py1,
    x2: px2, y2: py1
  });
 }

 // draw vertical lines
 for(i=0; i<19; i++)
 {
  var px1 = (i * 20) + 10;
  var py1 = 10;
  var py2 = 370;

  $("canvas").drawLine({
    strokeStyle: "#000",
    strokeWidth: 1,
    x1: px1, y1: py1,
    x2: px1, y2: py2
  });
 }

Step 5 - Draw the Star Points


One unusual feature about the go board is a set of 9 points it uses for handicapping. These are tiny black circles called star points. Interestingly, the HTML5 canvas forces you to draw a 360 degree arc if you want a circle. The nice thing about jCanvas's drawArc is that it defaults to 360 degrees which makes drawing circles simple.


 // draw starpoints
 for(i=0; i<3; i++)
 {
  var px = (i*120) + 70;

  for(j=0; j<3; j++)
  {
   
   var py = (j*120) + 70;

   $("canvas").drawArc({
     strokeStyle: "#000",
     strokeWidth: 5,
     x: px, y: py,
     radius: 2
   });
  }
 }


Step 6 - Putting it All Together


When I put all of the JavaScript code together it looked like this:
// wait until the page is loaded to draw the board
$(document).ready(function()
{
 drawBoard();
});

// this function just draws the background
function drawBoard()
{
 // load the image first 
 $("canvas").drawImage({
   source: "board.jpg",
   x: 10, y: 10,
   width: 360,
     height: 360,
          fromCenter: false,
          load: drawBoardLines //after image loads, this callback draws the lines on top
 });
}

// this function draws the lines on top of the board image
function drawBoardLines()
{
 // draw the border
 $("canvas").drawRect({
   strokeStyle: "#000",
   x: 0, y: 0,
   width: 380,
   height: 380,
   fromCenter: false,
   cornerRadius: 5
 });

 // draw horizontal lines
 for(i=0; i<19; i++)
 {
  var px1 = 10;
  var px2 = 370;
  var py1 = (i * 20) + 10;

  $("canvas").drawLine({
    strokeStyle: "#000",
    strokeWidth: 2,
    x1: px1, y1: py1,
    x2: px2, y2: py1
  });
 }

 // draw vertical lines
 for(i=0; i<19; i++)
 {
  var px1 = (i * 20) + 10;
  var py1 = 10;
  var py2 = 370;

  $("canvas").drawLine({
    strokeStyle: "#000",
    strokeWidth: 1,
    x1: px1, y1: py1,
    x2: px1, y2: py2
  });
 }

 // draw starpoints
 for(i=0; i<3; i++)
 {
  var px = (i*120) + 70;

  for(j=0; j<3; j++)
  {
   
   var py = (j*120) + 70;

   $("canvas").drawArc({
     strokeStyle: "#000",
     strokeWidth: 5,
     x: px, y: py,
     radius: 2
   });
  }
 }
}

I named the file go.js and I put it in the same directory as go.html from Step 1. Next I downloaded jQuery and jCanvas and added those libraries to the directory. And finally, I created an image for the board, and put that in the same directory, too.



Then once I loaded go.html into my browser I saw: