/****
* Classes
****/
//<Assets used in the game will automatically appear here>
// Define the Circle class for player moves
var Circle = Container.expand(function () {
var self = Container.call(this);
var circleGraphics = self.attachAsset('circle', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
// Define the Cross class for AI moves
var Cross = Container.expand(function () {
var self = Container.call(this);
var crossGraphics = self.attachAsset('cross', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xf5ebdc //Init game with #f5ebdc background
});
/****
* Game Code
****/
// Initialize game variables
var board = [];
var playerMoves = [];
var aiMoves = [];
var currentPlayer = 'player';
var cellSize = 300;
var boardOffsetX = (2048 - 3 * cellSize) / 2;
var boardOffsetY = (2732 - 3 * cellSize) / 2;
var isTwoPlayerMode = false;
var background;
// Create win streak text
var winStreakText = new Text2('Win Streak: 0', {
size: 100,
fill: "#000000",
font: "'Comic Sans MS', 'Comic Sans', cursive"
});
winStreakText.anchor.set(0.5, 0);
winStreakText.x = 2048 / 2;
winStreakText.y = 50;
// LK.gui.top.addChild(winStreakText);
// Create buttons for 1 player and 2 players mode
var onePlayerButton = new Text2('1 Player', {
size: 150,
fill: "#ffffff"
});
onePlayerButton.anchor.set(0.5, 0);
onePlayerButton.x = 2048 / 2;
onePlayerButton.y = 2732 / 2 - 200;
onePlayerButton.interactive = true;
onePlayerButton.buttonMode = true;
onePlayerButton.on('pointerdown', function () {
isTwoPlayerMode = false;
startGame();
});
var twoPlayerButton = new Text2('2 Players', {
size: 150,
fill: "#ffffff"
});
twoPlayerButton.anchor.set(0.5, 0);
twoPlayerButton.x = 2048 / 2;
twoPlayerButton.y = 2732 / 2 + 200;
twoPlayerButton.interactive = true;
twoPlayerButton.buttonMode = true;
twoPlayerButton.on('pointerdown', function () {
isTwoPlayerMode = true;
startGame();
});
LK.gui.center.addChild(onePlayerButton);
LK.gui.center.addChild(twoPlayerButton);
function startGame() {
// Remove buttons from the screen
onePlayerButton.destroy();
twoPlayerButton.destroy();
// Initialize the board
for (var i = 0; i < 3; i++) {
board[i] = [];
for (var j = 0; j < 3; j++) {
if (board[i][j]) {
board[i][j].destroy();
}
board[i][j] = null;
}
}
// Add win streak text to the game after background
game.addChild(winStreakText);
// Add win streak text to the game after background
game.addChild(winStreakText);
}
// Add background asset to the game
background = game.attachAsset('background', {
anchorX: 0.5,
anchorY: 0.5,
x: boardOffsetX + 1.5 * cellSize,
y: boardOffsetY + 1.5 * cellSize
});
// Add win streak text to the game after background
game.addChild(winStreakText);
// Move win streak text to be on top of the background
game.addChild(winStreakText);
// Mute the background music
LK.stopMusic();
// Initialize the board
for (var i = 0; i < 3; i++) {
board[i] = [];
for (var j = 0; j < 3; j++) {
board[i][j] = null;
}
}
// Function to check for a win
function checkWin(moves) {
var winPatterns = [[[0, 0], [0, 1], [0, 2]], [[1, 0], [1, 1], [1, 2]], [[2, 0], [2, 1], [2, 2]], [[0, 0], [1, 0], [2, 0]], [[0, 1], [1, 1], [2, 1]], [[0, 2], [1, 2], [2, 2]], [[0, 0], [1, 1], [2, 2]], [[0, 2], [1, 1], [2, 0]]];
for (var _i = 0, _winPatterns = winPatterns; _i < _winPatterns.length; _i++) {
var pattern = _winPatterns[_i];
if (pattern.every(function (pos) {
return moves.some(function (move) {
return move[0] === pos[0] && move[1] === pos[1];
});
})) {
return true;
}
}
return false;
}
// Function to handle player move
function handlePlayerMove(x, y) {
var col = Math.floor((x - boardOffsetX) / cellSize);
var row = Math.floor((y - boardOffsetY) / cellSize);
if (col >= 0 && col < 3 && row >= 0 && row < 3 && !board[row][col]) {
LK.getSound('clicksound').play();
var circle = new Circle();
circle.x = boardOffsetX + col * cellSize + cellSize / 2;
circle.y = boardOffsetY + row * cellSize + cellSize / 2;
game.addChild(circle);
board[row][col] = 'player';
playerMoves.push([row, col, circle]);
if (playerMoves.length > 3) {
var removedMove = playerMoves.shift();
board[removedMove[0]][removedMove[1]] = null;
removedMove[2].destroy();
}
if (checkWin(playerMoves)) {
// Update win streak text
var currentStreak = winStreakText.text ? parseInt(winStreakText.text.split(': ')[1]) : 0;
if (isNaN(currentStreak)) {
currentStreak = 0;
}
currentStreak += 1;
winStreakText.setText('Win Streak: ' + currentStreak);
// Clear the play site
for (var i = 0; i < 3; i++) {
for (var j = 0; j < 3; j++) {
if (board[i][j]) {
board[i][j].destroy();
board[i][j] = null;
}
}
}
playerMoves = [];
aiMoves = [];
} else if (!isTwoPlayerMode) {
currentPlayer = 'ai';
handleAIMove();
} else {
currentPlayer = currentPlayer === 'player' ? 'player2' : 'player';
}
}
}
// Function to handle AI move
function handleAIMove() {
var emptyCells = [];
for (var i = 0; i < 3; i++) {
for (var j = 0; j < 3; j++) {
if (!board[i][j]) {
emptyCells.push([i, j]);
}
}
}
if (!isTwoPlayerMode && emptyCells.length > 0) {
var move = getBestMove(emptyCells, aiMoves, playerMoves);
var cross = new Cross();
cross.x = boardOffsetX + move[1] * cellSize + cellSize / 2;
cross.y = boardOffsetY + move[0] * cellSize + cellSize / 2;
// Add delay for AI move
LK.setTimeout(function () {
LK.getSound('clicksound').play();
game.addChild(cross);
board[move[0]][move[1]] = 'ai';
aiMoves.push([move[0], move[1], cross]);
if (aiMoves.length > 3) {
var removedMove = aiMoves.shift();
board[removedMove[0]][removedMove[1]] = null;
removedMove[2].destroy();
}
if (checkWin(aiMoves)) {
LK.showGameOver();
// Reset win streak text
winStreakText.setText('Win Streak: 0');
} else {
currentPlayer = 'player';
}
}, 1000);
}
}
function getBestMove(emptyCells, aiMoves, playerMoves) {
// AI strategy:
// 1. Check if AI can win in the next move
// 2. Check if the player can win in the next move
// 3. Take the center cell if it's free
// 4. Take a random cell
var errorMargin = 0.4; // Default error margin
// Adjust error margin based on player's win streak
var currentStreak = winStreakText.text ? parseInt(winStreakText.text.split(': ')[1]) : 0;
if (currentStreak === 1) {
errorMargin = 0.3;
} else if (currentStreak === 2) {
errorMargin = 0.2;
} else if (currentStreak === 3) {
errorMargin = 0.1;
} else if (currentStreak === 4) {
errorMargin = 0.05;
} else if (currentStreak >= 5) {
errorMargin = 0.0;
}
for (var i = 0; i < emptyCells.length; i++) {
var testMoves = aiMoves.concat([emptyCells[i]]);
if (checkWin(testMoves) && Math.random() > errorMargin) {
return emptyCells[i];
}
}
for (var i = 0; i < emptyCells.length; i++) {
var testMoves = playerMoves.concat([emptyCells[i]]);
if (checkWin(testMoves) && Math.random() > errorMargin) {
return emptyCells[i];
}
}
if (board[1][1] === null && Math.random() > errorMargin) {
return [1, 1];
}
var randomIndex = Math.floor(Math.random() * emptyCells.length);
return emptyCells[randomIndex];
}
// Handle game down event
game.down = function (x, y, obj) {
if (currentPlayer === 'player') {
handlePlayerMove(x, y);
}
};
// Center the board
game.update = function () {
// No need to update anything every frame for this game
};
simple beige rectengular button vector drawing black outline. Single Game Texture. In-Game asset. 2d.blank background . High contrast. No shadows.
simple beige background with black outline rectengular. Single Game Texture. In-Game asset. 2d.blank background . High contrast. No shadows.
simple beige rectangle button smooth corners, black outline " + 1 " text on middle of button vector drawing. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.