Code edit (6 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
User prompt
Tic-Tac-Toe Master
Initial prompt
AI does X or O randomly and Player does X or O randomly. Player goes first and Ai goes second. Has A difficulty level of hardness of MEDIUM HARD EASY BEGINNER buttons on the home screen. BEGINNER Mode will show you how to play game show how to win and what does three X's or O's in a row and what Ai does to.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var GridCell = Container.expand(function (row, col) { var self = Container.call(this); var cellBg = self.attachAsset('gridCell', { anchorX: 0.5, anchorY: 0.5 }); self.row = row; self.col = col; self.symbol = null; self.symbolGraphic = null; self.down = function (x, y, obj) { if (gameState === 'playing' && self.symbol === null && !waitingForAI) { self.placeSymbol(playerSymbol); LK.getSound('placeSymbol').play(); if (checkWin(gameBoard, playerSymbol)) { gameState = 'playerWin'; showGameResult('You Win!'); LK.getSound('gameWin').play(); return; } if (checkDraw(gameBoard)) { gameState = 'draw'; showGameResult('Draw!'); LK.getSound('gameDraw').play(); return; } waitingForAI = true; LK.setTimeout(function () { makeAIMove(); waitingForAI = false; }, 500); } }; self.placeSymbol = function (symbol) { if (self.symbol !== null) { return; } self.symbol = symbol; gameBoard[self.row][self.col] = symbol; var assetName = symbol === 'X' ? 'xSymbol' : 'oSymbol'; self.symbolGraphic = self.attachAsset(assetName, { anchorX: 0.5, anchorY: 0.5, scaleX: 0.1, scaleY: 0.1 }); tween(self.symbolGraphic, { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.bounceOut }); }; return self; }); var MenuButton = Container.expand(function (text, difficulty) { var self = Container.call(this); var buttonBg = self.attachAsset('buttonBackground', { anchorX: 0.5, anchorY: 0.5 }); var buttonText = new Text2(text, { size: 60, fill: 0xFFFFFF }); buttonText.anchor.set(0.5, 0.5); self.addChild(buttonText); self.difficulty = difficulty; self.isHovered = false; self.down = function (x, y, obj) { tween(buttonBg, { scaleX: 0.95, scaleY: 0.95 }, { duration: 100 }); currentDifficulty = self.difficulty; gameState = 'playing'; initializeGame(); }; self.up = function (x, y, obj) { tween(buttonBg, { scaleX: 1, scaleY: 1 }, { duration: 100 }); }; return self; }); var TutorialOverlay = Container.expand(function (message) { var self = Container.call(this); var overlay = self.attachAsset('tutorialOverlay', { anchorX: 0.5, anchorY: 0.5, alpha: 0.8 }); var messageText = new Text2(message, { size: 80, fill: 0xFFFFFF }); messageText.anchor.set(0.5, 0.5); self.addChild(messageText); self.down = function (x, y, obj) { self.destroy(); tutorialStep++; showNextTutorial(); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x1a1a1a }); /**** * Game Code ****/ var gameState = 'menu'; // menu, playing, playerWin, aiWin, draw var currentDifficulty = 'EASY'; var gameBoard = []; var gridCells = []; var playerSymbol = 'X'; var aiSymbol = 'O'; var waitingForAI = false; var tutorialStep = 0; var tutorialOverlay = null; // Menu elements var menuButtons = []; var gameGrid = null; var resultText = null; var playAgainButton = null; // Tutorial messages var tutorialMessages = ["Welcome to Tic-Tac-Toe!\nTap to continue...", "Goal: Get 3 symbols in a row\n(horizontal, vertical, or diagonal)", "You are X, AI is O\nYou go first - tap any cell!", "Watch how the AI responds\nto your moves!", "Good luck! Tap to start playing..."]; function initializeMenu() { gameState = 'menu'; // Clear existing elements if (gameGrid) { gameGrid.destroy(); gameGrid = null; } if (resultText) { resultText.destroy(); resultText = null; } if (playAgainButton) { playAgainButton.destroy(); playAgainButton = null; } // Create menu buttons var difficulties = ['BEGINNER', 'EASY', 'MEDIUM', 'HARD']; var buttonSpacing = 200; var startY = 1366 - difficulties.length * buttonSpacing / 2; for (var i = 0; i < difficulties.length; i++) { var button = new MenuButton(difficulties[i], difficulties[i]); button.x = 1024; button.y = startY + i * buttonSpacing; menuButtons.push(button); game.addChild(button); } // Title var titleText = new Text2('Tic-Tac-Toe Master', { size: 120, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 400; game.addChild(titleText); } function initializeGame() { // Clear menu for (var i = 0; i < menuButtons.length; i++) { menuButtons[i].destroy(); } menuButtons = []; // Random symbol assignment if (Math.random() < 0.5) { playerSymbol = 'X'; aiSymbol = 'O'; } else { playerSymbol = 'O'; aiSymbol = 'X'; } // Initialize game board gameBoard = [[null, null, null], [null, null, null], [null, null, null]]; // Create grid createGrid(); // Show tutorial for beginner mode if (currentDifficulty === 'BEGINNER') { tutorialStep = 0; showNextTutorial(); } } function createGrid() { gameGrid = new Container(); game.addChild(gameGrid); // Center the grid gameGrid.x = 1024; gameGrid.y = 1366; // Create grid background var gridBg = gameGrid.attachAsset('gridBackground', { anchorX: 0.5, anchorY: 0.5 }); // Create cells gridCells = []; for (var row = 0; row < 3; row++) { gridCells[row] = []; for (var col = 0; col < 3; col++) { var cell = new GridCell(row, col); cell.x = (col - 1) * 200; cell.y = (row - 1) * 200; gridCells[row][col] = cell; gameGrid.addChild(cell); } } } function showNextTutorial() { if (currentDifficulty !== 'BEGINNER' || tutorialStep >= tutorialMessages.length) { return; } tutorialOverlay = new TutorialOverlay(tutorialMessages[tutorialStep]); tutorialOverlay.x = 1024; tutorialOverlay.y = 1366; game.addChild(tutorialOverlay); } function makeAIMove() { var availableMoves = []; // Find available moves for (var row = 0; row < 3; row++) { for (var col = 0; col < 3; col++) { if (gameBoard[row][col] === null) { availableMoves.push({ row: row, col: col }); } } } if (availableMoves.length === 0) { return; } var move = null; switch (currentDifficulty) { case 'BEGINNER': case 'EASY': // Random move move = availableMoves[Math.floor(Math.random() * availableMoves.length)]; break; case 'MEDIUM': // Try to win, then block, then random move = findWinningMove(gameBoard, aiSymbol) || findWinningMove(gameBoard, playerSymbol) || availableMoves[Math.floor(Math.random() * availableMoves.length)]; break; case 'HARD': // Strategic AI move = getBestMove(gameBoard, aiSymbol); break; } if (move) { gridCells[move.row][move.col].placeSymbol(aiSymbol); if (checkWin(gameBoard, aiSymbol)) { gameState = 'aiWin'; showGameResult('AI Wins!'); LK.getSound('gameLose').play(); } else if (checkDraw(gameBoard)) { gameState = 'draw'; showGameResult('Draw!'); LK.getSound('gameDraw').play(); } } } function findWinningMove(board, symbol) { for (var row = 0; row < 3; row++) { for (var col = 0; col < 3; col++) { if (board[row][col] === null) { board[row][col] = symbol; if (checkWin(board, symbol)) { board[row][col] = null; return { row: row, col: col }; } board[row][col] = null; } } } return null; } function getBestMove(board, symbol) { var bestScore = -Infinity; var bestMove = null; for (var row = 0; row < 3; row++) { for (var col = 0; col < 3; col++) { if (board[row][col] === null) { board[row][col] = symbol; var score = minimax(board, 0, false, symbol); board[row][col] = null; if (score > bestScore) { bestScore = score; bestMove = { row: row, col: col }; } } } } return bestMove; } function minimax(board, depth, isMaximizing, aiSym) { var playerSym = aiSym === 'X' ? 'O' : 'X'; if (checkWin(board, aiSym)) { return 10 - depth; } if (checkWin(board, playerSym)) { return depth - 10; } if (checkDraw(board)) { return 0; } if (isMaximizing) { var bestScore = -Infinity; for (var row = 0; row < 3; row++) { for (var col = 0; col < 3; col++) { if (board[row][col] === null) { board[row][col] = aiSym; var score = minimax(board, depth + 1, false, aiSym); board[row][col] = null; bestScore = Math.max(score, bestScore); } } } return bestScore; } else { var bestScore = Infinity; for (var row = 0; row < 3; row++) { for (var col = 0; col < 3; col++) { if (board[row][col] === null) { board[row][col] = playerSym; var score = minimax(board, depth + 1, true, aiSym); board[row][col] = null; bestScore = Math.min(score, bestScore); } } } return bestScore; } } function checkWin(board, symbol) { // Check rows for (var row = 0; row < 3; row++) { if (board[row][0] === symbol && board[row][1] === symbol && board[row][2] === symbol) { return true; } } // Check columns for (var col = 0; col < 3; col++) { if (board[0][col] === symbol && board[1][col] === symbol && board[2][col] === symbol) { return true; } } // Check diagonals if (board[0][0] === symbol && board[1][1] === symbol && board[2][2] === symbol) { return true; } if (board[0][2] === symbol && board[1][1] === symbol && board[2][0] === symbol) { return true; } return false; } function checkDraw(board) { for (var row = 0; row < 3; row++) { for (var col = 0; col < 3; col++) { if (board[row][col] === null) { return false; } } } return true; } function showGameResult(message) { resultText = new Text2(message, { size: 100, fill: 0xFFFFFF }); resultText.anchor.set(0.5, 0.5); resultText.x = 1024; resultText.y = 800; game.addChild(resultText); // Play again button playAgainButton = new MenuButton('Play Again', 'playAgain'); playAgainButton.x = 1024; playAgainButton.y = 1000; playAgainButton.down = function () { initializeMenu(); }; game.addChild(playAgainButton); } // Initialize menu on start initializeMenu(); game.update = function () { // Main game loop - most logic handled in event handlers };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var GridCell = Container.expand(function (row, col) {
var self = Container.call(this);
var cellBg = self.attachAsset('gridCell', {
anchorX: 0.5,
anchorY: 0.5
});
self.row = row;
self.col = col;
self.symbol = null;
self.symbolGraphic = null;
self.down = function (x, y, obj) {
if (gameState === 'playing' && self.symbol === null && !waitingForAI) {
self.placeSymbol(playerSymbol);
LK.getSound('placeSymbol').play();
if (checkWin(gameBoard, playerSymbol)) {
gameState = 'playerWin';
showGameResult('You Win!');
LK.getSound('gameWin').play();
return;
}
if (checkDraw(gameBoard)) {
gameState = 'draw';
showGameResult('Draw!');
LK.getSound('gameDraw').play();
return;
}
waitingForAI = true;
LK.setTimeout(function () {
makeAIMove();
waitingForAI = false;
}, 500);
}
};
self.placeSymbol = function (symbol) {
if (self.symbol !== null) {
return;
}
self.symbol = symbol;
gameBoard[self.row][self.col] = symbol;
var assetName = symbol === 'X' ? 'xSymbol' : 'oSymbol';
self.symbolGraphic = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.1,
scaleY: 0.1
});
tween(self.symbolGraphic, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.bounceOut
});
};
return self;
});
var MenuButton = Container.expand(function (text, difficulty) {
var self = Container.call(this);
var buttonBg = self.attachAsset('buttonBackground', {
anchorX: 0.5,
anchorY: 0.5
});
var buttonText = new Text2(text, {
size: 60,
fill: 0xFFFFFF
});
buttonText.anchor.set(0.5, 0.5);
self.addChild(buttonText);
self.difficulty = difficulty;
self.isHovered = false;
self.down = function (x, y, obj) {
tween(buttonBg, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100
});
currentDifficulty = self.difficulty;
gameState = 'playing';
initializeGame();
};
self.up = function (x, y, obj) {
tween(buttonBg, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
};
return self;
});
var TutorialOverlay = Container.expand(function (message) {
var self = Container.call(this);
var overlay = self.attachAsset('tutorialOverlay', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8
});
var messageText = new Text2(message, {
size: 80,
fill: 0xFFFFFF
});
messageText.anchor.set(0.5, 0.5);
self.addChild(messageText);
self.down = function (x, y, obj) {
self.destroy();
tutorialStep++;
showNextTutorial();
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a1a
});
/****
* Game Code
****/
var gameState = 'menu'; // menu, playing, playerWin, aiWin, draw
var currentDifficulty = 'EASY';
var gameBoard = [];
var gridCells = [];
var playerSymbol = 'X';
var aiSymbol = 'O';
var waitingForAI = false;
var tutorialStep = 0;
var tutorialOverlay = null;
// Menu elements
var menuButtons = [];
var gameGrid = null;
var resultText = null;
var playAgainButton = null;
// Tutorial messages
var tutorialMessages = ["Welcome to Tic-Tac-Toe!\nTap to continue...", "Goal: Get 3 symbols in a row\n(horizontal, vertical, or diagonal)", "You are X, AI is O\nYou go first - tap any cell!", "Watch how the AI responds\nto your moves!", "Good luck! Tap to start playing..."];
function initializeMenu() {
gameState = 'menu';
// Clear existing elements
if (gameGrid) {
gameGrid.destroy();
gameGrid = null;
}
if (resultText) {
resultText.destroy();
resultText = null;
}
if (playAgainButton) {
playAgainButton.destroy();
playAgainButton = null;
}
// Create menu buttons
var difficulties = ['BEGINNER', 'EASY', 'MEDIUM', 'HARD'];
var buttonSpacing = 200;
var startY = 1366 - difficulties.length * buttonSpacing / 2;
for (var i = 0; i < difficulties.length; i++) {
var button = new MenuButton(difficulties[i], difficulties[i]);
button.x = 1024;
button.y = startY + i * buttonSpacing;
menuButtons.push(button);
game.addChild(button);
}
// Title
var titleText = new Text2('Tic-Tac-Toe Master', {
size: 120,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 400;
game.addChild(titleText);
}
function initializeGame() {
// Clear menu
for (var i = 0; i < menuButtons.length; i++) {
menuButtons[i].destroy();
}
menuButtons = [];
// Random symbol assignment
if (Math.random() < 0.5) {
playerSymbol = 'X';
aiSymbol = 'O';
} else {
playerSymbol = 'O';
aiSymbol = 'X';
}
// Initialize game board
gameBoard = [[null, null, null], [null, null, null], [null, null, null]];
// Create grid
createGrid();
// Show tutorial for beginner mode
if (currentDifficulty === 'BEGINNER') {
tutorialStep = 0;
showNextTutorial();
}
}
function createGrid() {
gameGrid = new Container();
game.addChild(gameGrid);
// Center the grid
gameGrid.x = 1024;
gameGrid.y = 1366;
// Create grid background
var gridBg = gameGrid.attachAsset('gridBackground', {
anchorX: 0.5,
anchorY: 0.5
});
// Create cells
gridCells = [];
for (var row = 0; row < 3; row++) {
gridCells[row] = [];
for (var col = 0; col < 3; col++) {
var cell = new GridCell(row, col);
cell.x = (col - 1) * 200;
cell.y = (row - 1) * 200;
gridCells[row][col] = cell;
gameGrid.addChild(cell);
}
}
}
function showNextTutorial() {
if (currentDifficulty !== 'BEGINNER' || tutorialStep >= tutorialMessages.length) {
return;
}
tutorialOverlay = new TutorialOverlay(tutorialMessages[tutorialStep]);
tutorialOverlay.x = 1024;
tutorialOverlay.y = 1366;
game.addChild(tutorialOverlay);
}
function makeAIMove() {
var availableMoves = [];
// Find available moves
for (var row = 0; row < 3; row++) {
for (var col = 0; col < 3; col++) {
if (gameBoard[row][col] === null) {
availableMoves.push({
row: row,
col: col
});
}
}
}
if (availableMoves.length === 0) {
return;
}
var move = null;
switch (currentDifficulty) {
case 'BEGINNER':
case 'EASY':
// Random move
move = availableMoves[Math.floor(Math.random() * availableMoves.length)];
break;
case 'MEDIUM':
// Try to win, then block, then random
move = findWinningMove(gameBoard, aiSymbol) || findWinningMove(gameBoard, playerSymbol) || availableMoves[Math.floor(Math.random() * availableMoves.length)];
break;
case 'HARD':
// Strategic AI
move = getBestMove(gameBoard, aiSymbol);
break;
}
if (move) {
gridCells[move.row][move.col].placeSymbol(aiSymbol);
if (checkWin(gameBoard, aiSymbol)) {
gameState = 'aiWin';
showGameResult('AI Wins!');
LK.getSound('gameLose').play();
} else if (checkDraw(gameBoard)) {
gameState = 'draw';
showGameResult('Draw!');
LK.getSound('gameDraw').play();
}
}
}
function findWinningMove(board, symbol) {
for (var row = 0; row < 3; row++) {
for (var col = 0; col < 3; col++) {
if (board[row][col] === null) {
board[row][col] = symbol;
if (checkWin(board, symbol)) {
board[row][col] = null;
return {
row: row,
col: col
};
}
board[row][col] = null;
}
}
}
return null;
}
function getBestMove(board, symbol) {
var bestScore = -Infinity;
var bestMove = null;
for (var row = 0; row < 3; row++) {
for (var col = 0; col < 3; col++) {
if (board[row][col] === null) {
board[row][col] = symbol;
var score = minimax(board, 0, false, symbol);
board[row][col] = null;
if (score > bestScore) {
bestScore = score;
bestMove = {
row: row,
col: col
};
}
}
}
}
return bestMove;
}
function minimax(board, depth, isMaximizing, aiSym) {
var playerSym = aiSym === 'X' ? 'O' : 'X';
if (checkWin(board, aiSym)) {
return 10 - depth;
}
if (checkWin(board, playerSym)) {
return depth - 10;
}
if (checkDraw(board)) {
return 0;
}
if (isMaximizing) {
var bestScore = -Infinity;
for (var row = 0; row < 3; row++) {
for (var col = 0; col < 3; col++) {
if (board[row][col] === null) {
board[row][col] = aiSym;
var score = minimax(board, depth + 1, false, aiSym);
board[row][col] = null;
bestScore = Math.max(score, bestScore);
}
}
}
return bestScore;
} else {
var bestScore = Infinity;
for (var row = 0; row < 3; row++) {
for (var col = 0; col < 3; col++) {
if (board[row][col] === null) {
board[row][col] = playerSym;
var score = minimax(board, depth + 1, true, aiSym);
board[row][col] = null;
bestScore = Math.min(score, bestScore);
}
}
}
return bestScore;
}
}
function checkWin(board, symbol) {
// Check rows
for (var row = 0; row < 3; row++) {
if (board[row][0] === symbol && board[row][1] === symbol && board[row][2] === symbol) {
return true;
}
}
// Check columns
for (var col = 0; col < 3; col++) {
if (board[0][col] === symbol && board[1][col] === symbol && board[2][col] === symbol) {
return true;
}
}
// Check diagonals
if (board[0][0] === symbol && board[1][1] === symbol && board[2][2] === symbol) {
return true;
}
if (board[0][2] === symbol && board[1][1] === symbol && board[2][0] === symbol) {
return true;
}
return false;
}
function checkDraw(board) {
for (var row = 0; row < 3; row++) {
for (var col = 0; col < 3; col++) {
if (board[row][col] === null) {
return false;
}
}
}
return true;
}
function showGameResult(message) {
resultText = new Text2(message, {
size: 100,
fill: 0xFFFFFF
});
resultText.anchor.set(0.5, 0.5);
resultText.x = 1024;
resultText.y = 800;
game.addChild(resultText);
// Play again button
playAgainButton = new MenuButton('Play Again', 'playAgain');
playAgainButton.x = 1024;
playAgainButton.y = 1000;
playAgainButton.down = function () {
initializeMenu();
};
game.addChild(playAgainButton);
}
// Initialize menu on start
initializeMenu();
game.update = function () {
// Main game loop - most logic handled in event handlers
};