Code edit (1 edits merged)
Please save this source code
User prompt
Strategic Grid Conquest
Initial prompt
make othello game but not black and white do it orange and grey on table have grids 10x10, with numbers and alphabet characters on its sides, do a button an the to right corner 300x100 with text coordinates and when click on it show a background of the movements of each player.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Cell = Container.expand(function () { var self = Container.call(this); var cellGraphics = self.attachAsset('cell', { anchorX: 0.5, anchorY: 0.5 }); self.row = 0; self.col = 0; self.piece = null; self.down = function (x, y, obj) { if (!self.piece && currentPlayer === 0) { placePiece(self.row, self.col); } }; return self; }); var CoordButton = Container.expand(function () { var self = Container.call(this); var buttonBg = self.attachAsset('coordButton', { anchorX: 0.5, anchorY: 0.5 }); self.down = function (x, y, obj) { toggleHistory(); }; return self; }); var HistoryPanel = Container.expand(function () { var self = Container.call(this); var bg = self.attachAsset('historyBg', { anchorX: 0.5, anchorY: 0.5 }); var titleText = new Text2('Move History', { size: 65, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0); titleText.y = -960; self.addChild(titleText); self.historyText = new Text2('', { size: 60, fill: 0xFFFFFF }); self.historyText.anchor.set(0.5, 0); self.historyText.y = -880; self.addChild(self.historyText); self.updateHistory = function () { var historyString = ''; for (var i = 0; i < moveHistory.length; i++) { var move = moveHistory[i]; var player = move.player === 0 ? 'Orange' : 'Grey'; historyString += player + ': ' + move.coord + '\n'; } self.historyText.setText(historyString); }; self.down = function (x, y, obj) { toggleHistory(); }; return self; }); var IntroButton = Container.expand(function () { var self = Container.call(this); var buttonBg = self.attachAsset('startButton', { anchorX: 0.5, anchorY: 0.5 }); self.down = function (x, y, obj) { if (introScreen && !levelSelectionScreen) { introScreen.destroy(); introScreen = null; createLevelSelection(); } }; return self; }); var LevelButton = Container.expand(function () { var self = Container.call(this); self.levelNumber = 1; self.isSelected = false; self.buttonBg = self.attachAsset('levelButton', { anchorX: 0.5, anchorY: 0.5 }); self.levelText = new Text2('1', { size: 60, fill: 0xFFFFFF }); self.levelText.anchor.set(0.5, 0.5); self.addChild(self.levelText); self.setLevel = function (level) { self.levelNumber = level; self.levelText.setText(level.toString()); }; self.setSelected = function (selected) { if (self.isSelected === selected) return; self.isSelected = selected; self.removeChild(self.buttonBg); if (selected) { self.buttonBg = self.attachAsset('selectedLevelButton', { anchorX: 0.5, anchorY: 0.5 }); } else { self.buttonBg = self.attachAsset('levelButton', { anchorX: 0.5, anchorY: 0.5 }); } // Make sure text is on top self.removeChild(self.levelText); self.addChild(self.levelText); }; self.down = function (x, y, obj) { if (!gameStarted && levelSelectionScreen) { selectLevel(self.levelNumber); } }; return self; }); var Piece = Container.expand(function () { var self = Container.call(this); self.player = 0; // 0 for orange, 1 for grey self.graphics = null; self.setPlayer = function (player) { if (self.graphics) { self.graphics.destroy(); } self.player = player; var assetId = player === 0 ? 'orangePiece' : 'greyPiece'; self.graphics = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); }; self.flip = function () { tween(self, { scaleX: 0 }, { duration: 150, onFinish: function onFinish() { self.setPlayer(1 - self.player); tween(self, { scaleX: 1 }, { duration: 150 }); } }); }; return self; }); var StartButton = Container.expand(function () { var self = Container.call(this); var buttonBg = self.attachAsset('startButton', { anchorX: 0.5, anchorY: 0.5 }); self.down = function (x, y, obj) { if (levelSelectionScreen && !gameStarted && selectedLevel > 0) { levelSelectionScreen.destroy(); levelSelectionScreen = null; gameStarted = true; initializeGame(); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x1a3a1a }); /**** * Game Code ****/ var BOARD_SIZE = 10; var board = []; var cells = []; var currentPlayer = 0; // 0 for orange, 1 for grey var moveHistory = []; var historyPanel = null; var historyVisible = false; var introScreen = null; var levelSelectionScreen = null; var gameStarted = false; var boardContainer = null; var selectedLevel = 0; var levelButtons = []; var levelStartButton = null; var currentDifficulty = 1; // Stores the calculated difficulty for current level // Create intro screen introScreen = new Container(); game.addChild(introScreen); // Add intro background var introBg = LK.getAsset('introBackground', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1366 }); introScreen.addChild(introBg); // Add intro button var introButton = new IntroButton(); introButton.x = 1024; introButton.y = 2732 - 200; // 200px from bottom introScreen.addChild(introButton); // Game variables that need to be accessible var orangeCountText = null; var greyCountText = null; var playerText = null; var coordButton = null; var letters = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J']; var setupMode = false; function createLevelSelection() { // Create level selection screen levelSelectionScreen = new Container(); game.addChild(levelSelectionScreen); // Add level selection background var levelBg = LK.getAsset('levelsBackground', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1366 }); levelSelectionScreen.addChild(levelBg); // Add title text var titleText = new Text2('SELECT LEVEL', { size: 100, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 400; levelSelectionScreen.addChild(titleText); // Create 50 level buttons in a 5x10 grid to fill the screen var buttonSpacing = 180; var startX = 1024 - (5 * buttonSpacing - buttonSpacing) / 2; var startY = 650; levelButtons = []; // Reset level buttons array for (var i = 0; i < 50; i++) { var levelButton = new LevelButton(); levelButton.setLevel(i + 1); var row = Math.floor(i / 5); var col = i % 5; levelButton.x = startX + col * buttonSpacing; levelButton.y = startY + row * buttonSpacing; levelButtons.push(levelButton); levelSelectionScreen.addChild(levelButton); } // Add start button (initially hidden) levelStartButton = new StartButton(); levelStartButton.x = 1024; levelStartButton.y = 2732 - 200; // 200px from bottom levelStartButton.visible = false; levelSelectionScreen.addChild(levelStartButton); } function getDifficultySettings(level) { // Progressive difficulty scaling from level 1-50 var settings = { aiType: 'easy', // easy, medium, hard, expert startingPieces: 4, // Number of starting pieces (2x2, 3x3, etc.) aiDelay: 500, // AI thinking time in ms cornerBonus: 0, // Strategic corner bonus for AI edgeBonus: 0, // Strategic edge bonus for AI mobilityWeight: 0 // How much AI considers limiting opponent moves }; if (level <= 10) { // Levels 1-10: Easy AI, standard setup settings.aiType = 'easy'; settings.aiDelay = 500; } else if (level <= 20) { // Levels 11-20: Medium AI with slight strategic thinking settings.aiType = 'medium'; settings.aiDelay = 400; settings.cornerBonus = 10; } else if (level <= 35) { // Levels 21-35: Hard AI with better strategy settings.aiType = 'hard'; settings.aiDelay = 300; settings.cornerBonus = 20; settings.edgeBonus = 5; settings.mobilityWeight = 5; } else { // Levels 36-50: Expert AI with advanced strategy settings.aiType = 'expert'; settings.aiDelay = 200; settings.cornerBonus = 30; settings.edgeBonus = 10; settings.mobilityWeight = 10; } // Adjust starting pieces based on level if (level <= 15) { settings.startingPieces = 4; // 2x2 center } else if (level <= 30) { settings.startingPieces = 6; // 2x3 center } else { settings.startingPieces = 8; // 2x4 center - more challenging start } return settings; } function selectLevel(level) { selectedLevel = level; currentDifficulty = getDifficultySettings(level); // Update all buttons - deselect all first for (var i = 0; i < levelButtons.length; i++) { levelButtons[i].setSelected(false); } // Select the chosen level button if (level >= 1 && level <= 50) { levelButtons[level - 1].setSelected(true); } // Show start button if (levelStartButton) { levelStartButton.visible = true; } } function initializeGame() { // Create board container boardContainer = new Container(); boardContainer.x = 1024; boardContainer.y = 1366; game.addChild(boardContainer); // Create board background var boardBg = LK.getAsset('boardBg', { anchorX: 0.5, anchorY: 0.5 }); boardContainer.addChild(boardBg); // Create piece count texts orangeCountText = new Text2('Orange: 2', { size: 80, fill: 0xFF8C00 }); orangeCountText.anchor.set(0, 0.5); orangeCountText.x = -900; orangeCountText.y = 1000; boardContainer.addChild(orangeCountText); greyCountText = new Text2('Grey: 2', { size: 80, fill: 0x808080 }); greyCountText.anchor.set(1, 0.5); greyCountText.x = 900; greyCountText.y = 1000; boardContainer.addChild(greyCountText); // Initialize board array and create cells var cellSpacing = 1850 / BOARD_SIZE; for (var row = 0; row < BOARD_SIZE; row++) { board[row] = []; cells[row] = []; for (var col = 0; col < BOARD_SIZE; col++) { board[row][col] = null; var cell = new Cell(); cell.row = row; cell.col = col; cell.x = (col - 4.5) * cellSpacing; cell.y = (row - 4.5) * cellSpacing; boardContainer.addChild(cell); cells[row][col] = cell; } } // Create coordinate labels var cellSpacing = 1850 / BOARD_SIZE; for (var i = 0; i < BOARD_SIZE; i++) { // Column labels (A-J) var colLabel = new Text2(letters[i], { size: 40, fill: 0xFFFFFF }); colLabel.anchor.set(0.5, 0.5); colLabel.x = (i - 4.5) * cellSpacing; colLabel.y = -945; boardContainer.addChild(colLabel); // Row labels (1-10) var rowLabel = new Text2((i + 1).toString(), { size: 40, fill: 0xFFFFFF }); rowLabel.anchor.set(0.5, 0.5); rowLabel.x = -945; rowLabel.y = (i - 4.5) * cellSpacing; boardContainer.addChild(rowLabel); } // Create current player indicator playerText = new Text2('Current Player: Orange', { size: 60, fill: 0xFF8C00 }); playerText.anchor.set(0.5, 0); playerText.y = 100; LK.gui.top.addChild(playerText); // Create coordinates button coordButton = new CoordButton(); coordButton.x = -100; coordButton.y = 100; LK.gui.topRight.addChild(coordButton); // Create history panel (initially hidden) historyPanel = new HistoryPanel(); historyPanel.visible = false; game.addChild(historyPanel); historyPanel.x = 1024; historyPanel.y = 1366; // Initialize with starting pieces based on difficulty setupMode = true; var difficulty = getDifficultySettings(selectedLevel); if (difficulty.startingPieces === 4) { // Standard 2x2 center placePiece(4, 4); placePiece(4, 5); placePiece(5, 5); placePiece(5, 4); } else if (difficulty.startingPieces === 6) { // 2x3 center setup - more challenging placePiece(4, 4); placePiece(4, 5); placePiece(5, 4); placePiece(5, 5); placePiece(4, 6); placePiece(5, 6); } else if (difficulty.startingPieces === 8) { // 2x4 center setup - most challenging placePiece(4, 3); placePiece(4, 4); placePiece(4, 5); placePiece(4, 6); placePiece(5, 3); placePiece(5, 4); placePiece(5, 5); placePiece(5, 6); } setupMode = false; // Reset to orange player's turn currentPlayer = 0; updatePlayerText(); updatePieceCounts(); } // Game functions function getCoordinate(row, col) { return letters[col] + (row + 1); } function placePiece(row, col) { if (!gameStarted || board[row][col] !== null) return; // Create and place piece var piece = new Piece(); piece.setPlayer(currentPlayer); cells[row][col].addChild(piece); cells[row][col].piece = piece; board[row][col] = currentPlayer; // Play place sound LK.getSound('place').play(); // Add to move history moveHistory.push({ player: currentPlayer, coord: getCoordinate(row, col) }); // Update history panel if visible if (historyVisible && historyPanel) { historyPanel.updateHistory(); } // Check for flips in all directions var directions = [[-1, 0], [1, 0], [0, -1], [0, 1], // vertical and horizontal [-1, -1], [-1, 1], [1, -1], [1, 1] // diagonals ]; var totalFlips = 0; for (var d = 0; d < directions.length; d++) { var flips = checkDirection(row, col, directions[d][0], directions[d][1]); if (flips.length > 0) { flipPieces(flips); totalFlips += flips.length; } } if (totalFlips > 0) { LK.getSound('flip').play(); } // Update piece counts updatePieceCounts(); // Switch player currentPlayer = 1 - currentPlayer; updatePlayerText(); // Check for game over checkGameOver(); // If it's now grey's turn (AI), make AI move if (currentPlayer === 1 && !setupMode) { makeAIMove(); } } function checkDirection(row, col, dRow, dCol) { var flips = []; var r = row + dRow; var c = col + dCol; // Find opponent pieces while (r >= 0 && r < BOARD_SIZE && c >= 0 && c < BOARD_SIZE) { if (board[r][c] === null) { return []; } if (board[r][c] === currentPlayer) { return flips; } flips.push([r, c]); r += dRow; c += dCol; } return []; } function flipPieces(positions) { for (var i = 0; i < positions.length; i++) { var row = positions[i][0]; var col = positions[i][1]; board[row][col] = currentPlayer; cells[row][col].piece.flip(); } } function updatePlayerText() { var player = currentPlayer === 0 ? 'Orange' : 'Grey'; var color = currentPlayer === 0 ? 0xff8c00 : 0x808080; playerText.setText('Current Player: ' + player); // Remove old text and create new one with updated color LK.gui.top.removeChild(playerText); playerText = new Text2('Current Player: ' + player, { size: 60, fill: color }); playerText.anchor.set(0.5, 0); playerText.y = 100; LK.gui.top.addChild(playerText); } function updatePieceCounts() { var orangeCount = 0; var greyCount = 0; for (var row = 0; row < BOARD_SIZE; row++) { for (var col = 0; col < BOARD_SIZE; col++) { if (board[row][col] === 0) { orangeCount++; } else if (board[row][col] === 1) { greyCount++; } } } orangeCountText.setText('Orange: ' + orangeCount); greyCountText.setText('Grey: ' + greyCount); } function checkGameOver() { // Don't check for game over during initial setup if (setupMode) return; var hasEmpty = false; var orangeCount = 0; var greyCount = 0; var hasValidMove = false; for (var row = 0; row < BOARD_SIZE; row++) { for (var col = 0; col < BOARD_SIZE; col++) { if (board[row][col] === null) { hasEmpty = true; // Check if current player has valid move at this position if (!hasValidMove && isValidMove(row, col, currentPlayer)) { hasValidMove = true; } } else if (board[row][col] === 0) { orangeCount++; } else { greyCount++; } } } // Check for game over conditions if (!hasEmpty || !hasValidMove) { if (orangeCount > greyCount) { LK.showYouWin(); } else { LK.showGameOver(); } } } function toggleHistory() { historyVisible = !historyVisible; if (historyPanel) { historyPanel.visible = historyVisible; if (historyVisible) { historyPanel.updateHistory(); } } } // AI functions function isValidMove(row, col, player) { if (board[row][col] !== null) return false; var directions = [[-1, 0], [1, 0], [0, -1], [0, 1], [-1, -1], [-1, 1], [1, -1], [1, 1]]; for (var d = 0; d < directions.length; d++) { var flips = checkDirectionForPlayer(row, col, directions[d][0], directions[d][1], player); if (flips.length > 0) { return true; } } return false; } function checkDirectionForPlayer(row, col, dRow, dCol, player) { var flips = []; var r = row + dRow; var c = col + dCol; while (r >= 0 && r < BOARD_SIZE && c >= 0 && c < BOARD_SIZE) { if (board[r][c] === null) { return []; } if (board[r][c] === player) { return flips; } flips.push([r, c]); r += dRow; c += dCol; } return []; } function evaluateMove(row, col, player) { var directions = [[-1, 0], [1, 0], [0, -1], [0, 1], [-1, -1], [-1, 1], [1, -1], [1, 1]]; var totalFlips = 0; for (var d = 0; d < directions.length; d++) { var flips = checkDirectionForPlayer(row, col, directions[d][0], directions[d][1], player); totalFlips += flips.length; } var difficulty = getDifficultySettings(selectedLevel); var score = totalFlips; // Apply strategic bonuses based on difficulty level if (difficulty.aiType !== 'easy') { // Corner bonus - corners are very valuable if ((row === 0 || row === BOARD_SIZE - 1) && (col === 0 || col === BOARD_SIZE - 1)) { score += difficulty.cornerBonus; } // Edge bonus - edges are somewhat valuable else if (row === 0 || row === BOARD_SIZE - 1 || col === 0 || col === BOARD_SIZE - 1) { score += difficulty.edgeBonus; } // Mobility consideration - how many moves will opponent have after this move if (difficulty.mobilityWeight > 0) { var opponentMoves = countValidMovesAfterMove(row, col, player); score -= opponentMoves * difficulty.mobilityWeight; } // Avoid positions next to corners (they give opponent corner access) if (difficulty.aiType === 'hard' || difficulty.aiType === 'expert') { if (isNextToCorner(row, col)) { score -= 15; // Penalty for moves next to corners } } } return score; } function countValidMovesAfterMove(row, col, player) { // Simulate placing the piece and count opponent's valid moves var originalValue = board[row][col]; board[row][col] = player; var opponentPlayer = 1 - player; var count = 0; for (var r = 0; r < BOARD_SIZE; r++) { for (var c = 0; c < BOARD_SIZE; c++) { if (isValidMove(r, c, opponentPlayer)) { count++; } } } board[row][col] = originalValue; // Restore original state return count; } function isNextToCorner(row, col) { // Check if position is adjacent to a corner (bad strategic move) var corners = [[0, 0], [0, BOARD_SIZE - 1], [BOARD_SIZE - 1, 0], [BOARD_SIZE - 1, BOARD_SIZE - 1]]; for (var i = 0; i < corners.length; i++) { var cornerRow = corners[i][0]; var cornerCol = corners[i][1]; var rowDiff = Math.abs(row - cornerRow); var colDiff = Math.abs(col - cornerCol); if (rowDiff === 1 && colDiff === 0 || rowDiff === 0 && colDiff === 1 || rowDiff === 1 && colDiff === 1) { // Only penalize if the corner is empty (don't avoid if corner is already taken) if (board[cornerRow][cornerCol] === null) { return true; } } } return false; } function makeAIMove() { var validMoves = []; var difficulty = getDifficultySettings(selectedLevel); // Find all valid moves for (var row = 0; row < BOARD_SIZE; row++) { for (var col = 0; col < BOARD_SIZE; col++) { if (isValidMove(row, col, 1)) { validMoves.push({ row: row, col: col, score: evaluateMove(row, col, 1) }); } } } if (validMoves.length > 0) { var chosenMove; if (difficulty.aiType === 'easy') { // Easy AI: pick randomly from moves that flip at least 1 piece var movesWithFlips = []; for (var i = 0; i < validMoves.length; i++) { if (validMoves[i].score > 0) { movesWithFlips.push(validMoves[i]); } } if (movesWithFlips.length === 0) { movesWithFlips = validMoves; } var randomIndex = Math.floor(Math.random() * movesWithFlips.length); chosenMove = movesWithFlips[randomIndex]; } else if (difficulty.aiType === 'medium') { // Medium AI: pick from top 50% of moves validMoves.sort(function (a, b) { return b.score - a.score; }); var topHalf = Math.ceil(validMoves.length / 2); var randomIndex = Math.floor(Math.random() * topHalf); chosenMove = validMoves[randomIndex]; } else if (difficulty.aiType === 'hard') { // Hard AI: pick from top 25% of moves validMoves.sort(function (a, b) { return b.score - a.score; }); var topQuarter = Math.max(1, Math.ceil(validMoves.length / 4)); var randomIndex = Math.floor(Math.random() * topQuarter); chosenMove = validMoves[randomIndex]; } else { // expert // Expert AI: always pick the best move (with small randomness for variety) validMoves.sort(function (a, b) { return b.score - a.score; }); var bestScore = validMoves[0].score; var bestMoves = []; for (var i = 0; i < validMoves.length; i++) { if (validMoves[i].score === bestScore) { bestMoves.push(validMoves[i]); } else { break; // Stop when we leave the best moves } } var randomIndex = Math.floor(Math.random() * bestMoves.length); chosenMove = bestMoves[randomIndex]; } // Add difficulty-based delay to make AI move visible LK.setTimeout(function () { placePiece(chosenMove.row, chosenMove.col); }, difficulty.aiDelay); } } ;
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Cell = Container.expand(function () {
var self = Container.call(this);
var cellGraphics = self.attachAsset('cell', {
anchorX: 0.5,
anchorY: 0.5
});
self.row = 0;
self.col = 0;
self.piece = null;
self.down = function (x, y, obj) {
if (!self.piece && currentPlayer === 0) {
placePiece(self.row, self.col);
}
};
return self;
});
var CoordButton = Container.expand(function () {
var self = Container.call(this);
var buttonBg = self.attachAsset('coordButton', {
anchorX: 0.5,
anchorY: 0.5
});
self.down = function (x, y, obj) {
toggleHistory();
};
return self;
});
var HistoryPanel = Container.expand(function () {
var self = Container.call(this);
var bg = self.attachAsset('historyBg', {
anchorX: 0.5,
anchorY: 0.5
});
var titleText = new Text2('Move History', {
size: 65,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0);
titleText.y = -960;
self.addChild(titleText);
self.historyText = new Text2('', {
size: 60,
fill: 0xFFFFFF
});
self.historyText.anchor.set(0.5, 0);
self.historyText.y = -880;
self.addChild(self.historyText);
self.updateHistory = function () {
var historyString = '';
for (var i = 0; i < moveHistory.length; i++) {
var move = moveHistory[i];
var player = move.player === 0 ? 'Orange' : 'Grey';
historyString += player + ': ' + move.coord + '\n';
}
self.historyText.setText(historyString);
};
self.down = function (x, y, obj) {
toggleHistory();
};
return self;
});
var IntroButton = Container.expand(function () {
var self = Container.call(this);
var buttonBg = self.attachAsset('startButton', {
anchorX: 0.5,
anchorY: 0.5
});
self.down = function (x, y, obj) {
if (introScreen && !levelSelectionScreen) {
introScreen.destroy();
introScreen = null;
createLevelSelection();
}
};
return self;
});
var LevelButton = Container.expand(function () {
var self = Container.call(this);
self.levelNumber = 1;
self.isSelected = false;
self.buttonBg = self.attachAsset('levelButton', {
anchorX: 0.5,
anchorY: 0.5
});
self.levelText = new Text2('1', {
size: 60,
fill: 0xFFFFFF
});
self.levelText.anchor.set(0.5, 0.5);
self.addChild(self.levelText);
self.setLevel = function (level) {
self.levelNumber = level;
self.levelText.setText(level.toString());
};
self.setSelected = function (selected) {
if (self.isSelected === selected) return;
self.isSelected = selected;
self.removeChild(self.buttonBg);
if (selected) {
self.buttonBg = self.attachAsset('selectedLevelButton', {
anchorX: 0.5,
anchorY: 0.5
});
} else {
self.buttonBg = self.attachAsset('levelButton', {
anchorX: 0.5,
anchorY: 0.5
});
}
// Make sure text is on top
self.removeChild(self.levelText);
self.addChild(self.levelText);
};
self.down = function (x, y, obj) {
if (!gameStarted && levelSelectionScreen) {
selectLevel(self.levelNumber);
}
};
return self;
});
var Piece = Container.expand(function () {
var self = Container.call(this);
self.player = 0; // 0 for orange, 1 for grey
self.graphics = null;
self.setPlayer = function (player) {
if (self.graphics) {
self.graphics.destroy();
}
self.player = player;
var assetId = player === 0 ? 'orangePiece' : 'greyPiece';
self.graphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
};
self.flip = function () {
tween(self, {
scaleX: 0
}, {
duration: 150,
onFinish: function onFinish() {
self.setPlayer(1 - self.player);
tween(self, {
scaleX: 1
}, {
duration: 150
});
}
});
};
return self;
});
var StartButton = Container.expand(function () {
var self = Container.call(this);
var buttonBg = self.attachAsset('startButton', {
anchorX: 0.5,
anchorY: 0.5
});
self.down = function (x, y, obj) {
if (levelSelectionScreen && !gameStarted && selectedLevel > 0) {
levelSelectionScreen.destroy();
levelSelectionScreen = null;
gameStarted = true;
initializeGame();
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a3a1a
});
/****
* Game Code
****/
var BOARD_SIZE = 10;
var board = [];
var cells = [];
var currentPlayer = 0; // 0 for orange, 1 for grey
var moveHistory = [];
var historyPanel = null;
var historyVisible = false;
var introScreen = null;
var levelSelectionScreen = null;
var gameStarted = false;
var boardContainer = null;
var selectedLevel = 0;
var levelButtons = [];
var levelStartButton = null;
var currentDifficulty = 1; // Stores the calculated difficulty for current level
// Create intro screen
introScreen = new Container();
game.addChild(introScreen);
// Add intro background
var introBg = LK.getAsset('introBackground', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366
});
introScreen.addChild(introBg);
// Add intro button
var introButton = new IntroButton();
introButton.x = 1024;
introButton.y = 2732 - 200; // 200px from bottom
introScreen.addChild(introButton);
// Game variables that need to be accessible
var orangeCountText = null;
var greyCountText = null;
var playerText = null;
var coordButton = null;
var letters = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'];
var setupMode = false;
function createLevelSelection() {
// Create level selection screen
levelSelectionScreen = new Container();
game.addChild(levelSelectionScreen);
// Add level selection background
var levelBg = LK.getAsset('levelsBackground', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366
});
levelSelectionScreen.addChild(levelBg);
// Add title text
var titleText = new Text2('SELECT LEVEL', {
size: 100,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 400;
levelSelectionScreen.addChild(titleText);
// Create 50 level buttons in a 5x10 grid to fill the screen
var buttonSpacing = 180;
var startX = 1024 - (5 * buttonSpacing - buttonSpacing) / 2;
var startY = 650;
levelButtons = []; // Reset level buttons array
for (var i = 0; i < 50; i++) {
var levelButton = new LevelButton();
levelButton.setLevel(i + 1);
var row = Math.floor(i / 5);
var col = i % 5;
levelButton.x = startX + col * buttonSpacing;
levelButton.y = startY + row * buttonSpacing;
levelButtons.push(levelButton);
levelSelectionScreen.addChild(levelButton);
}
// Add start button (initially hidden)
levelStartButton = new StartButton();
levelStartButton.x = 1024;
levelStartButton.y = 2732 - 200; // 200px from bottom
levelStartButton.visible = false;
levelSelectionScreen.addChild(levelStartButton);
}
function getDifficultySettings(level) {
// Progressive difficulty scaling from level 1-50
var settings = {
aiType: 'easy',
// easy, medium, hard, expert
startingPieces: 4,
// Number of starting pieces (2x2, 3x3, etc.)
aiDelay: 500,
// AI thinking time in ms
cornerBonus: 0,
// Strategic corner bonus for AI
edgeBonus: 0,
// Strategic edge bonus for AI
mobilityWeight: 0 // How much AI considers limiting opponent moves
};
if (level <= 10) {
// Levels 1-10: Easy AI, standard setup
settings.aiType = 'easy';
settings.aiDelay = 500;
} else if (level <= 20) {
// Levels 11-20: Medium AI with slight strategic thinking
settings.aiType = 'medium';
settings.aiDelay = 400;
settings.cornerBonus = 10;
} else if (level <= 35) {
// Levels 21-35: Hard AI with better strategy
settings.aiType = 'hard';
settings.aiDelay = 300;
settings.cornerBonus = 20;
settings.edgeBonus = 5;
settings.mobilityWeight = 5;
} else {
// Levels 36-50: Expert AI with advanced strategy
settings.aiType = 'expert';
settings.aiDelay = 200;
settings.cornerBonus = 30;
settings.edgeBonus = 10;
settings.mobilityWeight = 10;
}
// Adjust starting pieces based on level
if (level <= 15) {
settings.startingPieces = 4; // 2x2 center
} else if (level <= 30) {
settings.startingPieces = 6; // 2x3 center
} else {
settings.startingPieces = 8; // 2x4 center - more challenging start
}
return settings;
}
function selectLevel(level) {
selectedLevel = level;
currentDifficulty = getDifficultySettings(level);
// Update all buttons - deselect all first
for (var i = 0; i < levelButtons.length; i++) {
levelButtons[i].setSelected(false);
}
// Select the chosen level button
if (level >= 1 && level <= 50) {
levelButtons[level - 1].setSelected(true);
}
// Show start button
if (levelStartButton) {
levelStartButton.visible = true;
}
}
function initializeGame() {
// Create board container
boardContainer = new Container();
boardContainer.x = 1024;
boardContainer.y = 1366;
game.addChild(boardContainer);
// Create board background
var boardBg = LK.getAsset('boardBg', {
anchorX: 0.5,
anchorY: 0.5
});
boardContainer.addChild(boardBg);
// Create piece count texts
orangeCountText = new Text2('Orange: 2', {
size: 80,
fill: 0xFF8C00
});
orangeCountText.anchor.set(0, 0.5);
orangeCountText.x = -900;
orangeCountText.y = 1000;
boardContainer.addChild(orangeCountText);
greyCountText = new Text2('Grey: 2', {
size: 80,
fill: 0x808080
});
greyCountText.anchor.set(1, 0.5);
greyCountText.x = 900;
greyCountText.y = 1000;
boardContainer.addChild(greyCountText);
// Initialize board array and create cells
var cellSpacing = 1850 / BOARD_SIZE;
for (var row = 0; row < BOARD_SIZE; row++) {
board[row] = [];
cells[row] = [];
for (var col = 0; col < BOARD_SIZE; col++) {
board[row][col] = null;
var cell = new Cell();
cell.row = row;
cell.col = col;
cell.x = (col - 4.5) * cellSpacing;
cell.y = (row - 4.5) * cellSpacing;
boardContainer.addChild(cell);
cells[row][col] = cell;
}
}
// Create coordinate labels
var cellSpacing = 1850 / BOARD_SIZE;
for (var i = 0; i < BOARD_SIZE; i++) {
// Column labels (A-J)
var colLabel = new Text2(letters[i], {
size: 40,
fill: 0xFFFFFF
});
colLabel.anchor.set(0.5, 0.5);
colLabel.x = (i - 4.5) * cellSpacing;
colLabel.y = -945;
boardContainer.addChild(colLabel);
// Row labels (1-10)
var rowLabel = new Text2((i + 1).toString(), {
size: 40,
fill: 0xFFFFFF
});
rowLabel.anchor.set(0.5, 0.5);
rowLabel.x = -945;
rowLabel.y = (i - 4.5) * cellSpacing;
boardContainer.addChild(rowLabel);
}
// Create current player indicator
playerText = new Text2('Current Player: Orange', {
size: 60,
fill: 0xFF8C00
});
playerText.anchor.set(0.5, 0);
playerText.y = 100;
LK.gui.top.addChild(playerText);
// Create coordinates button
coordButton = new CoordButton();
coordButton.x = -100;
coordButton.y = 100;
LK.gui.topRight.addChild(coordButton);
// Create history panel (initially hidden)
historyPanel = new HistoryPanel();
historyPanel.visible = false;
game.addChild(historyPanel);
historyPanel.x = 1024;
historyPanel.y = 1366;
// Initialize with starting pieces based on difficulty
setupMode = true;
var difficulty = getDifficultySettings(selectedLevel);
if (difficulty.startingPieces === 4) {
// Standard 2x2 center
placePiece(4, 4);
placePiece(4, 5);
placePiece(5, 5);
placePiece(5, 4);
} else if (difficulty.startingPieces === 6) {
// 2x3 center setup - more challenging
placePiece(4, 4);
placePiece(4, 5);
placePiece(5, 4);
placePiece(5, 5);
placePiece(4, 6);
placePiece(5, 6);
} else if (difficulty.startingPieces === 8) {
// 2x4 center setup - most challenging
placePiece(4, 3);
placePiece(4, 4);
placePiece(4, 5);
placePiece(4, 6);
placePiece(5, 3);
placePiece(5, 4);
placePiece(5, 5);
placePiece(5, 6);
}
setupMode = false;
// Reset to orange player's turn
currentPlayer = 0;
updatePlayerText();
updatePieceCounts();
}
// Game functions
function getCoordinate(row, col) {
return letters[col] + (row + 1);
}
function placePiece(row, col) {
if (!gameStarted || board[row][col] !== null) return;
// Create and place piece
var piece = new Piece();
piece.setPlayer(currentPlayer);
cells[row][col].addChild(piece);
cells[row][col].piece = piece;
board[row][col] = currentPlayer;
// Play place sound
LK.getSound('place').play();
// Add to move history
moveHistory.push({
player: currentPlayer,
coord: getCoordinate(row, col)
});
// Update history panel if visible
if (historyVisible && historyPanel) {
historyPanel.updateHistory();
}
// Check for flips in all directions
var directions = [[-1, 0], [1, 0], [0, -1], [0, 1],
// vertical and horizontal
[-1, -1], [-1, 1], [1, -1], [1, 1] // diagonals
];
var totalFlips = 0;
for (var d = 0; d < directions.length; d++) {
var flips = checkDirection(row, col, directions[d][0], directions[d][1]);
if (flips.length > 0) {
flipPieces(flips);
totalFlips += flips.length;
}
}
if (totalFlips > 0) {
LK.getSound('flip').play();
}
// Update piece counts
updatePieceCounts();
// Switch player
currentPlayer = 1 - currentPlayer;
updatePlayerText();
// Check for game over
checkGameOver();
// If it's now grey's turn (AI), make AI move
if (currentPlayer === 1 && !setupMode) {
makeAIMove();
}
}
function checkDirection(row, col, dRow, dCol) {
var flips = [];
var r = row + dRow;
var c = col + dCol;
// Find opponent pieces
while (r >= 0 && r < BOARD_SIZE && c >= 0 && c < BOARD_SIZE) {
if (board[r][c] === null) {
return [];
}
if (board[r][c] === currentPlayer) {
return flips;
}
flips.push([r, c]);
r += dRow;
c += dCol;
}
return [];
}
function flipPieces(positions) {
for (var i = 0; i < positions.length; i++) {
var row = positions[i][0];
var col = positions[i][1];
board[row][col] = currentPlayer;
cells[row][col].piece.flip();
}
}
function updatePlayerText() {
var player = currentPlayer === 0 ? 'Orange' : 'Grey';
var color = currentPlayer === 0 ? 0xff8c00 : 0x808080;
playerText.setText('Current Player: ' + player);
// Remove old text and create new one with updated color
LK.gui.top.removeChild(playerText);
playerText = new Text2('Current Player: ' + player, {
size: 60,
fill: color
});
playerText.anchor.set(0.5, 0);
playerText.y = 100;
LK.gui.top.addChild(playerText);
}
function updatePieceCounts() {
var orangeCount = 0;
var greyCount = 0;
for (var row = 0; row < BOARD_SIZE; row++) {
for (var col = 0; col < BOARD_SIZE; col++) {
if (board[row][col] === 0) {
orangeCount++;
} else if (board[row][col] === 1) {
greyCount++;
}
}
}
orangeCountText.setText('Orange: ' + orangeCount);
greyCountText.setText('Grey: ' + greyCount);
}
function checkGameOver() {
// Don't check for game over during initial setup
if (setupMode) return;
var hasEmpty = false;
var orangeCount = 0;
var greyCount = 0;
var hasValidMove = false;
for (var row = 0; row < BOARD_SIZE; row++) {
for (var col = 0; col < BOARD_SIZE; col++) {
if (board[row][col] === null) {
hasEmpty = true;
// Check if current player has valid move at this position
if (!hasValidMove && isValidMove(row, col, currentPlayer)) {
hasValidMove = true;
}
} else if (board[row][col] === 0) {
orangeCount++;
} else {
greyCount++;
}
}
}
// Check for game over conditions
if (!hasEmpty || !hasValidMove) {
if (orangeCount > greyCount) {
LK.showYouWin();
} else {
LK.showGameOver();
}
}
}
function toggleHistory() {
historyVisible = !historyVisible;
if (historyPanel) {
historyPanel.visible = historyVisible;
if (historyVisible) {
historyPanel.updateHistory();
}
}
}
// AI functions
function isValidMove(row, col, player) {
if (board[row][col] !== null) return false;
var directions = [[-1, 0], [1, 0], [0, -1], [0, 1], [-1, -1], [-1, 1], [1, -1], [1, 1]];
for (var d = 0; d < directions.length; d++) {
var flips = checkDirectionForPlayer(row, col, directions[d][0], directions[d][1], player);
if (flips.length > 0) {
return true;
}
}
return false;
}
function checkDirectionForPlayer(row, col, dRow, dCol, player) {
var flips = [];
var r = row + dRow;
var c = col + dCol;
while (r >= 0 && r < BOARD_SIZE && c >= 0 && c < BOARD_SIZE) {
if (board[r][c] === null) {
return [];
}
if (board[r][c] === player) {
return flips;
}
flips.push([r, c]);
r += dRow;
c += dCol;
}
return [];
}
function evaluateMove(row, col, player) {
var directions = [[-1, 0], [1, 0], [0, -1], [0, 1], [-1, -1], [-1, 1], [1, -1], [1, 1]];
var totalFlips = 0;
for (var d = 0; d < directions.length; d++) {
var flips = checkDirectionForPlayer(row, col, directions[d][0], directions[d][1], player);
totalFlips += flips.length;
}
var difficulty = getDifficultySettings(selectedLevel);
var score = totalFlips;
// Apply strategic bonuses based on difficulty level
if (difficulty.aiType !== 'easy') {
// Corner bonus - corners are very valuable
if ((row === 0 || row === BOARD_SIZE - 1) && (col === 0 || col === BOARD_SIZE - 1)) {
score += difficulty.cornerBonus;
}
// Edge bonus - edges are somewhat valuable
else if (row === 0 || row === BOARD_SIZE - 1 || col === 0 || col === BOARD_SIZE - 1) {
score += difficulty.edgeBonus;
}
// Mobility consideration - how many moves will opponent have after this move
if (difficulty.mobilityWeight > 0) {
var opponentMoves = countValidMovesAfterMove(row, col, player);
score -= opponentMoves * difficulty.mobilityWeight;
}
// Avoid positions next to corners (they give opponent corner access)
if (difficulty.aiType === 'hard' || difficulty.aiType === 'expert') {
if (isNextToCorner(row, col)) {
score -= 15; // Penalty for moves next to corners
}
}
}
return score;
}
function countValidMovesAfterMove(row, col, player) {
// Simulate placing the piece and count opponent's valid moves
var originalValue = board[row][col];
board[row][col] = player;
var opponentPlayer = 1 - player;
var count = 0;
for (var r = 0; r < BOARD_SIZE; r++) {
for (var c = 0; c < BOARD_SIZE; c++) {
if (isValidMove(r, c, opponentPlayer)) {
count++;
}
}
}
board[row][col] = originalValue; // Restore original state
return count;
}
function isNextToCorner(row, col) {
// Check if position is adjacent to a corner (bad strategic move)
var corners = [[0, 0], [0, BOARD_SIZE - 1], [BOARD_SIZE - 1, 0], [BOARD_SIZE - 1, BOARD_SIZE - 1]];
for (var i = 0; i < corners.length; i++) {
var cornerRow = corners[i][0];
var cornerCol = corners[i][1];
var rowDiff = Math.abs(row - cornerRow);
var colDiff = Math.abs(col - cornerCol);
if (rowDiff === 1 && colDiff === 0 || rowDiff === 0 && colDiff === 1 || rowDiff === 1 && colDiff === 1) {
// Only penalize if the corner is empty (don't avoid if corner is already taken)
if (board[cornerRow][cornerCol] === null) {
return true;
}
}
}
return false;
}
function makeAIMove() {
var validMoves = [];
var difficulty = getDifficultySettings(selectedLevel);
// Find all valid moves
for (var row = 0; row < BOARD_SIZE; row++) {
for (var col = 0; col < BOARD_SIZE; col++) {
if (isValidMove(row, col, 1)) {
validMoves.push({
row: row,
col: col,
score: evaluateMove(row, col, 1)
});
}
}
}
if (validMoves.length > 0) {
var chosenMove;
if (difficulty.aiType === 'easy') {
// Easy AI: pick randomly from moves that flip at least 1 piece
var movesWithFlips = [];
for (var i = 0; i < validMoves.length; i++) {
if (validMoves[i].score > 0) {
movesWithFlips.push(validMoves[i]);
}
}
if (movesWithFlips.length === 0) {
movesWithFlips = validMoves;
}
var randomIndex = Math.floor(Math.random() * movesWithFlips.length);
chosenMove = movesWithFlips[randomIndex];
} else if (difficulty.aiType === 'medium') {
// Medium AI: pick from top 50% of moves
validMoves.sort(function (a, b) {
return b.score - a.score;
});
var topHalf = Math.ceil(validMoves.length / 2);
var randomIndex = Math.floor(Math.random() * topHalf);
chosenMove = validMoves[randomIndex];
} else if (difficulty.aiType === 'hard') {
// Hard AI: pick from top 25% of moves
validMoves.sort(function (a, b) {
return b.score - a.score;
});
var topQuarter = Math.max(1, Math.ceil(validMoves.length / 4));
var randomIndex = Math.floor(Math.random() * topQuarter);
chosenMove = validMoves[randomIndex];
} else {
// expert
// Expert AI: always pick the best move (with small randomness for variety)
validMoves.sort(function (a, b) {
return b.score - a.score;
});
var bestScore = validMoves[0].score;
var bestMoves = [];
for (var i = 0; i < validMoves.length; i++) {
if (validMoves[i].score === bestScore) {
bestMoves.push(validMoves[i]);
} else {
break; // Stop when we leave the best moves
}
}
var randomIndex = Math.floor(Math.random() * bestMoves.length);
chosenMove = bestMoves[randomIndex];
}
// Add difficulty-based delay to make AI move visible
LK.setTimeout(function () {
placePiece(chosenMove.row, chosenMove.col);
}, difficulty.aiDelay);
}
}
;
Modern App Store icon, high definition, square with rounded corners, different othello game squares cells of wood, different wood, different colors, HD colors, for a game titled "Chorizora Othello" and without the description "A territorial strategy game where players flip opponent pieces by trapping them between their own pieces on a 10x10 grid.". with text on the middle of the icon "Chorizora Othello"!
Button "Coordinate". orange color In-Game asset. High contrast. No shadows. 3D