/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// NumberBubble: Represents a draggable number on the board
var NumberBubble = Container.expand(function () {
var self = Container.call(this);
// Attach a circular shape as the bubble
var bubble = self.attachAsset('bubble', {
anchorX: 0.5,
anchorY: 0.5
});
// Attach the number as text
self.text = new Text2('', {
size: 120,
fill: 0xFFFFFF
});
self.text.anchor.set(0.5, 0.5);
self.addChild(self.text);
// Value of the bubble
self.value = 0;
// Is this bubble currently selected?
self.selected = false;
// Set value and update text
self.setValue = function (v) {
self.value = v;
self.text.setText(v + '');
};
// Visual feedback for selection
self.setSelected = function (isSelected) {
self.selected = isSelected;
if (isSelected) {
tween(self, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 150,
easing: tween.easeOut
});
} else {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 150,
easing: tween.easeOut
});
}
};
// Destroy bubble
self.destroyBubble = function () {
// Animate out
tween(self, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 200,
onFinish: function onFinish() {
self.destroy();
}
});
};
return self;
});
// OperationButton: Represents an operation (+, -, ×, ÷) button
var OperationButton = Container.expand(function () {
var self = Container.call(this);
// Attach a box shape as the button
var btn = self.attachAsset('opbtn', {
anchorX: 0.5,
anchorY: 0.5
});
// Attach the operation symbol as text
self.text = new Text2('', {
size: 100,
fill: 0x222222
});
self.text.anchor.set(0.5, 0.5);
self.addChild(self.text);
// Operation type: '+', '-', '×', '÷'
self.op = '+';
// Set operation and update text
self.setOp = function (op) {
self.op = op;
self.text.setText(op);
};
// Visual feedback for selection
self.setSelected = function (isSelected) {
if (isSelected) {
tween(self, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 120,
easing: tween.easeOut
});
} else {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 120,
easing: tween.easeOut
});
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a2e
});
/****
* Game Code
****/
// --- Game parameters ---
var NUM_BUBBLES = 5;
var MIN_NUM = 1;
var MAX_NUM = 20;
var OPERATIONS = ['+', '-', '×', '÷'];
var MOVE_LIMIT = 8; // Number of allowed moves
var BUBBLE_RADIUS = 160;
var BUBBLE_SPACING = 340;
var BOARD_MARGIN = 200;
// --- State ---
var bubbles = [];
var opButtons = [];
var selectedBubbles = [];
var selectedOp = null;
var targetNumber = 0;
var moveCount = 0;
var moveLimit = MOVE_LIMIT;
var gameActive = true;
// --- UI Elements ---
var targetText, movesText, infoText;
// --- Asset Initialization ---
// --- Helper Functions ---
// Generate a random integer between min and max (inclusive)
function randInt(min, max) {
return min + Math.floor(Math.random() * (max - min + 1));
}
// Shuffle an array in-place
function shuffle(arr) {
for (var i = arr.length - 1; i > 0; i--) {
var j = randInt(0, i);
var t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
}
// Generate a solvable puzzle: returns {numbers:[], target: number}
function generatePuzzle() {
// Start with a random number as the "target"
var numbers = [];
var steps = NUM_BUBBLES - 1;
var current = randInt(10, 50);
var history = [current];
for (var i = 0; i < steps; i++) {
// Pick a random operation
var op = OPERATIONS[randInt(0, OPERATIONS.length - 1)];
// Pick a random operand
var operand;
if (op === '+') {
operand = randInt(MIN_NUM, MAX_NUM);
current = current - operand;
} else if (op === '-') {
operand = randInt(MIN_NUM, Math.min(current, MAX_NUM));
current = current + operand;
} else if (op === '×') {
operand = randInt(2, 5);
if (current % operand !== 0) {
current = current * operand;
}
current = current / operand;
} else if (op === '÷') {
operand = randInt(2, 5);
current = current * operand;
}
numbers.push(operand);
history.push(current);
}
numbers.push(Math.round(current));
shuffle(numbers);
return {
numbers: numbers.map(function (n) {
return Math.round(n);
}),
target: Math.round(history[0])
};
}
// Reset game state
function resetGame() {
// Remove old bubbles
for (var i = 0; i < bubbles.length; i++) {
bubbles[i].destroy();
}
bubbles = [];
selectedBubbles = [];
selectedOp = null;
moveCount = 0;
gameActive = true;
// Generate puzzle
var puzzle = generatePuzzle();
var nums = puzzle.numbers;
targetNumber = puzzle.target;
moveLimit = MOVE_LIMIT;
// Place bubbles in a circle
var centerX = 2048 / 2;
var centerY = 1200;
var angleStep = Math.PI * 2 / nums.length;
for (var i = 0; i < nums.length; i++) {
var nb = new NumberBubble();
nb.setValue(nums[i]);
nb.x = centerX + Math.cos(i * angleStep - Math.PI / 2) * BUBBLE_SPACING;
nb.y = centerY + Math.sin(i * angleStep - Math.PI / 2) * BUBBLE_SPACING;
nb.scaleX = nb.scaleY = 1;
nb.alpha = 1;
nb.index = i;
nb.setSelected(false);
game.addChild(nb);
bubbles.push(nb);
}
// Update UI
targetText.setText('Target: ' + targetNumber);
movesText.setText('Moves: 0/' + moveLimit);
infoText.setText('Select two numbers, pick an operation!');
}
// --- UI Setup ---
// Target number display
targetText = new Text2('Target: 0', {
size: 120,
fill: 0xFFBE0B
});
targetText.anchor.set(0.5, 0);
// Move the target text further down by setting its y position
targetText.y = 180;
LK.gui.top.addChild(targetText);
// Moves left display
movesText = new Text2('Moves: 0/' + MOVE_LIMIT, {
size: 90,
fill: 0xFFFFFF
});
movesText.anchor.set(0.5, 0);
LK.gui.top.addChild(movesText);
// Info text
infoText = new Text2('', {
size: 80,
fill: 0xFFFFFF
});
infoText.anchor.set(0.5, 0);
LK.gui.bottom.addChild(infoText);
// --- Operation Buttons ---
var opAreaY = 2100;
var opAreaX = 2048 / 2 - 2 * 220;
for (var i = 0; i < OPERATIONS.length; i++) {
var opBtn = new OperationButton();
opBtn.setOp(OPERATIONS[i]);
opBtn.x = opAreaX + i * 220;
opBtn.y = opAreaY;
opBtn.scaleX = opBtn.scaleY = 1;
opBtn.setSelected(false);
game.addChild(opBtn);
opButtons.push(opBtn);
}
// --- Input Handling ---
// Helper: get bubble at (x, y)
function getBubbleAt(x, y) {
for (var i = 0; i < bubbles.length; i++) {
var b = bubbles[i];
var dx = x - b.x;
var dy = y - b.y;
var r = BUBBLE_RADIUS;
if (dx * dx + dy * dy <= r * r) {
return b;
}
}
return null;
}
// Helper: get op button at (x, y)
function getOpButtonAt(x, y) {
for (var i = 0; i < opButtons.length; i++) {
var btn = opButtons[i];
var bx = btn.x,
by = btn.y;
var w = 180,
h = 180;
if (x >= bx - w / 2 && x <= bx + w / 2 && y >= by - h / 2 && y <= by + h / 2) {
return btn;
}
}
return null;
}
// Main input handler
game.down = function (x, y, obj) {
if (!gameActive) return;
// Try to select a bubble
var b = getBubbleAt(x, y);
if (b && selectedBubbles.indexOf(b) === -1) {
if (selectedBubbles.length < 2) {
selectedBubbles.push(b);
b.setSelected(true);
}
// Deselect if already selected
else if (selectedBubbles.length === 2) {
for (var i = 0; i < selectedBubbles.length; i++) {
selectedBubbles[i].setSelected(false);
}
selectedBubbles = [b];
b.setSelected(true);
}
infoText.setText(selectedBubbles.length === 2 ? 'Pick an operation!' : 'Select one more number!');
return;
}
// Try to select an operation
var opBtn = getOpButtonAt(x, y);
if (opBtn && selectedBubbles.length === 2) {
// Deselect previous op
for (var i = 0; i < opButtons.length; i++) {
opButtons[i].setSelected(false);
}
opBtn.setSelected(true);
selectedOp = opBtn.op;
// Apply operation
applyOperation();
return;
}
};
// --- Operation Logic ---
function applyOperation() {
if (!gameActive) return;
if (selectedBubbles.length !== 2 || !selectedOp) return;
var a = selectedBubbles[0];
var b = selectedBubbles[1];
var v1 = a.value,
v2 = b.value;
var result = 0;
var valid = true;
if (selectedOp === '+') {
result = v1 + v2;
} else if (selectedOp === '-') {
result = v1 - v2;
if (result < 0) valid = false;
} else if (selectedOp === '×') {
result = v1 * v2;
} else if (selectedOp === '÷') {
if (v2 === 0 || v1 % v2 !== 0) valid = false;else result = v1 / v2;
}
if (!valid) {
infoText.setText('Invalid operation!');
// Deselect
for (var i = 0; i < selectedBubbles.length; i++) {
selectedBubbles[i].setSelected(false);
}
selectedBubbles = [];
for (var i = 0; i < opButtons.length; i++) {
opButtons[i].setSelected(false);
}
selectedOp = null;
return;
}
// Remove used bubbles
a.destroyBubble();
b.destroyBubble();
var idxA = bubbles.indexOf(a);
var idxB = bubbles.indexOf(b);
if (idxA > -1) bubbles.splice(idxA, 1);
if (idxB > -1 && idxB !== idxA) bubbles.splice(bubbles.indexOf(b), 1);
// Add new bubble at average position
var newBubble = new NumberBubble();
newBubble.setValue(result);
newBubble.x = (a.x + b.x) / 2;
newBubble.y = (a.y + b.y) / 2;
newBubble.scaleX = newBubble.scaleY = 0.5;
newBubble.alpha = 0;
newBubble.setSelected(false);
game.addChild(newBubble);
bubbles.push(newBubble);
tween(newBubble, {
scaleX: 1,
scaleY: 1,
alpha: 1
}, {
duration: 200,
easing: tween.easeOut
});
// Deselect all
for (var i = 0; i < opButtons.length; i++) {
opButtons[i].setSelected(false);
}
selectedBubbles = [];
selectedOp = null;
// Update move count
moveCount++;
movesText.setText('Moves: ' + moveCount + '/' + moveLimit);
// Check win/lose
checkGameState();
}
// --- Game State Check ---
function checkGameState() {
// Win: Only one bubble left and its value == target
if (bubbles.length === 1 && bubbles[0].value === targetNumber) {
infoText.setText('Congratulations! You reached the target!');
LK.setScore(1);
LK.showYouWin();
gameActive = false;
return;
}
// Lose: Out of moves or no more valid moves
if (moveCount >= moveLimit) {
infoText.setText('No moves left!');
LK.setScore(0);
LK.showGameOver();
gameActive = false;
return;
}
// If only one bubble left but not target
if (bubbles.length === 1 && bubbles[0].value !== targetNumber) {
infoText.setText('You did not reach the target!');
LK.setScore(0);
LK.showGameOver();
gameActive = false;
return;
}
// Otherwise, keep playing
infoText.setText('Select two numbers, pick an operation!');
}
// --- Game Update Loop ---
game.update = function () {
// No per-frame logic needed for now
};
// --- Start Game ---
resetGame(); ===================================================================
--- original.js
+++ change.js
@@ -229,24 +229,24 @@
game.addChild(nb);
bubbles.push(nb);
}
// Update UI
- targetText.setText('Hedef: ' + targetNumber);
- movesText.setText('Hamle: 0/' + moveLimit);
- infoText.setText('İki sayı seç, işlem seç ve uygula!');
+ targetText.setText('Target: ' + targetNumber);
+ movesText.setText('Moves: 0/' + moveLimit);
+ infoText.setText('Select two numbers, pick an operation!');
}
// --- UI Setup ---
// Target number display
-targetText = new Text2('Hedef: 0', {
+targetText = new Text2('Target: 0', {
size: 120,
fill: 0xFFBE0B
});
targetText.anchor.set(0.5, 0);
// Move the target text further down by setting its y position
targetText.y = 180;
LK.gui.top.addChild(targetText);
// Moves left display
-movesText = new Text2('Hamle: 0/' + MOVE_LIMIT, {
+movesText = new Text2('Moves: 0/' + MOVE_LIMIT, {
size: 90,
fill: 0xFFFFFF
});
movesText.anchor.set(0.5, 0);
@@ -316,9 +316,9 @@
}
selectedBubbles = [b];
b.setSelected(true);
}
- infoText.setText(selectedBubbles.length === 2 ? 'İşlem seç!' : 'Bir sayı daha seç!');
+ infoText.setText(selectedBubbles.length === 2 ? 'Pick an operation!' : 'Select one more number!');
return;
}
// Try to select an operation
var opBtn = getOpButtonAt(x, y);
@@ -354,9 +354,9 @@
} else if (selectedOp === '÷') {
if (v2 === 0 || v1 % v2 !== 0) valid = false;else result = v1 / v2;
}
if (!valid) {
- infoText.setText('Geçersiz işlem!');
+ infoText.setText('Invalid operation!');
// Deselect
for (var i = 0; i < selectedBubbles.length; i++) {
selectedBubbles[i].setSelected(false);
}
@@ -399,40 +399,40 @@
selectedBubbles = [];
selectedOp = null;
// Update move count
moveCount++;
- movesText.setText('Hamle: ' + moveCount + '/' + moveLimit);
+ movesText.setText('Moves: ' + moveCount + '/' + moveLimit);
// Check win/lose
checkGameState();
}
// --- Game State Check ---
function checkGameState() {
// Win: Only one bubble left and its value == target
if (bubbles.length === 1 && bubbles[0].value === targetNumber) {
- infoText.setText('Tebrikler! Hedefe ulaştın!');
+ infoText.setText('Congratulations! You reached the target!');
LK.setScore(1);
LK.showYouWin();
gameActive = false;
return;
}
// Lose: Out of moves or no more valid moves
if (moveCount >= moveLimit) {
- infoText.setText('Hamle hakkın bitti!');
+ infoText.setText('No moves left!');
LK.setScore(0);
LK.showGameOver();
gameActive = false;
return;
}
// If only one bubble left but not target
if (bubbles.length === 1 && bubbles[0].value !== targetNumber) {
- infoText.setText('Hedefe ulaşamadın!');
+ infoText.setText('You did not reach the target!');
LK.setScore(0);
LK.showGameOver();
gameActive = false;
return;
}
// Otherwise, keep playing
- infoText.setText('İki sayı seç, işlem seç ve uygula!');
+ infoText.setText('Select two numbers, pick an operation!');
}
// --- Game Update Loop ---
game.update = function () {
// No per-frame logic needed for now