Inference

Telling you how we see the world.

A Sliding Puzzle While You Wait

Posted by Jay on Apr 24th, 2010

One of the issues we have had with Cadmus is that the first time you sign in or if you sign in after a while you would need to wait a bit before we show you your updates. On an average it takes around a minute to process your Twitter stream. We are working on ways to improve that but in the meanwhile we wanted to do something to improve the user experience during that delay.

We decided to add in a game that users could play around with while they waited for the process to complete. Inspired by the pong preloaders on some of the console games and the Highrise Tic-Tac-Toe setup game we set out to build one of our own. I looked at the various options and settled on the Sliding Puzzles since it was moderately difficult to play, relatively simple to build and easy to brand! The result is a fun to play 9-piece sliding puzzle that uses the Cadmus logo as the image.

puzzle

The puzzle was intended only for new users and users that have been inactive for a while but it was so fun to test/play; I decided to make it available for existing users as well. You can check it out @ http://thecadmus.com/?puzzle. You need to be logged in before visiting that URL.

The Details

Lets dive right into some the things that I used to build the puzzle. Firstly the puzzle image which is a single image of the Cadmus logo. I wanted each of the pieces in the puzzle to seem like a piece on a board. Meaning it needed to have a shadow to give a feel that it is sitting on top of the board. I did this by using the CSS3 box-shadow property and the rgba properties to give the effect of a shadow.

div.puzzle div.piece {
	width: 100px;
	height: 100px;
	background: transparent url(puzzle-image.png) no-repeat top left;
	position: absolute;
	cursor: pointer;
	box-shadow: 1px 1px rgba(0, 0, 0, 0.26);
	-moz-box-shadow: 1px 1px rgba(0, 0, 0, 0.26);
	-webkit-box-shadow: 1px 1px rgba(0, 0, 0, 0.26);
}
div.puzzle div.piece-0 {
	background-position: 0 0;
}
div.puzzle div.piece-1 {
	background-position: -100px 0;
}
...

The second part of creating the puzzle was the board itself. As with all the other elements it is important that it fits in with the rest of the application. I went with the look where the board is cut into the canvas because it reminds me of how most sliding puzzles are in reality. They are usually set into the surface so the pieces don’t slide off the board.

Picture 6

The grid within the board are also cutting further into the board to give a really crisp feel to the whole thing. Lets look at the effects used to create the board in a little more detail.

board

  1. A 1 pixel stroke on the outside of the board that is lighter than the background giving the impression that the board is set into the canvas. There is also an inner shadow on the board to further the effect. It is a matter of playing around with these effects to figure out how much the board is cut into the canvas.
  2. The texture and color of the board is different from the texture of the canvas to give you the feel that there is something underneath the canvas. I used a layer of noise and a layer of the Gray Granite texture in Photoshop to create it. My general rule of thumb with textures is that they should be noisy but not too noisy. It means that it should be noisy enough to give you the feel of the texture but not too noisy that you see the Photoshop layer effects instead of the texture itself.
  3. There is also a slight inner glow to further the effect of the shadow the canvas casts on the board.
  4. The grid is three 1 pixel lines; the two outer ones are white and the inner one is black in color. The three lines have 13%, 45% and 43% opacity respectively. The values would differ depending on the background but it is important to remember that it is the third line’s job to highlight the second one. The effect does not work if they don’t play well together.
  5. Finally, there is a slight gradient across the whole board that is darker at the top and lighter at the bottom. Again, further adding to the effect that the board is cut into the canvas.

The final part of creating the puzzle is the JS portion of it. Most of it is really straight forward; I have an array representation of the board, an array of possible moves for each position and an array of CSS left and top values for each position. And so every time a piece is clicked the following function runs.

'onPieceClick': function(e, el, args) {
	var from = this.getPositionForPiece(args.position),
	to = this.getAvailableMove(from);
 
	return (to === null)
		? this
		: this
			.stopMoveAnimation()
			.setCurrentPieceEl(args.el)
			.movePiece(args.position, args.el, from, to)
			.checkStatus();
},

We find the position given the piece number (pieces are numbered 0-8) and find the available moves given the current position. If there is a move then we stop any current animations (the last piece could still be sliding into place), save a reference to the current piece, move the piece and check the status of the board to see if the puzzle has been solved.

To start the game we need to randomize the board. But a number of possible positions for this puzzle are unsolvable. So I wrote up this function that shuffles the pieces along in a similar manner a user would click around the board to shuffle it up.

'shufflePiece': function(i, position, lastPosition) {
	if (i > 0) {
		var from = this.getRandomExcept(
			this.movesList[position],
			this.getExcludeList(lastPosition)
		),
		piece = this.getPieceForPosition(from);
 
		return this.movePiece(
			piece,
			this.getPieceEl(piece),
			from,
			position,
			function() {
				return this.shufflePiece(i - 1, from, position);
			}
		);
	}
 
	return (this.isSolved())
		? this.shufflePiece(this.shuffleCount, 9, null)
		: this.startGame();
},
...
this.shufflePiece(this.shuffleCount, 9, null);
...

I get the available moves for the given empty position in the board and I also exclude the previous empty position since I don’t want the randomizer to pick the previous move. This function calls itself as it shuffles every move. I start it off by passing in the number of times I want it shuffled and the first empty position on the board. Now at the end of all the shuffling I might end up right where I started so I have a simple check that restarts the shuffling if that happens. A better approach would be to calculate the distance of the shuffled state from the solved state and set a lower limit on that.

The entire code for the game is actually quite small and it was relatively simple to implement (not to mention fun to test). We will keep an eye on how this impacts the experience for a new user and see if it actually helps.

By going into the different aspects (CSS, Photoshop and JS) of building this feature, I am hoping it would help others venture out into areas that they have been previously shying away from.

Notes

If you have any questions or would like me to go into further detail; just let me know on Twitter.

Also, check out the 37signals post about the Tic-Tac-Toe game in their Highrise iPhone app.

Share

Please do share this on .

Thanks for all the mentions

Posted by Jay on Apr 11th, 2010

Just wanted to make a quick post about the press Cadmus has gotten recently.

The Tweet House panel at SXSW with @brian_wong, @scobleizer, @markmilian, @domLink (around 13:07)

Opening up opportunity with Twitter at Mix10 by @rsarver and @raffiLink (around 20:39)

A Cinchcast with @louisgrayLink

With @scobleizer at the Palo Alto Apple Store – Link

Thanks guys!

Anomaly Follow us on Twitter Contact us via Email