/**** * 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 };
/****
* 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.