/**** 
* Classes
****/
var Tile = Container.expand(function (value) {
	var self = Container.call(this);
	self.alpha = 0;
	var fadeIn = function fadeIn() {
		if (self.alpha < 1) {
			self.alpha = Math.min(self.alpha + 0.24, 1);
			self.scale.set(self.alpha);
			LK.setTimeout(fadeIn, 16.67);
		} else {
			self.alpha = 1;
			self.scale.set(1);
		}
	};
	fadeIn();
	self.value = value || 2;
	var tileGraphics = self.attachAsset('tile', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var hsvToRgb = function hsvToRgb(h, s, v) {
		var r, g, b;
		var i = Math.floor(h * 6);
		var f = h * 6 - i;
		var p = v * (1 - s);
		var q = v * (1 - f * s);
		var t = v * (1 - (1 - f) * s);
		switch (i % 6) {
			case 0:
				r = v, g = t, b = p;
				break;
			case 1:
				r = q, g = v, b = p;
				break;
			case 2:
				r = p, g = v, b = t;
				break;
			case 3:
				r = p, g = q, b = v;
				break;
			case 4:
				r = t, g = p, b = v;
				break;
			case 5:
				r = v, g = p, b = q;
				break;
		}
		return (Math.round(r * 255) << 16) + (Math.round(g * 255) << 8) + Math.round(b * 255);
	};
	self.setTint = function () {
		var hue = (Math.log2(self.value) + 6) % 20 / 20;
		tileGraphics.tint = hsvToRgb(hue, 0.3, 1);
	};
	self.setTint();
	var tileLabel = new Text2(self.value.toString(), {
		size: 300,
		fill: '#332d28',
		font: 'Sans-Serif',
		weight: '800',
		strokeThickness: 0
	});
	tileLabel.anchor.set(0.5, 0.5);
	tileLabel.x = 0;
	tileLabel.y = -40;
	self.addChild(tileLabel);
	self.setValue = function (value) {
		self.newValue = value;
	};
	self.updateToRealValue = function () {
		if (self.newValue) {
			self.value = self.newValue;
			tileLabel.setText(self.value.toString());
			var textScale = Math.min(1, 350 / (tileLabel.width / tileLabel.scale.x));
			tileLabel.scale.set(textScale);
			self.setTint();
			self.newValue = null;
			self.scale.set(1.2);
			var scaleDown = function scaleDown() {
				if (self.scale.x > 1) {
					self.scale.x -= 0.02;
					self.scale.y -= 0.02;
					LK.setTimeout(scaleDown, 16.67);
				} else {
					self.scale.set(1);
				}
			};
			scaleDown();
		}
	};
	self.targetX = 0;
	self.targetY = 0;
	self.isMoving = false;
	self.merged = false;
	self.setPosition = function (x, y, instant) {
		self.targetX = x * 500 + 250;
		self.targetY = y * 500 + 250;
		if (instant) {
			self.x = self.targetX;
			self.y = self.targetY;
		}
	};
	self.move = function () {
		var dx = self.targetX - self.x;
		var dy = self.targetY - self.y;
		var distance = Math.sqrt(dx * dx + dy * dy);
		if (distance > 150) {
			self.isMoving = true;
			self.x += dx / distance * 150;
			self.y += dy / distance * 150;
			return false;
		}
		self.isMoving = false;
		self.x = self.targetX;
		self.y = self.targetY;
		return true;
	};
});
/**** 
* Initialize Game
****/
var game = new LK.Game({
	backgroundColor: 0x000000
});
/**** 
* Game Code
****/
game.checkPossibleMoves = function () {
	for (var i = 0; i < gridSize; i++) {
		for (var j = 0; j < gridSize; j++) {
			if (squares[i][j] === null) {
				return true;
			}
			if (i < gridSize - 1 && squares[i][j] !== null && squares[i + 1][j] !== null && squares[i][j].value === squares[i + 1][j].value) {
				return true;
			}
			if (j < gridSize - 1 && squares[i][j] !== null && squares[i][j + 1] !== null && squares[i][j].value === squares[i][j + 1].value) {
				return true;
			}
		}
	}
	return false;
};
var scoreTxt = new Text2('2', {
	size: 220,
	fill: '#000000',
	font: 'Impact',
	strokeThickness: 0
});
scoreTxt.anchor.set(.5, 0);
LK.gui.topCenter.addChild(scoreTxt);
var tutorialTxt = new Text2('Swipe to merge & merge', {
	size: 120,
	fill: '#000000',
	font: 'Impact',
	strokeThickness: 0
});
tutorialTxt.anchor.set(.5, 1);
LK.gui.bottom.addChild(tutorialTxt);
tutorialTxt.y -= 30;
var toBeRemoved = [];
game.addRandomTile = function () {
	var emptyPositions = [];
	for (var i = 0; i < gridSize; i++) {
		for (var j = 0; j < gridSize; j++) {
			if (squares[i][j] === null) {
				emptyPositions.push({
					x: i,
					y: j
				});
			}
		}
	}
	if (emptyPositions.length > 0) {
		var randomPosition = emptyPositions[Math.floor(Math.random() * emptyPositions.length)];
		var square = new Tile(Math.random() < 0.5 ? 2 : 4);
		square.setPosition(randomPosition.x, randomPosition.y, true);
		squares[randomPosition.x][randomPosition.y] = square;
		gridContainer.addChild(square);
	}
};
game.mergeTiles = function (x1, y1, x2, y2) {
	if (squares[x1][y1] !== null && squares[x2][y2] !== null && squares[x1][y1].value === squares[x2][y2].value && !squares[x1][y1].merged && !squares[x2][y2].merged) {
		squares[x2][y2].setValue(squares[x2][y2].value * 2, true);
		squares[x2][y2].merged = true;
		squares[x1][y1].targetX = squares[x2][y2].targetX;
		squares[x1][y1].targetY = squares[x2][y2].targetY;
		toBeRemoved.push(squares[x1][y1]);
		squares[x1][y1] = null;
		gridContainer.removeChild(squares[x2][y2]);
		gridContainer.addChild(squares[x2][y2]);
		return true;
	}
	return false;
};
var gridSize = 4;
game.setBackgroundColor(0xD3D3D3);
var gridContainer = new Container();
gridContainer.x = 44;
gridContainer.y = 400;
game.addChild(gridContainer);
for (var i = 0; i < gridSize; i++) {
	for (var j = 0; j < gridSize; j++) {
		var gridTile = gridContainer.attachAsset('gridTile', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		gridTile.x = i * 500 + 250;
		gridTile.y = j * 500 + 250;
		gridTile.alpha = .1;
	}
}
var squares = new Array(gridSize).fill().map(function () {
	return new Array(gridSize).fill(null);
});
for (var i = 0; i < gridSize; i++) {
	for (var j = 0; j < gridSize; j++) {
		squares[i][j] = null;
	}
}
var initialTiles = 2;
for (var i = 0; i < initialTiles; i++) {
	var x, y;
	do {
		x = Math.floor(Math.random() * gridSize);
		y = Math.floor(Math.random() * gridSize);
	} while (squares[x][y] !== null);
	var square = new Tile();
	square.setPosition(x, y, true);
	square.alpha = 1;
	square.scale.set(1);
	squares[x][y] = square;
	gridContainer.addChild(square);
}
var swipeStart = {
	x: 0,
	y: 0
};
var swipeEnd = {
	x: 0,
	y: 0
};
var boardChanged = false;
var winMessageShown = false;
game.moveTiles = function (direction) {
	var dx = (direction === 'right') - (direction === 'left');
	var dy = (direction === 'down') - (direction === 'up');
	var moved = false;
	do {
		moved = false;
		var iStart = dx > 0 ? gridSize - 1 : 0;
		var iEnd = dx > 0 ? -1 : gridSize;
		var iStep = dx > 0 ? -1 : 1;
		var jStart = dy > 0 ? gridSize - 1 : 0;
		var jEnd = dy > 0 ? -1 : gridSize;
		var jStep = dy > 0 ? -1 : 1;
		for (var i = iStart; i !== iEnd; i += iStep) {
			for (var j = jStart; j !== jEnd; j += jStep) {
				var x = i + dx;
				var y = j + dy;
				if (x >= 0 && x < gridSize && y >= 0 && y < gridSize && squares[i][j] !== null) {
					if (squares[x][y] === null) {
						squares[x][y] = squares[i][j];
						squares[i][j] = null;
						squares[x][y].setPosition(x, y);
						moved = true;
						boardChanged = true;
					} else if (squares[x][y] !== null && squares[i][j] !== null && squares[x][y].value === squares[i][j].value) {
						moved = game.mergeTiles(i, j, x, y);
						if (moved) {
							boardChanged = true;
						}
					}
				}
			}
		}
	} while (moved);
	for (var i = 0; i < gridSize; i++) {
		for (var j = 0; j < gridSize; j++) {
			if (squares[i][j] !== null) {
				squares[i][j].merged = false;
			}
		}
	}
};
game.on('down', function (obj) {
	var anyTileMoving = squares.some(function (row) {
		return row.some(function (tile) {
			return tile && tile.isMoving;
		});
	});
	if (!anyTileMoving) {
		var pos = obj.event.getLocalPosition(game);
		swipeStart = {
			x: pos.x,
			y: pos.y
		};
	}
});
game.on('up', function (obj) {
	var pos = obj.event.getLocalPosition(game);
	swipeEnd = {
		x: pos.x,
		y: pos.y
	};
	var dx = swipeEnd.x - swipeStart.x;
	var dy = swipeEnd.y - swipeStart.y;
	var threshold = 50;
	if (Math.abs(dx) > threshold || Math.abs(dy) > threshold) {
		if (Math.abs(dx) > Math.abs(dy)) {
			if (dx > 0) {
				game.moveTiles('right');
			} else {
				game.moveTiles('left');
			}
		} else {
			if (dy > 0) {
				game.moveTiles('down');
			} else {
				game.moveTiles('up');
			}
		}
		if (tutorialTxt) {
			LK.gui.bottom.removeChild(tutorialTxt);
			tutorialTxt = null;
		}
	}
});
LK.on('tick', function () {
	var allTilesStopped = true;
	for (var i = 0; i < gridSize; i++) {
		for (var j = 0; j < gridSize; j++) {
			if (squares[i][j] !== null) {
				if (!squares[i][j].move()) {
					allTilesStopped = false;
				}
			}
		}
	}
	for (var i = 0; i < toBeRemoved.length; i++) {
		if (!toBeRemoved[i].move()) {
			allTilesStopped = false;
		} else {
			toBeRemoved[i].destroy();
			toBeRemoved.splice(i, 1);
			i--;
		}
	}
	if (allTilesStopped) {
		for (var i = 0; i < gridSize; i++) {
			for (var j = 0; j < gridSize; j++) {
				if (squares[i][j] !== null && squares[i][j].newValue) {
					squares[i][j].updateToRealValue();
					if (squares[i][j].value === 2048 && !winMessageShown) {
						var winMessage = new Text2('Congratulations\n you win!', {
							size: 150,
							fill: '#ffffff',
							font: 'Sans-Serif',
							weight: '800',
							stroke: '#000000',
							strokeThickness: 25,
							align: 'center'
						});
						winMessage.anchor.set(0.5, 0.5);
						LK.gui.center.addChild(winMessage);
						winMessageShown = true;
						LK.setTimeout(function () {
							LK.gui.center.removeChild(winMessage);
						}, 5000);
					}
				}
			}
		}
		if (boardChanged) {
			game.addRandomTile();
			boardChanged = false;
			var maxTileValue = Math.max.apply(Math, squares.map(function (row) {
				return Math.max.apply(Math, row.map(function (tile) {
					return tile ? tile.value : 0;
				}));
			}));
			var newScore = maxTileValue;
			LK.setScore(newScore);
			scoreTxt.setText(newScore.toString());
		}
		if (!game.checkPossibleMoves()) {
			for (var i = 0; i < gridSize; i++) {
				for (var j = 0; j < gridSize; j++) {
					if (squares[i][j] !== null) {
						squares[i][j].alpha = 1;
						squares[i][j].scale.set(1);
					}
				}
			}
			LK.showGameOver();
		}
	}
}); /**** 
* Classes
****/
var Tile = Container.expand(function (value) {
	var self = Container.call(this);
	self.alpha = 0;
	var fadeIn = function fadeIn() {
		if (self.alpha < 1) {
			self.alpha = Math.min(self.alpha + 0.24, 1);
			self.scale.set(self.alpha);
			LK.setTimeout(fadeIn, 16.67);
		} else {
			self.alpha = 1;
			self.scale.set(1);
		}
	};
	fadeIn();
	self.value = value || 2;
	var tileGraphics = self.attachAsset('tile', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var hsvToRgb = function hsvToRgb(h, s, v) {
		var r, g, b;
		var i = Math.floor(h * 6);
		var f = h * 6 - i;
		var p = v * (1 - s);
		var q = v * (1 - f * s);
		var t = v * (1 - (1 - f) * s);
		switch (i % 6) {
			case 0:
				r = v, g = t, b = p;
				break;
			case 1:
				r = q, g = v, b = p;
				break;
			case 2:
				r = p, g = v, b = t;
				break;
			case 3:
				r = p, g = q, b = v;
				break;
			case 4:
				r = t, g = p, b = v;
				break;
			case 5:
				r = v, g = p, b = q;
				break;
		}
		return (Math.round(r * 255) << 16) + (Math.round(g * 255) << 8) + Math.round(b * 255);
	};
	self.setTint = function () {
		var hue = (Math.log2(self.value) + 6) % 20 / 20;
		tileGraphics.tint = hsvToRgb(hue, 0.3, 1);
	};
	self.setTint();
	var tileLabel = new Text2(self.value.toString(), {
		size: 300,
		fill: '#332d28',
		font: 'Sans-Serif',
		weight: '800',
		strokeThickness: 0
	});
	tileLabel.anchor.set(0.5, 0.5);
	tileLabel.x = 0;
	tileLabel.y = -40;
	self.addChild(tileLabel);
	self.setValue = function (value) {
		self.newValue = value;
	};
	self.updateToRealValue = function () {
		if (self.newValue) {
			self.value = self.newValue;
			tileLabel.setText(self.value.toString());
			var textScale = Math.min(1, 350 / (tileLabel.width / tileLabel.scale.x));
			tileLabel.scale.set(textScale);
			self.setTint();
			self.newValue = null;
			self.scale.set(1.2);
			var scaleDown = function scaleDown() {
				if (self.scale.x > 1) {
					self.scale.x -= 0.02;
					self.scale.y -= 0.02;
					LK.setTimeout(scaleDown, 16.67);
				} else {
					self.scale.set(1);
				}
			};
			scaleDown();
		}
	};
	self.targetX = 0;
	self.targetY = 0;
	self.isMoving = false;
	self.merged = false;
	self.setPosition = function (x, y, instant) {
		self.targetX = x * 500 + 250;
		self.targetY = y * 500 + 250;
		if (instant) {
			self.x = self.targetX;
			self.y = self.targetY;
		}
	};
	self.move = function () {
		var dx = self.targetX - self.x;
		var dy = self.targetY - self.y;
		var distance = Math.sqrt(dx * dx + dy * dy);
		if (distance > 150) {
			self.isMoving = true;
			self.x += dx / distance * 150;
			self.y += dy / distance * 150;
			return false;
		}
		self.isMoving = false;
		self.x = self.targetX;
		self.y = self.targetY;
		return true;
	};
});
/**** 
* Initialize Game
****/
var game = new LK.Game({
	backgroundColor: 0x000000
});
/**** 
* Game Code
****/
game.checkPossibleMoves = function () {
	for (var i = 0; i < gridSize; i++) {
		for (var j = 0; j < gridSize; j++) {
			if (squares[i][j] === null) {
				return true;
			}
			if (i < gridSize - 1 && squares[i][j] !== null && squares[i + 1][j] !== null && squares[i][j].value === squares[i + 1][j].value) {
				return true;
			}
			if (j < gridSize - 1 && squares[i][j] !== null && squares[i][j + 1] !== null && squares[i][j].value === squares[i][j + 1].value) {
				return true;
			}
		}
	}
	return false;
};
var scoreTxt = new Text2('2', {
	size: 220,
	fill: '#000000',
	font: 'Impact',
	strokeThickness: 0
});
scoreTxt.anchor.set(.5, 0);
LK.gui.topCenter.addChild(scoreTxt);
var tutorialTxt = new Text2('Swipe to merge & merge', {
	size: 120,
	fill: '#000000',
	font: 'Impact',
	strokeThickness: 0
});
tutorialTxt.anchor.set(.5, 1);
LK.gui.bottom.addChild(tutorialTxt);
tutorialTxt.y -= 30;
var toBeRemoved = [];
game.addRandomTile = function () {
	var emptyPositions = [];
	for (var i = 0; i < gridSize; i++) {
		for (var j = 0; j < gridSize; j++) {
			if (squares[i][j] === null) {
				emptyPositions.push({
					x: i,
					y: j
				});
			}
		}
	}
	if (emptyPositions.length > 0) {
		var randomPosition = emptyPositions[Math.floor(Math.random() * emptyPositions.length)];
		var square = new Tile(Math.random() < 0.5 ? 2 : 4);
		square.setPosition(randomPosition.x, randomPosition.y, true);
		squares[randomPosition.x][randomPosition.y] = square;
		gridContainer.addChild(square);
	}
};
game.mergeTiles = function (x1, y1, x2, y2) {
	if (squares[x1][y1] !== null && squares[x2][y2] !== null && squares[x1][y1].value === squares[x2][y2].value && !squares[x1][y1].merged && !squares[x2][y2].merged) {
		squares[x2][y2].setValue(squares[x2][y2].value * 2, true);
		squares[x2][y2].merged = true;
		squares[x1][y1].targetX = squares[x2][y2].targetX;
		squares[x1][y1].targetY = squares[x2][y2].targetY;
		toBeRemoved.push(squares[x1][y1]);
		squares[x1][y1] = null;
		gridContainer.removeChild(squares[x2][y2]);
		gridContainer.addChild(squares[x2][y2]);
		return true;
	}
	return false;
};
var gridSize = 4;
game.setBackgroundColor(0xD3D3D3);
var gridContainer = new Container();
gridContainer.x = 44;
gridContainer.y = 400;
game.addChild(gridContainer);
for (var i = 0; i < gridSize; i++) {
	for (var j = 0; j < gridSize; j++) {
		var gridTile = gridContainer.attachAsset('gridTile', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		gridTile.x = i * 500 + 250;
		gridTile.y = j * 500 + 250;
		gridTile.alpha = .1;
	}
}
var squares = new Array(gridSize).fill().map(function () {
	return new Array(gridSize).fill(null);
});
for (var i = 0; i < gridSize; i++) {
	for (var j = 0; j < gridSize; j++) {
		squares[i][j] = null;
	}
}
var initialTiles = 2;
for (var i = 0; i < initialTiles; i++) {
	var x, y;
	do {
		x = Math.floor(Math.random() * gridSize);
		y = Math.floor(Math.random() * gridSize);
	} while (squares[x][y] !== null);
	var square = new Tile();
	square.setPosition(x, y, true);
	square.alpha = 1;
	square.scale.set(1);
	squares[x][y] = square;
	gridContainer.addChild(square);
}
var swipeStart = {
	x: 0,
	y: 0
};
var swipeEnd = {
	x: 0,
	y: 0
};
var boardChanged = false;
var winMessageShown = false;
game.moveTiles = function (direction) {
	var dx = (direction === 'right') - (direction === 'left');
	var dy = (direction === 'down') - (direction === 'up');
	var moved = false;
	do {
		moved = false;
		var iStart = dx > 0 ? gridSize - 1 : 0;
		var iEnd = dx > 0 ? -1 : gridSize;
		var iStep = dx > 0 ? -1 : 1;
		var jStart = dy > 0 ? gridSize - 1 : 0;
		var jEnd = dy > 0 ? -1 : gridSize;
		var jStep = dy > 0 ? -1 : 1;
		for (var i = iStart; i !== iEnd; i += iStep) {
			for (var j = jStart; j !== jEnd; j += jStep) {
				var x = i + dx;
				var y = j + dy;
				if (x >= 0 && x < gridSize && y >= 0 && y < gridSize && squares[i][j] !== null) {
					if (squares[x][y] === null) {
						squares[x][y] = squares[i][j];
						squares[i][j] = null;
						squares[x][y].setPosition(x, y);
						moved = true;
						boardChanged = true;
					} else if (squares[x][y] !== null && squares[i][j] !== null && squares[x][y].value === squares[i][j].value) {
						moved = game.mergeTiles(i, j, x, y);
						if (moved) {
							boardChanged = true;
						}
					}
				}
			}
		}
	} while (moved);
	for (var i = 0; i < gridSize; i++) {
		for (var j = 0; j < gridSize; j++) {
			if (squares[i][j] !== null) {
				squares[i][j].merged = false;
			}
		}
	}
};
game.on('down', function (obj) {
	var anyTileMoving = squares.some(function (row) {
		return row.some(function (tile) {
			return tile && tile.isMoving;
		});
	});
	if (!anyTileMoving) {
		var pos = obj.event.getLocalPosition(game);
		swipeStart = {
			x: pos.x,
			y: pos.y
		};
	}
});
game.on('up', function (obj) {
	var pos = obj.event.getLocalPosition(game);
	swipeEnd = {
		x: pos.x,
		y: pos.y
	};
	var dx = swipeEnd.x - swipeStart.x;
	var dy = swipeEnd.y - swipeStart.y;
	var threshold = 50;
	if (Math.abs(dx) > threshold || Math.abs(dy) > threshold) {
		if (Math.abs(dx) > Math.abs(dy)) {
			if (dx > 0) {
				game.moveTiles('right');
			} else {
				game.moveTiles('left');
			}
		} else {
			if (dy > 0) {
				game.moveTiles('down');
			} else {
				game.moveTiles('up');
			}
		}
		if (tutorialTxt) {
			LK.gui.bottom.removeChild(tutorialTxt);
			tutorialTxt = null;
		}
	}
});
LK.on('tick', function () {
	var allTilesStopped = true;
	for (var i = 0; i < gridSize; i++) {
		for (var j = 0; j < gridSize; j++) {
			if (squares[i][j] !== null) {
				if (!squares[i][j].move()) {
					allTilesStopped = false;
				}
			}
		}
	}
	for (var i = 0; i < toBeRemoved.length; i++) {
		if (!toBeRemoved[i].move()) {
			allTilesStopped = false;
		} else {
			toBeRemoved[i].destroy();
			toBeRemoved.splice(i, 1);
			i--;
		}
	}
	if (allTilesStopped) {
		for (var i = 0; i < gridSize; i++) {
			for (var j = 0; j < gridSize; j++) {
				if (squares[i][j] !== null && squares[i][j].newValue) {
					squares[i][j].updateToRealValue();
					if (squares[i][j].value === 2048 && !winMessageShown) {
						var winMessage = new Text2('Congratulations\n you win!', {
							size: 150,
							fill: '#ffffff',
							font: 'Sans-Serif',
							weight: '800',
							stroke: '#000000',
							strokeThickness: 25,
							align: 'center'
						});
						winMessage.anchor.set(0.5, 0.5);
						LK.gui.center.addChild(winMessage);
						winMessageShown = true;
						LK.setTimeout(function () {
							LK.gui.center.removeChild(winMessage);
						}, 5000);
					}
				}
			}
		}
		if (boardChanged) {
			game.addRandomTile();
			boardChanged = false;
			var maxTileValue = Math.max.apply(Math, squares.map(function (row) {
				return Math.max.apply(Math, row.map(function (tile) {
					return tile ? tile.value : 0;
				}));
			}));
			var newScore = maxTileValue;
			LK.setScore(newScore);
			scoreTxt.setText(newScore.toString());
		}
		if (!game.checkPossibleMoves()) {
			for (var i = 0; i < gridSize; i++) {
				for (var j = 0; j < gridSize; j++) {
					if (squares[i][j] !== null) {
						squares[i][j].alpha = 1;
						squares[i][j].scale.set(1);
					}
				}
			}
			LK.showGameOver();
		}
	}
});