/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var GridTile = Container.expand(function () {
var self = Container.call(this);
self.gridX = 0;
self.gridY = 0;
self.owner = 0; // 0 = empty, 1 = blue, 2 = red
self.isCastle = false;
self.tileGraphics = null;
self.init = function (gridX, gridY, owner, isCastle) {
self.gridX = gridX;
self.gridY = gridY;
self.owner = owner;
self.isCastle = isCastle;
var assetId = 'emptyTile';
if (isCastle && owner === 1) assetId = 'blueCastle';else if (isCastle && owner === 2) assetId = 'redCastle';else if (owner === 1) assetId = 'blueTile';else if (owner === 2) assetId = 'redTile';
if (self.tileGraphics) self.removeChild(self.tileGraphics);
self.tileGraphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
};
self.setOwner = function (newOwner) {
self.owner = newOwner;
var assetId = 'emptyTile';
if (newOwner === 1) assetId = 'blueTile';else if (newOwner === 2) assetId = 'redTile';
if (self.tileGraphics) self.removeChild(self.tileGraphics);
self.tileGraphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
};
self.highlight = function () {
if (self.tileGraphics) self.removeChild(self.tileGraphics);
self.tileGraphics = self.attachAsset('highlightTile', {
anchorX: 0.5,
anchorY: 0.5
});
};
self.down = function (x, y, obj) {
handleTileClick(self.gridX, self.gridY);
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x333333
});
/****
* Game Code
****/
var GRID_SIZE = 8;
var TILE_SIZE = 128;
var MAX_TURNS = 25;
var gameGrid = [];
var currentPlayer = 1; // 1 = blue, 2 = red
var turnCount = 0;
var lastMoveX = -1;
var lastMoveY = -1;
var gameActive = true;
var gameResult = null; // null = ongoing, 'win' = current player won, 'lose' = current player lost
var boardContainer = new Container();
game.addChild(boardContainer);
// Initialize game board
function initBoard() {
gameGrid = [];
for (var y = 0; y < GRID_SIZE; y++) {
gameGrid[y] = [];
for (var x = 0; x < GRID_SIZE; x++) {
var tile = new GridTile();
gameGrid[y][x] = tile;
boardContainer.addChild(tile);
var owner = 0;
var isCastle = false;
if (y === 0 && x === GRID_SIZE / 2) {
owner = 1;
isCastle = true;
} else if (y === GRID_SIZE - 1 && x === GRID_SIZE / 2) {
owner = 2;
isCastle = true;
}
tile.init(x, y, owner, isCastle);
tile.x = x * TILE_SIZE + TILE_SIZE / 2 + (2048 - GRID_SIZE * TILE_SIZE) / 2;
tile.y = y * TILE_SIZE + TILE_SIZE / 2 + (2732 - GRID_SIZE * TILE_SIZE) / 2;
}
}
lastMoveX = GRID_SIZE / 2;
lastMoveY = 0;
currentPlayer = 1;
turnCount = 0;
gameActive = true;
gameResult = null;
updateUI();
}
function getAdjacentTiles(x, y) {
var adjacent = [];
var directions = [[0, -1], [1, 0], [0, 1], [-1, 0], [-1, -1], [1, -1], [-1, 1], [1, 1]];
for (var i = 0; i < directions.length; i++) {
var nx = x + directions[i][0];
var ny = y + directions[i][1];
if (nx >= 0 && nx < GRID_SIZE && ny >= 0 && ny < GRID_SIZE) {
adjacent.push({
x: nx,
y: ny
});
}
}
return adjacent;
}
function getValidMoves() {
var validMoves = [];
var checkedTiles = {};
// Find all tiles owned by current player
for (var y = 0; y < GRID_SIZE; y++) {
for (var x = 0; x < GRID_SIZE; x++) {
if (gameGrid[y][x].owner === currentPlayer) {
// Get adjacent tiles to this player's tile
var adjacent = getAdjacentTiles(x, y);
for (var i = 0; i < adjacent.length; i++) {
var adjTile = adjacent[i];
var key = adjTile.x + ',' + adjTile.y;
var adjacentTile = gameGrid[adjTile.y][adjTile.x];
var isOpponentTile = currentPlayer === 1 && adjacentTile.owner === 2 || currentPlayer === 2 && adjacentTile.owner === 1;
var isOwnTile = adjacentTile.owner === currentPlayer;
var isEmptyTile = adjacentTile.owner === 0;
// Allow painting on empty tiles, opponent tiles, or own tiles
if ((isEmptyTile || isOpponentTile || isOwnTile) && !checkedTiles[key]) {
validMoves.push({
x: adjTile.x,
y: adjTile.y
});
checkedTiles[key] = true;
}
}
}
}
}
return validMoves;
}
function clearHighlights() {
for (var y = 0; y < GRID_SIZE; y++) {
for (var x = 0; x < GRID_SIZE; x++) {
var tile = gameGrid[y][x];
var owner = tile.owner;
var isCastle = tile.isCastle;
tile.init(x, y, owner, isCastle);
}
}
}
function highlightValidMoves() {
clearHighlights();
var validMoves = getValidMoves();
for (var i = 0; i < validMoves.length; i++) {
var move = validMoves[i];
if (gameGrid[move.y][move.x].owner === 0) {
gameGrid[move.y][move.x].highlight();
}
}
}
function handleTileClick(x, y) {
if (!gameActive) return;
var tile = gameGrid[y][x];
// Check if tile is paintable: empty, opponent's, or own tile
var isOpponentTile = currentPlayer === 1 && tile.owner === 2 || currentPlayer === 2 && tile.owner === 1;
var isOwnTile = tile.owner === currentPlayer;
var isEmptyTile = tile.owner === 0;
if (!isEmptyTile && !isOpponentTile && !isOwnTile) return;
var validMoves = getValidMoves();
var isValid = false;
for (var i = 0; i < validMoves.length; i++) {
if (validMoves[i].x === x && validMoves[i].y === y) {
isValid = true;
break;
}
}
if (!isValid) return;
// Painting opponent's tile doesn't consume a turn
var isCapture = isOpponentTile;
tile.setOwner(currentPlayer);
LK.getSound('paint').play();
if (!isCapture) {
turnCount++;
}
lastMoveX = x;
lastMoveY = y;
if (turnCount >= MAX_TURNS) {
checkWinCondition();
} else {
switchPlayer();
}
}
function isCastleSurrounded(castleX, castleY, playerToCheck) {
var directions = [[0, -1], [1, 0], [0, 1], [-1, 0], [-1, -1], [1, -1], [-1, 1], [1, 1]];
for (var i = 0; i < directions.length; i++) {
var nx = castleX + directions[i][0];
var ny = castleY + directions[i][1];
if (nx >= 0 && nx < GRID_SIZE && ny >= 0 && ny < GRID_SIZE) {
if (gameGrid[ny][nx].owner !== playerToCheck) {
return false;
}
}
}
return true;
}
function checkWinCondition() {
gameActive = false;
var opponentCastleX, opponentCastleY;
if (currentPlayer === 1) {
opponentCastleX = GRID_SIZE / 2;
opponentCastleY = GRID_SIZE - 1;
} else {
opponentCastleX = GRID_SIZE / 2;
opponentCastleY = 0;
}
if (isCastleSurrounded(opponentCastleX, opponentCastleY, currentPlayer)) {
gameResult = 'win';
LK.getSound('win').play();
LK.setTimeout(function () {
LK.showYouWin();
}, 1000);
} else {
gameResult = 'lose';
LK.setTimeout(function () {
LK.showGameOver();
}, 1000);
}
}
function switchPlayer() {
currentPlayer = currentPlayer === 1 ? 2 : 1;
updateUI();
highlightValidMoves();
}
function updateUI() {
if (turnStatusText) {
turnStatusText.setText('Player ' + currentPlayer + ' - Turn ' + turnCount + '/' + MAX_TURNS);
}
}
var turnStatusText = new Text2('Player 1 - Turn 0/25', {
size: 60,
fill: '#FFFFFF'
});
turnStatusText.anchor.set(0.5, 0);
LK.gui.top.addChild(turnStatusText);
initBoard();
highlightValidMoves();
game.update = function () {
// Game updates handled through user interactions
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var GridTile = Container.expand(function () {
var self = Container.call(this);
self.gridX = 0;
self.gridY = 0;
self.owner = 0; // 0 = empty, 1 = blue, 2 = red
self.isCastle = false;
self.tileGraphics = null;
self.init = function (gridX, gridY, owner, isCastle) {
self.gridX = gridX;
self.gridY = gridY;
self.owner = owner;
self.isCastle = isCastle;
var assetId = 'emptyTile';
if (isCastle && owner === 1) assetId = 'blueCastle';else if (isCastle && owner === 2) assetId = 'redCastle';else if (owner === 1) assetId = 'blueTile';else if (owner === 2) assetId = 'redTile';
if (self.tileGraphics) self.removeChild(self.tileGraphics);
self.tileGraphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
};
self.setOwner = function (newOwner) {
self.owner = newOwner;
var assetId = 'emptyTile';
if (newOwner === 1) assetId = 'blueTile';else if (newOwner === 2) assetId = 'redTile';
if (self.tileGraphics) self.removeChild(self.tileGraphics);
self.tileGraphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
};
self.highlight = function () {
if (self.tileGraphics) self.removeChild(self.tileGraphics);
self.tileGraphics = self.attachAsset('highlightTile', {
anchorX: 0.5,
anchorY: 0.5
});
};
self.down = function (x, y, obj) {
handleTileClick(self.gridX, self.gridY);
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x333333
});
/****
* Game Code
****/
var GRID_SIZE = 8;
var TILE_SIZE = 128;
var MAX_TURNS = 25;
var gameGrid = [];
var currentPlayer = 1; // 1 = blue, 2 = red
var turnCount = 0;
var lastMoveX = -1;
var lastMoveY = -1;
var gameActive = true;
var gameResult = null; // null = ongoing, 'win' = current player won, 'lose' = current player lost
var boardContainer = new Container();
game.addChild(boardContainer);
// Initialize game board
function initBoard() {
gameGrid = [];
for (var y = 0; y < GRID_SIZE; y++) {
gameGrid[y] = [];
for (var x = 0; x < GRID_SIZE; x++) {
var tile = new GridTile();
gameGrid[y][x] = tile;
boardContainer.addChild(tile);
var owner = 0;
var isCastle = false;
if (y === 0 && x === GRID_SIZE / 2) {
owner = 1;
isCastle = true;
} else if (y === GRID_SIZE - 1 && x === GRID_SIZE / 2) {
owner = 2;
isCastle = true;
}
tile.init(x, y, owner, isCastle);
tile.x = x * TILE_SIZE + TILE_SIZE / 2 + (2048 - GRID_SIZE * TILE_SIZE) / 2;
tile.y = y * TILE_SIZE + TILE_SIZE / 2 + (2732 - GRID_SIZE * TILE_SIZE) / 2;
}
}
lastMoveX = GRID_SIZE / 2;
lastMoveY = 0;
currentPlayer = 1;
turnCount = 0;
gameActive = true;
gameResult = null;
updateUI();
}
function getAdjacentTiles(x, y) {
var adjacent = [];
var directions = [[0, -1], [1, 0], [0, 1], [-1, 0], [-1, -1], [1, -1], [-1, 1], [1, 1]];
for (var i = 0; i < directions.length; i++) {
var nx = x + directions[i][0];
var ny = y + directions[i][1];
if (nx >= 0 && nx < GRID_SIZE && ny >= 0 && ny < GRID_SIZE) {
adjacent.push({
x: nx,
y: ny
});
}
}
return adjacent;
}
function getValidMoves() {
var validMoves = [];
var checkedTiles = {};
// Find all tiles owned by current player
for (var y = 0; y < GRID_SIZE; y++) {
for (var x = 0; x < GRID_SIZE; x++) {
if (gameGrid[y][x].owner === currentPlayer) {
// Get adjacent tiles to this player's tile
var adjacent = getAdjacentTiles(x, y);
for (var i = 0; i < adjacent.length; i++) {
var adjTile = adjacent[i];
var key = adjTile.x + ',' + adjTile.y;
var adjacentTile = gameGrid[adjTile.y][adjTile.x];
var isOpponentTile = currentPlayer === 1 && adjacentTile.owner === 2 || currentPlayer === 2 && adjacentTile.owner === 1;
var isOwnTile = adjacentTile.owner === currentPlayer;
var isEmptyTile = adjacentTile.owner === 0;
// Allow painting on empty tiles, opponent tiles, or own tiles
if ((isEmptyTile || isOpponentTile || isOwnTile) && !checkedTiles[key]) {
validMoves.push({
x: adjTile.x,
y: adjTile.y
});
checkedTiles[key] = true;
}
}
}
}
}
return validMoves;
}
function clearHighlights() {
for (var y = 0; y < GRID_SIZE; y++) {
for (var x = 0; x < GRID_SIZE; x++) {
var tile = gameGrid[y][x];
var owner = tile.owner;
var isCastle = tile.isCastle;
tile.init(x, y, owner, isCastle);
}
}
}
function highlightValidMoves() {
clearHighlights();
var validMoves = getValidMoves();
for (var i = 0; i < validMoves.length; i++) {
var move = validMoves[i];
if (gameGrid[move.y][move.x].owner === 0) {
gameGrid[move.y][move.x].highlight();
}
}
}
function handleTileClick(x, y) {
if (!gameActive) return;
var tile = gameGrid[y][x];
// Check if tile is paintable: empty, opponent's, or own tile
var isOpponentTile = currentPlayer === 1 && tile.owner === 2 || currentPlayer === 2 && tile.owner === 1;
var isOwnTile = tile.owner === currentPlayer;
var isEmptyTile = tile.owner === 0;
if (!isEmptyTile && !isOpponentTile && !isOwnTile) return;
var validMoves = getValidMoves();
var isValid = false;
for (var i = 0; i < validMoves.length; i++) {
if (validMoves[i].x === x && validMoves[i].y === y) {
isValid = true;
break;
}
}
if (!isValid) return;
// Painting opponent's tile doesn't consume a turn
var isCapture = isOpponentTile;
tile.setOwner(currentPlayer);
LK.getSound('paint').play();
if (!isCapture) {
turnCount++;
}
lastMoveX = x;
lastMoveY = y;
if (turnCount >= MAX_TURNS) {
checkWinCondition();
} else {
switchPlayer();
}
}
function isCastleSurrounded(castleX, castleY, playerToCheck) {
var directions = [[0, -1], [1, 0], [0, 1], [-1, 0], [-1, -1], [1, -1], [-1, 1], [1, 1]];
for (var i = 0; i < directions.length; i++) {
var nx = castleX + directions[i][0];
var ny = castleY + directions[i][1];
if (nx >= 0 && nx < GRID_SIZE && ny >= 0 && ny < GRID_SIZE) {
if (gameGrid[ny][nx].owner !== playerToCheck) {
return false;
}
}
}
return true;
}
function checkWinCondition() {
gameActive = false;
var opponentCastleX, opponentCastleY;
if (currentPlayer === 1) {
opponentCastleX = GRID_SIZE / 2;
opponentCastleY = GRID_SIZE - 1;
} else {
opponentCastleX = GRID_SIZE / 2;
opponentCastleY = 0;
}
if (isCastleSurrounded(opponentCastleX, opponentCastleY, currentPlayer)) {
gameResult = 'win';
LK.getSound('win').play();
LK.setTimeout(function () {
LK.showYouWin();
}, 1000);
} else {
gameResult = 'lose';
LK.setTimeout(function () {
LK.showGameOver();
}, 1000);
}
}
function switchPlayer() {
currentPlayer = currentPlayer === 1 ? 2 : 1;
updateUI();
highlightValidMoves();
}
function updateUI() {
if (turnStatusText) {
turnStatusText.setText('Player ' + currentPlayer + ' - Turn ' + turnCount + '/' + MAX_TURNS);
}
}
var turnStatusText = new Text2('Player 1 - Turn 0/25', {
size: 60,
fill: '#FFFFFF'
});
turnStatusText.anchor.set(0.5, 0);
LK.gui.top.addChild(turnStatusText);
initBoard();
highlightValidMoves();
game.update = function () {
// Game updates handled through user interactions
};