Do you like my tutorials?

Then consider supporting me on Ko-fi

Talking about Threes game, Game development and Javascript.

Did you play Threes or one of its “inspired-by” games like 1024 or 2048?

There is a grid filled with numbers, and you have to make them slide up, down, left and right. If two numbers with the same value get in touch, they merge into a new number which is the sum of previous number.

Have a look at the free 2048 game to see what I mean.

Here you will find a jQuery only version of 2048 using only sliding «div»s to make it work – I did not even use an array to store grid information – with only a different way to calculate the score and the “combo” feature: placing three “two”s in a row won’t give you a “4” and a “2” but an “8”. A smart way to quickly get higher numbers.

Try the game:

Slide numbers with WASD keys. What’s your best score?

And this is the jQuery only source code:

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="utf-8">
  	<script src  = "https://code.jquery.com/jquery-2.1.0.min.js"></script>
  	<script>
  		var animSpeed = 200;
  		var canMove=false;
  		$(document).ready(function(){
			$('body').append('<div id = "boardcontainer"></div>');
			for(i=0;i<4;i++){
				for(j=0;j<4;j++){
					$('#boardcontainer').append('<div class = "boardtile emptytile" data-row="'+i+'" data-col="'+j+'"></div>');
				}
				$('#boardcontainer').append('<div style = "clear:both"></div>');
			}
			$('body').append('<div id = "scorediv"></div>');
			newTwo();
			newTwo();			  
		});
		
		$(document).keypress(function(event){
			if(canMove){
				canMove=false; 
				somethingMoved=false;
				switch(event.keyCode){
					case 97:
						$('.tile').sort(function(a,b){
							var attrA = $(a).attr('data-col');
							var attrB = $(b).attr('data-col');
							if(attrA>attrB){
								return 1;
							}		
							if(attrA<attrB){
								return -1;
							}
							return 0;
						}).each(function(){
							var currentCol = parseInt($(this).attr('data-col'));
							var currentRow = parseInt($(this).attr('data-row'));
							var destination = currentCol;
							$(this).attr('data-destroy',0)
							if(currentCol>0){
								for(i=currentCol-1;i>=0;i--){
									if($('.boardtile[data-col='+i+'][data-row='+currentRow+']').hasClass('fulltile')){
										if($(this).html()==$('.tile[data-col='+i+'][data-row='+currentRow+']').html()){
											$(this).attr('data-destroy',1)
											destination = i;
										}
										break;
									}
									else{
										destination = i 
									}
								}
								if(currentCol!=destination){
									somethingMoved=true;
								}
								$(this).animate({
									left: '-='+(116*(currentCol-destination))
								},animSpeed,function(){
									if($(this).attr('data-destroy')==1){
										$('.tile[data-col='+destination+'][data-row='+currentRow+']').html(parseInt($(this).html()*2));
										$(this).remove();
									}
								});
								$('.boardtile[data-col='+currentCol+'][data-row='+currentRow+']').removeClass('fulltile').addClass('emptytile');
								$(this).attr('data-col',destination);
								$('.boardtile[data-col='+destination+'][data-row='+currentRow+']').removeClass('emptytile').addClass('fulltile');
											
							}
						});
						break;
					case 100:
						$('.tile').sort(function(a,b){
							var attrA = $(a).attr('data-col');
							var attrB = $(b).attr('data-col');
							if(attrA>attrB){
								return -1;
							}		
							if(attrA<attrB){
								return 1;
							}
							return 0;
						}).each(function(){
							var currentCol = parseInt($(this).attr('data-col'));
							var currentRow = parseInt($(this).attr('data-row'));
							var destination = currentCol;
							$(this).attr('data-destroy',0)
							if(currentCol<4){
								for(i=currentCol+1;i<=3;i++){
									if($('.boardtile[data-col='+i+'][data-row='+currentRow+']').hasClass('fulltile')){
										if($(this).html()==$('.tile[data-col='+i+'][data-row='+currentRow+']').html()){
											$(this).attr('data-destroy',1)
											destination = i;
										}
										break;
									}
									else{
										destination = i 
									}
								}
								if(currentCol!=destination){
									somethingMoved=true;
								}
								$(this).animate({
									left: '+='+(116*(destination-currentCol))
								},animSpeed,function(){
									if($(this).attr('data-destroy')==1){
										$('.tile[data-col='+destination+'][data-row='+currentRow+']').html(parseInt($(this).html()*2));
										$(this).remove();
									}	
								});
								$('.boardtile[data-col='+currentCol+'][data-row='+currentRow+']').removeClass('fulltile').addClass('emptytile');
								$(this).attr('data-col',destination);
								$('.boardtile[data-col='+destination+'][data-row='+currentRow+']').removeClass('emptytile').addClass('fulltile');
							}
						})
						break;
					case 119:
						$('.tile').sort(function(a,b){
							var attrA = $(a).attr('data-row');
							var attrB = $(b).attr('data-row');
							if(attrA>attrB){
								return 1;
							}		
							if(attrA<attrB){
								return -1;
							}
							return 0;
						}).each(function(){
							var currentCol = parseInt($(this).attr('data-col'));
							var currentRow = parseInt($(this).attr('data-row'));
							var destination = currentRow;
							$(this).attr('data-destroy',0)
							if(currentRow>0){
								for(i=currentRow-1;i>=0;i--){
									if($('.boardtile[data-col='+currentCol+'][data-row='+i+']').hasClass('fulltile')){
										if($(this).html()==$('.tile[data-col='+currentCol+'][data-row='+i+']').html()){
											$(this).attr('data-destroy',1)
											destination = i;
										}
										break;
									}
									else{
										destination = i 
									}
								}
								if(destination!=currentRow){
									somethingMoved=true;
								}
								$(this).animate({
									top: '-='+(116*(currentRow-destination))
								},animSpeed,function(){
									if($(this).attr('data-destroy')==1){
										$('.tile[data-col='+currentCol+'][data-row='+destination+']').html(parseInt($(this).html()*2));
										$(this).remove();
									}
								});
								$('.boardtile[data-col='+currentCol+'][data-row='+currentRow+']').removeClass('fulltile').addClass('emptytile');
								$(this).attr('data-row',destination);
								$('.boardtile[data-col='+currentCol+'][data-row='+destination+']').removeClass('emptytile').addClass('fulltile');		
							}
						})
						break;
					case 115:
						$('.tile').sort(function(a,b){
							var attrA = $(a).attr('data-row');
							var attrB = $(b).attr('data-row');
							if(attrA>attrB){
								return -1;
							}		
							if(attrA<attrB){
								return 1;
							}
							return 0;
						}).each(function(){
							var currentCol = parseInt($(this).attr('data-col'));
							var currentRow = parseInt($(this).attr('data-row'));
							var destination = currentRow;
							$(this).attr('data-destroy',0);
							if(currentRow<4){
								for(i=currentRow+1;i<=3;i++){
									if($('.boardtile[data-col='+currentCol+'][data-row='+i+']').hasClass('fulltile')){
										if($(this).html()==$('.tile[data-col='+currentCol+'][data-row='+i+']').html()){
											$(this).attr('data-destroy',1)
											destination = i;
										}
										break;
									}
									else{
										destination = i 
									}
								}
								if(destination!=currentRow){
									somethingMoved=true;
								}
									$(this).animate({
										top: '+='+(116*(destination-currentRow))
									},animSpeed,function(){
										if($(this).attr('data-destroy')==1){
											$('.tile[data-col='+currentCol+'][data-row='+destination+']').html(parseInt($(this).html()*2));
											$(this).remove();
										}
									});
									$('.boardtile[data-col='+currentCol+'][data-row='+currentRow+']').removeClass('fulltile').addClass('emptytile');
									$(this).attr('data-row',destination);
									$('.boardtile[data-col='+currentCol+'][data-row='+destination+']').removeClass('emptytile').addClass('fulltile');		
							}
						})
						break;
				}
				if(somethingMoved){
					newTwo();
				}
				else{
					canMove=true;
				}
			}
		});
		
		function newTwo(){
			var emptyTiles = $('.emptytile').length;
			var randomTwo = Math.floor(Math.random()*emptyTiles);
			var tile = $('.emptytile').eq(randomTwo);
			$(tile).removeClass('emptytile');
			$(tile).addClass('fulltile');
			var tilePosition = $(tile).position();
			$('#boardcontainer').append('<div id = "lastadded" class = "tile" data-row="'+$(tile).attr('data-row')+'" data-col="'+$(tile).attr('data-col')+'">2</div>')
			$('#lastadded').css({top:(tilePosition.top+8)+'px',left:(tilePosition.left+8)+'px'})
			$('#lastadded').fadeTo(animSpeed*3,1,function(){
				canMove=true;
				showScore();
			})
			$('#lastadded').attr('id','');
		}
		
		function showScore(){
			var score = 0;
			$('.tile').sort(function(a,b){
				var attrA = parseInt($(a).html());
				var attrB = parseInt($(b).html());
				if(attrA>attrB){
					return -1;
				}		
				if(attrA<attrB){
					return 1;
				}
				return 0;
			}).each(function(){
				score = score+parseInt($(this).html());
			}); 
			score*=parseInt($('.tile').first().html());
			score *=0.5;
			$('#scorediv').html('Your score: '+score);    
		}
		
  	</script>
  	<style>
  		body{
			margin:0px;
			background-color:#F9F3E3;  
		}
		#boardcontainer{
			border:8px solid #D78B7D;
			width:464px;
			margin:0px auto;
			position:relative;
		}
  		.boardtile{
			width:100px;
			height:100px;
			border:8px solid #D78B7D; 
			float:left; 	
		}
		.tile{
			width:100px;
			height:65px;
			background-color:#CFC8B5;
			z-index:50;
			position:absolute;
			top:0px;
			left:0px;
			text-align:center;                                   
			display:none;
			font:bold 24px arial;
			color:#5C5B57;
			padding-top:35px;
		}
		#scorediv{
			margin:5px;
			text-align:center;
			font:bold 48px arial;
			color:#CFC8B5;
		}
		
  	</style>
</head>
<body>
</body>
</html>

I did not include any comment because a jQuery only game is just an exercise. Soon I will show you how to make an HTML5 version of the game with some popular framework, and you’ll get commented code.

Meanwhile you can download the source code of the game.

Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.