/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Cell class: represents a single cell in the minesweeper grid
var Cell = Container.expand(function () {
var self = Container.call(this);
// Cell state
self.isMine = false;
self.isRevealed = false;
self.isFlagged = false;
self.adjacentMines = 0;
self.gridX = 0;
self.gridY = 0;
// Visuals
// Cell background (hidden/revealed)
self.bg = self.attachAsset('cellBg', {
anchorX: 0.5,
anchorY: 0.5
});
// Flag icon (hidden by default)
self.flagIcon = self.attachAsset('cellFlag', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
// Mine icon (hidden by default)
self.mineIcon = self.attachAsset('cellMine', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
// Number text (hidden by default)
self.numberText = new Text2('', {
size: 32,
fill: 0x1A1A1A
});
self.numberText.anchor.set(0.5, 0.5);
self.numberText.alpha = 0;
self.addChild(self.numberText);
// Reveal this cell
self.reveal = function () {
if (self.isRevealed || self.isFlagged) return;
self.isRevealed = true;
// Show mine or number
if (self.isMine) {
self.mineIcon.alpha = 1;
self.bg.tint = 0xffaaaa;
} else {
self.bg.tint = 0xe0e0e0;
if (self.adjacentMines > 0) {
self.numberText.setText(self.adjacentMines + '');
self.numberText.alpha = 1;
}
}
};
// Hide (reset) this cell
self.hide = function () {
self.isRevealed = false;
self.isFlagged = false;
self.bg.tint = 0xcccccc;
self.flagIcon.alpha = 0;
self.mineIcon.alpha = 0;
self.numberText.alpha = 0;
};
// Set flagged state
self.setFlagged = function (flagged) {
if (self.isRevealed) return;
// Only allow flagging if not already flagged and flag limit not reached
if (flagged && !self.isFlagged) {
if (flagCount >= MINE_COUNT) return; // Do not allow more flags than mines
self.isFlagged = true;
self.flagIcon.alpha = 1;
if (typeof game.updateFlagCount === "function") game.updateFlagCount();
} else if (!flagged && self.isFlagged) {
self.isFlagged = false;
self.flagIcon.alpha = 0;
if (typeof game.updateFlagCount === "function") game.updateFlagCount();
}
};
// Event: tap/click (reveal)
self.down = function (x, y, obj) {
if (game.isGameOver || game.isWin) return;
if (flagMode) {
// Only allow flagging if not revealed
if (!self.isRevealed) {
// Only allow flagging if not exceeding flag limit
if (!self.isFlagged && flagCount >= MINE_COUNT) {
// Optionally: flash or shake to indicate no more flags
return;
}
self.setFlagged(!self.isFlagged);
// game.updateFlagCount(); // Already called in setFlagged
}
return;
}
if (self.isFlagged) return;
if (!self.isRevealed) {
game.revealCell(self.gridX, self.gridY);
}
};
// Event: long press (flag)
self.up = function (x, y, obj) {
// No-op, handled in game
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xeeeeee
});
/****
* Game Code
****/
// --- Game constants ---
var COLS = 12;
var ROWS = 8;
var CELL_SIZE = 120; // px, will be scaled to fit
var MINE_COUNT = 18; // Küçük harita için uygun mayın sayısı
// --- Game variables ---
var grid = [];
var cellNodes = [];
var isFirstClick = true;
var isGameOver = false;
var isWin = false;
var flagCount = 0;
var revealedCount = 0;
var flagMode = false; // If true, taps flag/unflag instead of reveal
// --- Asset initialization ---
// --- Layout calculation ---
var boardWidth = COLS * CELL_SIZE;
var boardHeight = ROWS * CELL_SIZE;
var boardOffsetX = Math.floor((2048 - boardWidth) / 2);
var boardOffsetY = Math.floor((2732 - boardHeight) / 2);
// --- GUI elements ---
var flagTxt = new Text2('Bayrak: 0/' + MINE_COUNT, {
size: 60,
fill: 0x333333
});
flagTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(flagTxt);
// Floating flag button (bottom right, not in top left!)
// Use the flag asset for visual consistency
var flagBtn = LK.getAsset('cellFlag', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 - 180,
y: 2732 - 180,
scaleX: 1.2,
scaleY: 1.2
});
flagBtn.interactive = true;
flagBtn.buttonMode = true;
game.addChild(flagBtn);
// Visual feedback for flag mode
function updateFlagBtnVisual() {
flagBtn.alpha = flagMode ? 1 : 0.7;
flagBtn.tint = flagMode ? 0xff3333 : 0xffffff;
}
updateFlagBtnVisual();
// Touch handler for flag button
flagBtn.down = function (x, y, obj) {
flagMode = !flagMode;
updateFlagBtnVisual();
modeTxt.setText(flagMode ? 'Bayrak' : 'Aç');
modeTxt.fill = flagMode ? "#ff3333" : "#666666";
};
// Optional: also allow toggling with the old modeTxt for accessibility
var modeTxt = new Text2('Aç', {
size: 48,
fill: 0x666666
});
modeTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(modeTxt);
modeTxt.y = 80;
modeTxt.x = 2048 / 2;
modeTxt.down = function (x, y, obj) {
flagMode = !flagMode;
updateFlagBtnVisual();
modeTxt.setText(flagMode ? 'Bayrak' : 'Aç');
modeTxt.fill = flagMode ? "#ff3333" : "#666666";
};
// --- Board container ---
var board = new Container();
game.addChild(board);
board.x = boardOffsetX;
board.y = boardOffsetY;
// --- Helper functions ---
// Returns true if (x, y) is inside the grid
function inBounds(x, y) {
return x >= 0 && x < COLS && y >= 0 && y < ROWS;
}
// Place mines randomly, avoiding (safeX, safeY) and its neighbors
function placeMines(safeX, safeY) {
var placed = 0;
while (placed < MINE_COUNT) {
var x = Math.floor(Math.random() * COLS);
var y = Math.floor(Math.random() * ROWS);
// Don't place on safe cell or its neighbors
if (Math.abs(x - safeX) <= 1 && Math.abs(y - safeY) <= 1) continue;
if (!grid[y][x].isMine) {
grid[y][x].isMine = true;
placed++;
}
}
}
// Calculate adjacent mine counts for all cells
function calcAdjacents() {
for (var y = 0; y < ROWS; y++) {
for (var x = 0; x < COLS; x++) {
var count = 0;
for (var dy = -1; dy <= 1; dy++) {
for (var dx = -1; dx <= 1; dx++) {
if (dx === 0 && dy === 0) continue;
var nx = x + dx,
ny = y + dy;
if (inBounds(nx, ny) && grid[ny][nx].isMine) count++;
}
}
grid[y][x].adjacentMines = count;
}
}
}
// Reveal cell at (x, y). If first click, place mines after click.
game.revealCell = function (x, y) {
if (isGameOver || isWin) return;
var cell = grid[y][x];
if (cell.isRevealed || cell.isFlagged) return;
if (isFirstClick) {
placeMines(x, y);
calcAdjacents();
isFirstClick = false;
}
cell.reveal();
revealedCount++;
if (cell.isMine) {
// Game over
isGameOver = true;
revealAllMines();
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
// If no adjacent mines, reveal neighbors recursively
if (cell.adjacentMines === 0) {
for (var dy = -1; dy <= 1; dy++) {
for (var dx = -1; dx <= 1; dx++) {
if (dx === 0 && dy === 0) continue;
var nx = x + dx,
ny = y + dy;
if (inBounds(nx, ny)) {
var neighbor = grid[ny][nx];
if (!neighbor.isRevealed && !neighbor.isMine && !neighbor.isFlagged) {
game.revealCell(nx, ny);
}
}
}
}
}
checkWin();
};
// Reveal all mines (on game over)
function revealAllMines() {
for (var y = 0; y < ROWS; y++) {
for (var x = 0; x < COLS; x++) {
var cell = grid[y][x];
if (cell.isMine) {
cell.mineIcon.alpha = 1;
cell.bg.tint = 0xffaaaa;
}
}
}
}
// Check win condition
function checkWin() {
// Win if all non-mine cells are revealed
var totalSafe = COLS * ROWS - MINE_COUNT;
if (revealedCount === totalSafe) {
isWin = true;
LK.effects.flashScreen(0x44ff44, 1000);
LK.showYouWin();
}
}
// Update flag count display
game.updateFlagCount = function () {
flagCount = 0;
for (var y = 0; y < ROWS; y++) {
for (var x = 0; x < COLS; x++) {
if (grid[y][x].isFlagged) flagCount++;
}
}
flagTxt.setText('Bayrak: ' + flagCount + '/' + MINE_COUNT);
};
// --- Board setup ---
// Create grid and cell nodes
for (var y = 0; y < ROWS; y++) {
grid[y] = [];
cellNodes[y] = [];
for (var x = 0; x < COLS; x++) {
var cell = new Cell();
cell.gridX = x;
cell.gridY = y;
cell.x = x * CELL_SIZE + CELL_SIZE / 2;
cell.y = y * CELL_SIZE + CELL_SIZE / 2;
board.addChild(cell);
grid[y][x] = cell;
cellNodes[y][x] = cell;
}
}
// --- Touch/flag mode toggle ---
// Toggle flag mode on modeTxt tap
modeTxt.down = function (x, y, obj) {
flagMode = !flagMode;
modeTxt.setText(flagMode ? 'Bayrak' : 'Aç');
modeTxt.fill = flagMode ? "#ff3333" : "#666666";
};
// --- Game event handlers ---
// Prevent drag/scroll on board
board.move = function (x, y, obj) {};
// --- Reset function (called by LK on game restart) ---
game.reset = function () {
isFirstClick = true;
isGameOver = false;
isWin = false;
flagCount = 0;
revealedCount = 0;
flagMode = false;
if (typeof updateFlagBtnVisual === "function") updateFlagBtnVisual();
modeTxt.setText('Aç');
modeTxt.fill = "#666666";
flagTxt.setText('Bayrak: 0/' + MINE_COUNT);
for (var y = 0; y < ROWS; y++) {
for (var x = 0; x < COLS; x++) {
var cell = grid[y][x];
cell.isMine = false;
cell.isRevealed = false;
cell.isFlagged = false;
cell.adjacentMines = 0;
cell.hide();
}
}
};
// --- Game update loop (not used, but required) ---
game.update = function () {};
// --- End of file --- /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Cell class: represents a single cell in the minesweeper grid
var Cell = Container.expand(function () {
var self = Container.call(this);
// Cell state
self.isMine = false;
self.isRevealed = false;
self.isFlagged = false;
self.adjacentMines = 0;
self.gridX = 0;
self.gridY = 0;
// Visuals
// Cell background (hidden/revealed)
self.bg = self.attachAsset('cellBg', {
anchorX: 0.5,
anchorY: 0.5
});
// Flag icon (hidden by default)
self.flagIcon = self.attachAsset('cellFlag', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
// Mine icon (hidden by default)
self.mineIcon = self.attachAsset('cellMine', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
// Number text (hidden by default)
self.numberText = new Text2('', {
size: 32,
fill: 0x1A1A1A
});
self.numberText.anchor.set(0.5, 0.5);
self.numberText.alpha = 0;
self.addChild(self.numberText);
// Reveal this cell
self.reveal = function () {
if (self.isRevealed || self.isFlagged) return;
self.isRevealed = true;
// Show mine or number
if (self.isMine) {
self.mineIcon.alpha = 1;
self.bg.tint = 0xffaaaa;
} else {
self.bg.tint = 0xe0e0e0;
if (self.adjacentMines > 0) {
self.numberText.setText(self.adjacentMines + '');
self.numberText.alpha = 1;
}
}
};
// Hide (reset) this cell
self.hide = function () {
self.isRevealed = false;
self.isFlagged = false;
self.bg.tint = 0xcccccc;
self.flagIcon.alpha = 0;
self.mineIcon.alpha = 0;
self.numberText.alpha = 0;
};
// Set flagged state
self.setFlagged = function (flagged) {
if (self.isRevealed) return;
// Only allow flagging if not already flagged and flag limit not reached
if (flagged && !self.isFlagged) {
if (flagCount >= MINE_COUNT) return; // Do not allow more flags than mines
self.isFlagged = true;
self.flagIcon.alpha = 1;
if (typeof game.updateFlagCount === "function") game.updateFlagCount();
} else if (!flagged && self.isFlagged) {
self.isFlagged = false;
self.flagIcon.alpha = 0;
if (typeof game.updateFlagCount === "function") game.updateFlagCount();
}
};
// Event: tap/click (reveal)
self.down = function (x, y, obj) {
if (game.isGameOver || game.isWin) return;
if (flagMode) {
// Only allow flagging if not revealed
if (!self.isRevealed) {
// Only allow flagging if not exceeding flag limit
if (!self.isFlagged && flagCount >= MINE_COUNT) {
// Optionally: flash or shake to indicate no more flags
return;
}
self.setFlagged(!self.isFlagged);
// game.updateFlagCount(); // Already called in setFlagged
}
return;
}
if (self.isFlagged) return;
if (!self.isRevealed) {
game.revealCell(self.gridX, self.gridY);
}
};
// Event: long press (flag)
self.up = function (x, y, obj) {
// No-op, handled in game
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xeeeeee
});
/****
* Game Code
****/
// --- Game constants ---
var COLS = 12;
var ROWS = 8;
var CELL_SIZE = 120; // px, will be scaled to fit
var MINE_COUNT = 18; // Küçük harita için uygun mayın sayısı
// --- Game variables ---
var grid = [];
var cellNodes = [];
var isFirstClick = true;
var isGameOver = false;
var isWin = false;
var flagCount = 0;
var revealedCount = 0;
var flagMode = false; // If true, taps flag/unflag instead of reveal
// --- Asset initialization ---
// --- Layout calculation ---
var boardWidth = COLS * CELL_SIZE;
var boardHeight = ROWS * CELL_SIZE;
var boardOffsetX = Math.floor((2048 - boardWidth) / 2);
var boardOffsetY = Math.floor((2732 - boardHeight) / 2);
// --- GUI elements ---
var flagTxt = new Text2('Bayrak: 0/' + MINE_COUNT, {
size: 60,
fill: 0x333333
});
flagTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(flagTxt);
// Floating flag button (bottom right, not in top left!)
// Use the flag asset for visual consistency
var flagBtn = LK.getAsset('cellFlag', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 - 180,
y: 2732 - 180,
scaleX: 1.2,
scaleY: 1.2
});
flagBtn.interactive = true;
flagBtn.buttonMode = true;
game.addChild(flagBtn);
// Visual feedback for flag mode
function updateFlagBtnVisual() {
flagBtn.alpha = flagMode ? 1 : 0.7;
flagBtn.tint = flagMode ? 0xff3333 : 0xffffff;
}
updateFlagBtnVisual();
// Touch handler for flag button
flagBtn.down = function (x, y, obj) {
flagMode = !flagMode;
updateFlagBtnVisual();
modeTxt.setText(flagMode ? 'Bayrak' : 'Aç');
modeTxt.fill = flagMode ? "#ff3333" : "#666666";
};
// Optional: also allow toggling with the old modeTxt for accessibility
var modeTxt = new Text2('Aç', {
size: 48,
fill: 0x666666
});
modeTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(modeTxt);
modeTxt.y = 80;
modeTxt.x = 2048 / 2;
modeTxt.down = function (x, y, obj) {
flagMode = !flagMode;
updateFlagBtnVisual();
modeTxt.setText(flagMode ? 'Bayrak' : 'Aç');
modeTxt.fill = flagMode ? "#ff3333" : "#666666";
};
// --- Board container ---
var board = new Container();
game.addChild(board);
board.x = boardOffsetX;
board.y = boardOffsetY;
// --- Helper functions ---
// Returns true if (x, y) is inside the grid
function inBounds(x, y) {
return x >= 0 && x < COLS && y >= 0 && y < ROWS;
}
// Place mines randomly, avoiding (safeX, safeY) and its neighbors
function placeMines(safeX, safeY) {
var placed = 0;
while (placed < MINE_COUNT) {
var x = Math.floor(Math.random() * COLS);
var y = Math.floor(Math.random() * ROWS);
// Don't place on safe cell or its neighbors
if (Math.abs(x - safeX) <= 1 && Math.abs(y - safeY) <= 1) continue;
if (!grid[y][x].isMine) {
grid[y][x].isMine = true;
placed++;
}
}
}
// Calculate adjacent mine counts for all cells
function calcAdjacents() {
for (var y = 0; y < ROWS; y++) {
for (var x = 0; x < COLS; x++) {
var count = 0;
for (var dy = -1; dy <= 1; dy++) {
for (var dx = -1; dx <= 1; dx++) {
if (dx === 0 && dy === 0) continue;
var nx = x + dx,
ny = y + dy;
if (inBounds(nx, ny) && grid[ny][nx].isMine) count++;
}
}
grid[y][x].adjacentMines = count;
}
}
}
// Reveal cell at (x, y). If first click, place mines after click.
game.revealCell = function (x, y) {
if (isGameOver || isWin) return;
var cell = grid[y][x];
if (cell.isRevealed || cell.isFlagged) return;
if (isFirstClick) {
placeMines(x, y);
calcAdjacents();
isFirstClick = false;
}
cell.reveal();
revealedCount++;
if (cell.isMine) {
// Game over
isGameOver = true;
revealAllMines();
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
// If no adjacent mines, reveal neighbors recursively
if (cell.adjacentMines === 0) {
for (var dy = -1; dy <= 1; dy++) {
for (var dx = -1; dx <= 1; dx++) {
if (dx === 0 && dy === 0) continue;
var nx = x + dx,
ny = y + dy;
if (inBounds(nx, ny)) {
var neighbor = grid[ny][nx];
if (!neighbor.isRevealed && !neighbor.isMine && !neighbor.isFlagged) {
game.revealCell(nx, ny);
}
}
}
}
}
checkWin();
};
// Reveal all mines (on game over)
function revealAllMines() {
for (var y = 0; y < ROWS; y++) {
for (var x = 0; x < COLS; x++) {
var cell = grid[y][x];
if (cell.isMine) {
cell.mineIcon.alpha = 1;
cell.bg.tint = 0xffaaaa;
}
}
}
}
// Check win condition
function checkWin() {
// Win if all non-mine cells are revealed
var totalSafe = COLS * ROWS - MINE_COUNT;
if (revealedCount === totalSafe) {
isWin = true;
LK.effects.flashScreen(0x44ff44, 1000);
LK.showYouWin();
}
}
// Update flag count display
game.updateFlagCount = function () {
flagCount = 0;
for (var y = 0; y < ROWS; y++) {
for (var x = 0; x < COLS; x++) {
if (grid[y][x].isFlagged) flagCount++;
}
}
flagTxt.setText('Bayrak: ' + flagCount + '/' + MINE_COUNT);
};
// --- Board setup ---
// Create grid and cell nodes
for (var y = 0; y < ROWS; y++) {
grid[y] = [];
cellNodes[y] = [];
for (var x = 0; x < COLS; x++) {
var cell = new Cell();
cell.gridX = x;
cell.gridY = y;
cell.x = x * CELL_SIZE + CELL_SIZE / 2;
cell.y = y * CELL_SIZE + CELL_SIZE / 2;
board.addChild(cell);
grid[y][x] = cell;
cellNodes[y][x] = cell;
}
}
// --- Touch/flag mode toggle ---
// Toggle flag mode on modeTxt tap
modeTxt.down = function (x, y, obj) {
flagMode = !flagMode;
modeTxt.setText(flagMode ? 'Bayrak' : 'Aç');
modeTxt.fill = flagMode ? "#ff3333" : "#666666";
};
// --- Game event handlers ---
// Prevent drag/scroll on board
board.move = function (x, y, obj) {};
// --- Reset function (called by LK on game restart) ---
game.reset = function () {
isFirstClick = true;
isGameOver = false;
isWin = false;
flagCount = 0;
revealedCount = 0;
flagMode = false;
if (typeof updateFlagBtnVisual === "function") updateFlagBtnVisual();
modeTxt.setText('Aç');
modeTxt.fill = "#666666";
flagTxt.setText('Bayrak: 0/' + MINE_COUNT);
for (var y = 0; y < ROWS; y++) {
for (var x = 0; x < COLS; x++) {
var cell = grid[y][x];
cell.isMine = false;
cell.isRevealed = false;
cell.isFlagged = false;
cell.adjacentMines = 0;
cell.hide();
}
}
};
// --- Game update loop (not used, but required) ---
game.update = function () {};
// --- End of file ---