/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// BoardCell: Represents a single cell in the Tic Tac Toe grid
var BoardCell = Container.expand(function () {
var self = Container.call(this);
// Cell highlight background (grikutu, hidden by default)
var grikutuBg = self.attachAsset('grikutu', {
anchorX: 0.5,
anchorY: 0.5
});
grikutuBg.visible = false;
self.addChild(grikutuBg);
// Cell background (box)
var cellBg = self.attachAsset('cellBg', {
anchorX: 0.5,
anchorY: 0.5
});
// Symbol image for X or O
var xImage = LK.getAsset('x', {
anchorX: 0.5,
anchorY: 0.5
});
xImage.visible = false;
self.addChild(xImage);
var oImage = LK.getAsset('y', {
anchorX: 0.5,
anchorY: 0.5
});
oImage.visible = false;
self.addChild(oImage);
self.symbol = ''; // '', 'X', or 'O'
self.row = 0;
self.col = 0;
self.isActive = true; // Can be tapped
self.setSymbol = function (sym) {
self.symbol = sym;
if (sym === 'X') {
grikutuBg.visible = true;
xImage.visible = true;
oImage.visible = false;
} else if (sym === 'O') {
grikutuBg.visible = true;
xImage.visible = false;
oImage.visible = true;
} else {
grikutuBg.visible = false;
xImage.visible = false;
oImage.visible = false;
}
};
self.clear = function () {
self.symbol = '';
grikutuBg.visible = false;
xImage.visible = false;
oImage.visible = false;
self.isActive = true;
};
self.flash = function (color, duration) {
tween(cellBg, {
tint: color
}, {
duration: duration / 2,
easing: tween.easeIn,
onFinish: function onFinish() {
tween(cellBg, {
tint: 0xffffff
}, {
duration: duration / 2,
easing: tween.easeOut
});
}
});
};
return self;
});
// Health bar class
var HealthBar = Container.expand(function () {
var self = Container.call(this);
var bg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
var bar = self.attachAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5
});
self.set = function (val, max) {
// Use the background width for dynamic sizing, and clamp value between 0 and max
var percent = Math.max(0, Math.min(1, val / max));
bar.width = bg.width * percent;
if (percent < 0.3) bar.tint = 0xff4444;else if (percent < 0.6) bar.tint = 0xffcc00;else bar.tint = 0x4caf50;
};
self.set(1, 1);
return self;
});
/****
* Initialize Game
****/
// Create vikings
var game = new LK.Game({
backgroundColor: 0xffffff
});
/****
* Game Code
****/
// O symbol asset (green ellipse, could be replaced with image for stylized O)
// X symbol asset (blue box, could be replaced with image for stylized X)
// Cell background for Tic Tac Toe
// Tic Tac Toe Game State
var BOARD_SIZE = 3;
var CELL_SIZE = 320;
var CELL_MARGIN = 24;
var board = [];
var currentPlayer = 'X';
var gameActive = true;
var statusText = new Text2('Sıra: X', {
size: 110,
fill: 0x333333
});
statusText.anchor.set(0.5, 0);
LK.gui.top.addChild(statusText);
// Center the board
var boardWidth = BOARD_SIZE * CELL_SIZE + (BOARD_SIZE - 1) * CELL_MARGIN;
var boardHeight = BOARD_SIZE * CELL_SIZE + (BOARD_SIZE - 1) * CELL_MARGIN;
var boardOriginX = (2048 - boardWidth) / 2;
var boardOriginY = (2732 - boardHeight) / 2 + 60;
// Create board cells
for (var row = 0; row < BOARD_SIZE; row++) {
board[row] = [];
for (var col = 0; col < BOARD_SIZE; col++) {
var cell = new BoardCell();
cell.x = boardOriginX + col * (CELL_SIZE + CELL_MARGIN) + CELL_SIZE / 2;
cell.y = boardOriginY + row * (CELL_SIZE + CELL_MARGIN) + CELL_SIZE / 2;
cell.row = row;
cell.col = col;
cell.setSymbol('');
cell.isActive = true;
// Cell tap handler
cell.down = function (cell) {
return function (x, y, obj) {
if (!gameActive || !cell.isActive) return;
cell.setSymbol(currentPlayer);
cell.isActive = false;
if (checkWin(currentPlayer)) {
gameActive = false;
statusText.setText('Kazanan: ' + currentPlayer);
highlightWin(currentPlayer);
LK.setTimeout(function () {
LK.showYouWin();
}, 1200);
} else if (isBoardFull()) {
gameActive = false;
statusText.setText('Berabere!');
LK.setTimeout(function () {
LK.showGameOver();
}, 1200);
} else {
// If X just played, make a smart O move if game is still active
if (currentPlayer === 'X') {
currentPlayer = 'O';
statusText.setText('Sıra: O');
var oPlaced = false;
// 1. Check for two Xs in a row with an empty cell next to them (horizontal)
for (var r = 0; r < BOARD_SIZE && !oPlaced; r++) {
for (var c = 0; c < BOARD_SIZE - 1 && !oPlaced; c++) {
// X X _
if (board[r][c].symbol === 'X' && board[r][c + 1].symbol === 'X') {
// Try to place O to the right
if (c + 2 < BOARD_SIZE && board[r][c + 2].symbol === '') {
board[r][c + 2].setSymbol('O');
board[r][c + 2].isActive = false;
oPlaced = true;
}
// Try to place O to the left
else if (c - 1 >= 0 && board[r][c - 1].symbol === '') {
board[r][c - 1].setSymbol('O');
board[r][c - 1].isActive = false;
oPlaced = true;
}
}
}
}
// 2. Check for two Xs in a column with an empty cell next to them (vertical)
for (var c = 0; c < BOARD_SIZE && !oPlaced; c++) {
for (var r = 0; r < BOARD_SIZE - 1 && !oPlaced; r++) {
// X
// X
// _
if (board[r][c].symbol === 'X' && board[r + 1][c].symbol === 'X') {
// Try to place O below
if (r + 2 < BOARD_SIZE && board[r + 2][c].symbol === '') {
board[r + 2][c].setSymbol('O');
board[r + 2][c].isActive = false;
oPlaced = true;
}
// Try to place O above
else if (r - 1 >= 0 && board[r - 1][c].symbol === '') {
board[r - 1][c].setSymbol('O');
board[r - 1][c].isActive = false;
oPlaced = true;
}
}
}
}
// 3. Check for two Xs in a diagonal (\) with an empty cell next to them
for (var i = 0; i < BOARD_SIZE - 1 && !oPlaced; i++) {
// X X _
if (board[i][i].symbol === 'X' && board[i + 1][i + 1].symbol === 'X') {
// Try to place O after
if (i + 2 < BOARD_SIZE && board[i + 2][i + 2].symbol === '') {
board[i + 2][i + 2].setSymbol('O');
board[i + 2][i + 2].isActive = false;
oPlaced = true;
}
// Try to place O before
else if (i - 1 >= 0 && board[i - 1][i - 1].symbol === '') {
board[i - 1][i - 1].setSymbol('O');
board[i - 1][i - 1].isActive = false;
oPlaced = true;
}
}
}
// 4. Check for two Xs in a diagonal (/) with an empty cell next to them
for (var i = 0; i < BOARD_SIZE - 1 && !oPlaced; i++) {
var row1 = i,
col1 = BOARD_SIZE - 1 - i;
var row2 = i + 1,
col2 = BOARD_SIZE - 2 - i;
if (board[row1][col1].symbol === 'X' && board[row2][col2].symbol === 'X') {
// Try to place O after
if (i + 2 < BOARD_SIZE && board[i + 2][BOARD_SIZE - 1 - (i + 2)].symbol === '') {
board[i + 2][BOARD_SIZE - 1 - (i + 2)].setSymbol('O');
board[i + 2][BOARD_SIZE - 1 - (i + 2)].isActive = false;
oPlaced = true;
}
// Try to place O before
else if (i - 1 >= 0 && board[i - 1][BOARD_SIZE - 1 - (i - 1)].symbol === '') {
board[i - 1][BOARD_SIZE - 1 - (i - 1)].setSymbol('O');
board[i - 1][BOARD_SIZE - 1 - (i - 1)].isActive = false;
oPlaced = true;
}
}
}
// 5. If no such pattern, pick a random empty cell for O
if (!oPlaced) {
// Find all empty cells
var emptyCells = [];
for (var r = 0; r < BOARD_SIZE; r++) {
for (var c = 0; c < BOARD_SIZE; c++) {
if (board[r][c].symbol === '') {
emptyCells.push(board[r][c]);
}
}
}
if (emptyCells.length > 0) {
var idx = Math.floor(Math.random() * emptyCells.length);
var oCell = emptyCells[idx];
oCell.setSymbol('O');
oCell.isActive = false;
}
}
// Check if O wins
if (checkWin('O')) {
gameActive = false;
statusText.setText('Kazanan: O');
highlightWin('O');
LK.setTimeout(function () {
LK.showYouWin();
}, 1200);
} else if (isBoardFull()) {
gameActive = false;
statusText.setText('Berabere!');
LK.setTimeout(function () {
LK.showGameOver();
}, 1200);
} else {
currentPlayer = 'X';
statusText.setText('Sıra: X');
}
} else {
currentPlayer = 'X';
statusText.setText('Sıra: X');
}
}
};
}(cell);
board[row][col] = cell;
game.addChild(cell);
}
}
// Check for win
function checkWin(player) {
// Rows
for (var r = 0; r < BOARD_SIZE; r++) {
var win = true;
for (var c = 0; c < BOARD_SIZE; c++) {
if (board[r][c].symbol !== player) win = false;
}
if (win) return true;
}
// Columns
for (var c = 0; c < BOARD_SIZE; c++) {
var win = true;
for (var r = 0; r < BOARD_SIZE; r++) {
if (board[r][c].symbol !== player) win = false;
}
if (win) return true;
}
// Diagonal \
var win = true;
for (var i = 0; i < BOARD_SIZE; i++) {
if (board[i][i].symbol !== player) win = false;
}
if (win) return true;
// Diagonal /
win = true;
for (var i = 0; i < BOARD_SIZE; i++) {
if (board[i][BOARD_SIZE - 1 - i].symbol !== player) win = false;
}
if (win) return true;
return false;
}
// Highlight winning cells
function highlightWin(player) {
// Rows
for (var r = 0; r < BOARD_SIZE; r++) {
var win = true;
for (var c = 0; c < BOARD_SIZE; c++) {
if (board[r][c].symbol !== player) win = false;
}
if (win) {
for (var c = 0; c < BOARD_SIZE; c++) {
board[r][c].flash(0x00ff00, 800);
}
return;
}
}
// Columns
for (var c = 0; c < BOARD_SIZE; c++) {
var win = true;
for (var r = 0; r < BOARD_SIZE; r++) {
if (board[r][c].symbol !== player) win = false;
}
if (win) {
for (var r = 0; r < BOARD_SIZE; r++) {
board[r][c].flash(0x00ff00, 800);
}
return;
}
}
// Diagonal \
var win = true;
for (var i = 0; i < BOARD_SIZE; i++) {
if (board[i][i].symbol !== player) win = false;
}
if (win) {
for (var i = 0; i < BOARD_SIZE; i++) {
board[i][i].flash(0x00ff00, 800);
}
return;
}
// Diagonal /
win = true;
for (var i = 0; i < BOARD_SIZE; i++) {
if (board[i][BOARD_SIZE - 1 - i].symbol !== player) win = false;
}
if (win) {
for (var i = 0; i < BOARD_SIZE; i++) {
board[i][BOARD_SIZE - 1 - i].flash(0x00ff00, 800);
}
return;
}
}
// Check if board is full
function isBoardFull() {
for (var r = 0; r < BOARD_SIZE; r++) {
for (var c = 0; c < BOARD_SIZE; c++) {
if (board[r][c].symbol === '') return false;
}
}
return true;
}
// Reset game on LK reset (handled automatically)
function resetBoard() {
for (var r = 0; r < BOARD_SIZE; r++) {
for (var c = 0; c < BOARD_SIZE; c++) {
board[r][c].clear();
}
}
currentPlayer = 'X';
gameActive = true;
statusText.setText('Sıra: X');
}
resetBoard(); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// BoardCell: Represents a single cell in the Tic Tac Toe grid
var BoardCell = Container.expand(function () {
var self = Container.call(this);
// Cell highlight background (grikutu, hidden by default)
var grikutuBg = self.attachAsset('grikutu', {
anchorX: 0.5,
anchorY: 0.5
});
grikutuBg.visible = false;
self.addChild(grikutuBg);
// Cell background (box)
var cellBg = self.attachAsset('cellBg', {
anchorX: 0.5,
anchorY: 0.5
});
// Symbol image for X or O
var xImage = LK.getAsset('x', {
anchorX: 0.5,
anchorY: 0.5
});
xImage.visible = false;
self.addChild(xImage);
var oImage = LK.getAsset('y', {
anchorX: 0.5,
anchorY: 0.5
});
oImage.visible = false;
self.addChild(oImage);
self.symbol = ''; // '', 'X', or 'O'
self.row = 0;
self.col = 0;
self.isActive = true; // Can be tapped
self.setSymbol = function (sym) {
self.symbol = sym;
if (sym === 'X') {
grikutuBg.visible = true;
xImage.visible = true;
oImage.visible = false;
} else if (sym === 'O') {
grikutuBg.visible = true;
xImage.visible = false;
oImage.visible = true;
} else {
grikutuBg.visible = false;
xImage.visible = false;
oImage.visible = false;
}
};
self.clear = function () {
self.symbol = '';
grikutuBg.visible = false;
xImage.visible = false;
oImage.visible = false;
self.isActive = true;
};
self.flash = function (color, duration) {
tween(cellBg, {
tint: color
}, {
duration: duration / 2,
easing: tween.easeIn,
onFinish: function onFinish() {
tween(cellBg, {
tint: 0xffffff
}, {
duration: duration / 2,
easing: tween.easeOut
});
}
});
};
return self;
});
// Health bar class
var HealthBar = Container.expand(function () {
var self = Container.call(this);
var bg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
var bar = self.attachAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5
});
self.set = function (val, max) {
// Use the background width for dynamic sizing, and clamp value between 0 and max
var percent = Math.max(0, Math.min(1, val / max));
bar.width = bg.width * percent;
if (percent < 0.3) bar.tint = 0xff4444;else if (percent < 0.6) bar.tint = 0xffcc00;else bar.tint = 0x4caf50;
};
self.set(1, 1);
return self;
});
/****
* Initialize Game
****/
// Create vikings
var game = new LK.Game({
backgroundColor: 0xffffff
});
/****
* Game Code
****/
// O symbol asset (green ellipse, could be replaced with image for stylized O)
// X symbol asset (blue box, could be replaced with image for stylized X)
// Cell background for Tic Tac Toe
// Tic Tac Toe Game State
var BOARD_SIZE = 3;
var CELL_SIZE = 320;
var CELL_MARGIN = 24;
var board = [];
var currentPlayer = 'X';
var gameActive = true;
var statusText = new Text2('Sıra: X', {
size: 110,
fill: 0x333333
});
statusText.anchor.set(0.5, 0);
LK.gui.top.addChild(statusText);
// Center the board
var boardWidth = BOARD_SIZE * CELL_SIZE + (BOARD_SIZE - 1) * CELL_MARGIN;
var boardHeight = BOARD_SIZE * CELL_SIZE + (BOARD_SIZE - 1) * CELL_MARGIN;
var boardOriginX = (2048 - boardWidth) / 2;
var boardOriginY = (2732 - boardHeight) / 2 + 60;
// Create board cells
for (var row = 0; row < BOARD_SIZE; row++) {
board[row] = [];
for (var col = 0; col < BOARD_SIZE; col++) {
var cell = new BoardCell();
cell.x = boardOriginX + col * (CELL_SIZE + CELL_MARGIN) + CELL_SIZE / 2;
cell.y = boardOriginY + row * (CELL_SIZE + CELL_MARGIN) + CELL_SIZE / 2;
cell.row = row;
cell.col = col;
cell.setSymbol('');
cell.isActive = true;
// Cell tap handler
cell.down = function (cell) {
return function (x, y, obj) {
if (!gameActive || !cell.isActive) return;
cell.setSymbol(currentPlayer);
cell.isActive = false;
if (checkWin(currentPlayer)) {
gameActive = false;
statusText.setText('Kazanan: ' + currentPlayer);
highlightWin(currentPlayer);
LK.setTimeout(function () {
LK.showYouWin();
}, 1200);
} else if (isBoardFull()) {
gameActive = false;
statusText.setText('Berabere!');
LK.setTimeout(function () {
LK.showGameOver();
}, 1200);
} else {
// If X just played, make a smart O move if game is still active
if (currentPlayer === 'X') {
currentPlayer = 'O';
statusText.setText('Sıra: O');
var oPlaced = false;
// 1. Check for two Xs in a row with an empty cell next to them (horizontal)
for (var r = 0; r < BOARD_SIZE && !oPlaced; r++) {
for (var c = 0; c < BOARD_SIZE - 1 && !oPlaced; c++) {
// X X _
if (board[r][c].symbol === 'X' && board[r][c + 1].symbol === 'X') {
// Try to place O to the right
if (c + 2 < BOARD_SIZE && board[r][c + 2].symbol === '') {
board[r][c + 2].setSymbol('O');
board[r][c + 2].isActive = false;
oPlaced = true;
}
// Try to place O to the left
else if (c - 1 >= 0 && board[r][c - 1].symbol === '') {
board[r][c - 1].setSymbol('O');
board[r][c - 1].isActive = false;
oPlaced = true;
}
}
}
}
// 2. Check for two Xs in a column with an empty cell next to them (vertical)
for (var c = 0; c < BOARD_SIZE && !oPlaced; c++) {
for (var r = 0; r < BOARD_SIZE - 1 && !oPlaced; r++) {
// X
// X
// _
if (board[r][c].symbol === 'X' && board[r + 1][c].symbol === 'X') {
// Try to place O below
if (r + 2 < BOARD_SIZE && board[r + 2][c].symbol === '') {
board[r + 2][c].setSymbol('O');
board[r + 2][c].isActive = false;
oPlaced = true;
}
// Try to place O above
else if (r - 1 >= 0 && board[r - 1][c].symbol === '') {
board[r - 1][c].setSymbol('O');
board[r - 1][c].isActive = false;
oPlaced = true;
}
}
}
}
// 3. Check for two Xs in a diagonal (\) with an empty cell next to them
for (var i = 0; i < BOARD_SIZE - 1 && !oPlaced; i++) {
// X X _
if (board[i][i].symbol === 'X' && board[i + 1][i + 1].symbol === 'X') {
// Try to place O after
if (i + 2 < BOARD_SIZE && board[i + 2][i + 2].symbol === '') {
board[i + 2][i + 2].setSymbol('O');
board[i + 2][i + 2].isActive = false;
oPlaced = true;
}
// Try to place O before
else if (i - 1 >= 0 && board[i - 1][i - 1].symbol === '') {
board[i - 1][i - 1].setSymbol('O');
board[i - 1][i - 1].isActive = false;
oPlaced = true;
}
}
}
// 4. Check for two Xs in a diagonal (/) with an empty cell next to them
for (var i = 0; i < BOARD_SIZE - 1 && !oPlaced; i++) {
var row1 = i,
col1 = BOARD_SIZE - 1 - i;
var row2 = i + 1,
col2 = BOARD_SIZE - 2 - i;
if (board[row1][col1].symbol === 'X' && board[row2][col2].symbol === 'X') {
// Try to place O after
if (i + 2 < BOARD_SIZE && board[i + 2][BOARD_SIZE - 1 - (i + 2)].symbol === '') {
board[i + 2][BOARD_SIZE - 1 - (i + 2)].setSymbol('O');
board[i + 2][BOARD_SIZE - 1 - (i + 2)].isActive = false;
oPlaced = true;
}
// Try to place O before
else if (i - 1 >= 0 && board[i - 1][BOARD_SIZE - 1 - (i - 1)].symbol === '') {
board[i - 1][BOARD_SIZE - 1 - (i - 1)].setSymbol('O');
board[i - 1][BOARD_SIZE - 1 - (i - 1)].isActive = false;
oPlaced = true;
}
}
}
// 5. If no such pattern, pick a random empty cell for O
if (!oPlaced) {
// Find all empty cells
var emptyCells = [];
for (var r = 0; r < BOARD_SIZE; r++) {
for (var c = 0; c < BOARD_SIZE; c++) {
if (board[r][c].symbol === '') {
emptyCells.push(board[r][c]);
}
}
}
if (emptyCells.length > 0) {
var idx = Math.floor(Math.random() * emptyCells.length);
var oCell = emptyCells[idx];
oCell.setSymbol('O');
oCell.isActive = false;
}
}
// Check if O wins
if (checkWin('O')) {
gameActive = false;
statusText.setText('Kazanan: O');
highlightWin('O');
LK.setTimeout(function () {
LK.showYouWin();
}, 1200);
} else if (isBoardFull()) {
gameActive = false;
statusText.setText('Berabere!');
LK.setTimeout(function () {
LK.showGameOver();
}, 1200);
} else {
currentPlayer = 'X';
statusText.setText('Sıra: X');
}
} else {
currentPlayer = 'X';
statusText.setText('Sıra: X');
}
}
};
}(cell);
board[row][col] = cell;
game.addChild(cell);
}
}
// Check for win
function checkWin(player) {
// Rows
for (var r = 0; r < BOARD_SIZE; r++) {
var win = true;
for (var c = 0; c < BOARD_SIZE; c++) {
if (board[r][c].symbol !== player) win = false;
}
if (win) return true;
}
// Columns
for (var c = 0; c < BOARD_SIZE; c++) {
var win = true;
for (var r = 0; r < BOARD_SIZE; r++) {
if (board[r][c].symbol !== player) win = false;
}
if (win) return true;
}
// Diagonal \
var win = true;
for (var i = 0; i < BOARD_SIZE; i++) {
if (board[i][i].symbol !== player) win = false;
}
if (win) return true;
// Diagonal /
win = true;
for (var i = 0; i < BOARD_SIZE; i++) {
if (board[i][BOARD_SIZE - 1 - i].symbol !== player) win = false;
}
if (win) return true;
return false;
}
// Highlight winning cells
function highlightWin(player) {
// Rows
for (var r = 0; r < BOARD_SIZE; r++) {
var win = true;
for (var c = 0; c < BOARD_SIZE; c++) {
if (board[r][c].symbol !== player) win = false;
}
if (win) {
for (var c = 0; c < BOARD_SIZE; c++) {
board[r][c].flash(0x00ff00, 800);
}
return;
}
}
// Columns
for (var c = 0; c < BOARD_SIZE; c++) {
var win = true;
for (var r = 0; r < BOARD_SIZE; r++) {
if (board[r][c].symbol !== player) win = false;
}
if (win) {
for (var r = 0; r < BOARD_SIZE; r++) {
board[r][c].flash(0x00ff00, 800);
}
return;
}
}
// Diagonal \
var win = true;
for (var i = 0; i < BOARD_SIZE; i++) {
if (board[i][i].symbol !== player) win = false;
}
if (win) {
for (var i = 0; i < BOARD_SIZE; i++) {
board[i][i].flash(0x00ff00, 800);
}
return;
}
// Diagonal /
win = true;
for (var i = 0; i < BOARD_SIZE; i++) {
if (board[i][BOARD_SIZE - 1 - i].symbol !== player) win = false;
}
if (win) {
for (var i = 0; i < BOARD_SIZE; i++) {
board[i][BOARD_SIZE - 1 - i].flash(0x00ff00, 800);
}
return;
}
}
// Check if board is full
function isBoardFull() {
for (var r = 0; r < BOARD_SIZE; r++) {
for (var c = 0; c < BOARD_SIZE; c++) {
if (board[r][c].symbol === '') return false;
}
}
return true;
}
// Reset game on LK reset (handled automatically)
function resetBoard() {
for (var r = 0; r < BOARD_SIZE; r++) {
for (var c = 0; c < BOARD_SIZE; c++) {
board[r][c].clear();
}
}
currentPlayer = 'X';
gameActive = true;
statusText.setText('Sıra: X');
}
resetBoard();