Code edit (1 edits merged)
Please save this source code
User prompt
add random tint to confettis
Code edit (1 edits merged)
Please save this source code
User prompt
create a new confetti class. use line asset. call it in playFinalAnimation
Code edit (6 edits merged)
Please save this source code
User prompt
play bgMusic in loop
Code edit (10 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Timeout.tick error: Error: Invalid color format. Expected 0xRRGGBB format, received: undefined' in or related to this line: 'tween(tileGraphics, {' Line Number: 358 โช๐ก Consider importing and using the following plugins: @upit/tween.v1, @upit/storage.v1, @upit/tween.v1
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Script error.' in or related to this line: 'tween(dragNode, {' Line Number: 2174 โช๐ก Consider importing and using the following plugins: @upit/tween.v1, @upit/storage.v1, @upit/tween.v1
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Script error.' in or related to this line: 'tween(dragNode, {' Line Number: 2174 โช๐ก Consider importing and using the following plugins: @upit/tween.v1, @upit/storage.v1, @upit/tween.v1
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Script error.' in or related to this line: 'tween(dragNode, {' Line Number: 2173 โช๐ก Consider importing and using the following plugins: @upit/tween.v1, @upit/storage.v1, @upit/tween.v1
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Script error.' in or related to this line: 'tween(dragNode, {' Line Number: 2173 โช๐ก Consider importing and using the following plugins: @upit/tween.v1, @upit/storage.v1, @upit/tween.v1
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Script error.' in or related to this line: 'tween(dragNode, {' Line Number: 2170 โช๐ก Consider importing and using the following plugins: @upit/tween.v1, @upit/storage.v1, @upit/tween.v1
User prompt
Please fix the bug: 'Script error.' in or related to this line: 'tween(dragNode, {' Line Number: 2170 โช๐ก Consider importing and using the following plugins: @upit/tween.v1, @upit/storage.v1, @upit/tween.v1
User prompt
Please fix the bug: 'Script error.' in or related to this line: 'tween(dragNode, {' Line Number: 2170 โช๐ก Consider importing and using the following plugins: @upit/tween.v1, @upit/storage.v1, @upit/tween.v1
User prompt
Please fix the bug: 'Script error.' in or related to this line: 'tween(dragNode, {' Line Number: 2170 โช๐ก Consider importing and using the following plugins: @upit/tween.v1, @upit/storage.v1, @upit/tween.v1
Code edit (10 edits merged)
Please save this source code
/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/**** 
* Classes
****/ 
// BackgroundImage class to represent the background image
var BackgroundImage = Container.expand(function () {
	var self = Container.call(this);
	// Asset Attachments
	var backgroundGraphics = self.attachAsset('gradientBackground', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: centerX,
		y: centerY
		//tint: 0x00FF00
	});
	var nextBackgroundH = self.attachAsset('gradientBackground', {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: -1,
		scaleY: 1,
		x: centerX + 2048,
		y: centerY
	});
	var nextBackgroundV = self.attachAsset('gradientBackground', {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 1,
		scaleY: -1,
		x: centerX,
		y: centerY + 2732
	});
	var nextBackgroundC = self.attachAsset('gradientBackground', {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: -1,
		scaleY: -1,
		x: centerX + 2048,
		y: centerY + 2732
		//tint: 0xFF0000
	});
	var backgroundWall = self.attachAsset('startButton', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: centerX,
		y: centerY,
		visible: false
	});
	self.animateTransition = function (dirX, dirY) {
		if (puzzleManager.currentLevel == 1 || !dirX || !dirY) {
			// No anim for level 1 or reset
			return;
		}
		self.prepareSideBackgrounds(dirX, dirY);
		var deltaX = -dirX * 2048;
		var deltaY = -dirY * 2732;
		tween(backgroundGraphics, {
			x: backgroundGraphics.x + deltaX,
			y: backgroundGraphics.y + deltaY
		}, {
			duration: 1000,
			easing: tween.easeInOut
		});
		tween(nextBackgroundH, {
			x: nextBackgroundH.x + deltaX,
			y: nextBackgroundH.y + deltaY
		}, {
			duration: 1000,
			easing: tween.easeInOut
		});
		tween(nextBackgroundV, {
			x: nextBackgroundV.x + deltaX,
			y: nextBackgroundV.y + deltaY
		}, {
			duration: 1000,
			easing: tween.easeInOut
		});
		tween(nextBackgroundC, {
			x: nextBackgroundC.x + deltaX,
			y: nextBackgroundC.y + deltaY
		}, {
			duration: 1000,
			easing: tween.easeInOut,
			onFinish: function onFinish() {
				// Update main background like the transitioned one
				var referenceNextScaleX = Math.abs(dirX) == 0 ? nextBackgroundV.scale.x : nextBackgroundH.scale.x;
				var referenceNextScaleY = Math.abs(dirY) == 0 ? nextBackgroundH.scale.y : nextBackgroundV.scale.y;
				backgroundGraphics.scale.x = referenceNextScaleX;
				backgroundGraphics.scale.y = referenceNextScaleY;
				// Switch backgrounds
				backgroundGraphics.x = centerX;
				backgroundGraphics.y = centerY;
				nextBackgroundC.x += 2048;
				nextBackgroundC.y += 2732;
				// Restore initial positions of graphics
				nextBackgroundH.scale.x = -1 * backgroundGraphics.scale.x;
				nextBackgroundH.scale.y = 1 * backgroundGraphics.scale.y;
				nextBackgroundV.scale.x = 1 * backgroundGraphics.scale.x;
				nextBackgroundV.scale.y = -1 * backgroundGraphics.scale.y;
				nextBackgroundC.scale.x = -1 * backgroundGraphics.scale.x;
				nextBackgroundC.scale.y = -1 * backgroundGraphics.scale.y;
			}
		});
	};
	self.prepareSideBackgrounds = function (dirX, dirY) {
		// Position the next backgrounds depending on the currrent transition direction
		nextBackgroundH.x = centerX + dirX * 2048;
		nextBackgroundH.y = centerY;
		nextBackgroundV.x = centerX;
		nextBackgroundV.y = centerY + dirY * 2732;
		nextBackgroundC.x = centerX + dirX * 2048;
		nextBackgroundC.y = centerY + dirY * 2732;
	};
	self.showWall = function () {
		backgroundWall.visible = true;
		backgroundWall.alpha = 0;
		tween(backgroundWall, {
			alpha: 1
		}, {
			duration: 500,
			easing: tween.easeOut
		});
	};
	self.hideWall = function () {
		backgroundWall.alpha = 1;
		tween(backgroundWall, {
			alpha: 0
		}, {
			duration: 500,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				backgroundWall.visible = false;
			}
		});
	};
	return self;
});
// Confetti class to represent confetti animation
var Confetti = Container.expand(function () {
	var self = Container.call(this);
	// Create and attach line asset
	var lineGraphics = self.attachAsset('line', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Set initial properties
	self.speed = Math.random() * 5 + 4; // Random speed between 2 and 7
	self.rotationSpeed = Math.random() * 0.1 - 0.05; // Random rotation speed
	lineGraphics.tint = Math.random() * 0xFFFFFF; // Random tint color
	self.update = function () {
		// Update position and rotation
		self.y += self.speed;
		self.rotation += self.rotationSpeed;
		// Reset position if out of bounds
		if (self.y > 2732) {
			self.y = -20;
			self.x = Math.random() * 2048;
		}
	};
	return self;
});
// GameHints class to represent hint popups
var GameHints = Container.expand(function () {
	var self = Container.call(this);
	self.x = centerX;
	self.y = centerY;
	self.visible = false;
	self.hasShowHint = 0;
	self.visible = false;
	// Attach hintPopup asset
	self.popup = self.attachAsset('hintPopup', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 0,
		y: 0
	});
	self.chevron = self.attachAsset('blackChevron', {
		anchorX: 0.5,
		anchorY: 0.5,
		rotation: Math.PI * 0.5,
		x: -530,
		y: 0
	});
	// Add hintText property
	self.hintText = new Text2('', {
		size: 80,
		fill: 0xFFFFFF,
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.hintText.x = self.popup.x - 350;
	self.hintText.y = self.popup.y - 45;
	self.addChild(self.hintText);
	self.showHint = function () {
		if (self.hasShowHint == 0) {
			// Show hint 1
			self.showHint1();
			return;
		}
		if (self.hasShowHint == 1) {
			// Show hint 1
			self.showHint2();
			return;
		}
		self.visible = false;
		log("All hints shown");
	};
	self.showHint1 = function () {
		self.visible = true;
		self.alpha = 0;
		self.hintText.setText("Drag this operation");
		self.chevron.x = -530;
		self.chevron.y = 0;
		self.chevron.rotation = Math.PI * 0.5, self.x = centerX;
		self.y = 2300;
		tween(self, {
			alpha: 1
		}, {
			duration: 500,
			easing: tween.easeIn,
			onFinish: function onFinish() {
				self.hasShowHint = 1;
			}
		});
	};
	self.showHint2 = function () {
		//self.alpha = 0;
		self.hintText.setText("  Drop it on a tile");
		self.chevron.rotation = 0;
		self.chevron.x = 0;
		self.chevron.y = 250;
		self.x = centerX;
		self.y = self.y == 2300 ? 2300 : -500;
		tween(self, {
			y: 600
		}, {
			duration: 500,
			easing: tween.easeIn,
			onFinish: function onFinish() {
				self.hasShowHint = 2;
			}
		});
	};
	self.hideHint = function () {
		self.alpha = 1;
		tween(self, {
			alpha: 0
		}, {
			duration: 500,
			easing: tween.easeIn,
			onFinish: function onFinish() {}
		});
	};
	self.removeHint = function () {
		self.visible = false;
	};
	return self;
});
/***********************************************************************************************/ 
/******************************************* ASSETS CLASSES ************************************/
/***********************************************************************************************/ 
// HexTile class to represent each tile on the board
var HexTile = Container.expand(function (value, col, row, levelData) {
	var self = Container.call(this);
	// Constants
	var interTileOffsetX = -2;
	var interTileOffsetY = -4; // relative to interTileOffsetX
	self.tileSizeX = LK.getAsset('hexTile', {}).width + interTileOffsetX;
	self.tileSizeY = self.tileSizeX * 0.75 - interTileOffsetY;
	// Properties
	self.value = value;
	self.originalValue = value;
	self.visible = false;
	self.col = col;
	self.row = row;
	self.neighbors = [];
	var tileX = col * self.tileSizeX;
	var tileY = row * self.tileSizeY;
	self.baseX = tileX;
	self.baseY = tileY;
	log("Tile Init row, col: ", row, col, " => ", tileX, tileY);
	self.x = tileX;
	self.y = tileY;
	// Asset Attachments
	var tileGraphicsShadow = self.attachAsset('hexTile', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 7,
		y: 5,
		tint: 0x000000,
		alpha: 0.70
	});
	var tileGraphics = self.attachAsset('hexTile', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 0,
		y: 0,
		tint: tileColors[self.value],
		alpha: 0.9
	});
	// Value text shadow
	var valueTextShadow = new Text2(self.value.toString(), {
		size: self.tileSizeX * 0.5,
		fill: 0x000000,
		//fill: tileColors[self.value],
		weight: 1000
	});
	valueTextShadow.anchor.set(0.5, 0.5);
	valueTextShadow.alpha = 0.1;
	valueTextShadow.x = tileGraphics.x + 12;
	valueTextShadow.y = tileGraphics.y - self.tileSizeY * 0.01 + 12;
	self.valueTextShadow = self.addChild(valueTextShadow);
	// Value Text
	var valueText = new Text2(self.value.toString(), {
		size: self.tileSizeX * 0.5,
		fill: 0xEAEEE8,
		dropShadow: false
	});
	valueText.anchor.set(0.5, 0.5);
	valueText.x = tileGraphics.x;
	valueText.y = tileGraphics.y - self.tileSizeY * 0.01;
	self.valueText = self.addChild(valueText);
	// Functions
	self.setValue = function (newValue, depth) {
		log("setValue to ", newValue, depth);
		self.value = newValue;
		LK.setTimeout(function () {
			// Enclose operation in a timeout
			if (self.value === 0) {
				self.valueTextShadow.setText("");
				self.valueText.setText("");
				LK.getSound('tileRemove').play();
				tween(tileGraphics, {
					scaleX: 0,
					scaleY: 0,
					rotation: Math.PI / 2
				}, {
					duration: 1000,
					easing: tween.easeOut
				});
				tween(tileGraphicsShadow, {
					scaleX: 0,
					scaleY: 0,
					rotation: Math.PI / 2
				}, {
					duration: 1000,
					easing: tween.easeOut
				});
			} else {
				LK.getSound('tileChangeValue').play();
				self.valueText.setText(self.value.toString());
				self.valueTextShadow.setText(self.value.toString());
			}
			// Animate color change
			tween(tileGraphics, {
				tint: tileColors[self.value]
			}, {
				duration: 600,
				easing: tween.easeOut
			});
		}, depth * 175); // Delay proportional to normalized distance
	};
	self.setBasePosition = function (x, y) {
		self.x = x;
		self.y = y;
		self.baseX = x;
		self.baseY = y;
	};
	self.shake = function () {
		log("shaking...");
		tween(self, {
			rotation: 0.3
		}, {
			duration: 150,
			easing: tween.bounceIn,
			onFinish: function onFinish() {
				tween(self, {
					rotation: -0.3
				}, {
					duration: 150,
					easing: tween.bounceIn,
					onFinish: function onFinish() {
						tween(self, {
							rotation: 0
						}, {
							duration: 150,
							easing: tween.bounceIn
						});
					}
				});
			}
		});
	};
	return self;
});
// LevelNumberText class to represent the level number text
var LevelNumberText = Container.expand(function (initialLevel) {
	var self = Container.call(this);
	self.displayedLevel = initialLevel;
	// Initialize level number text
	var levelText = new Text2(initialLevel.toString(), {
		size: 600,
		fill: 0x787878,
		weight: 1000,
		dropShadow: true,
		dropShadowAngle: Math.PI,
		dropShadowDistance: 10
	});
	levelText.anchor.set(0.5, 0.5);
	levelText.alpha = 0.2;
	levelText.blendMode = 2;
	levelText.x = centerX;
	levelText.y = centerY;
	levelText.visible = false;
	self.addChild(levelText);
	// Initialize next level number text 
	var levelText2 = new Text2((initialLevel + 1).toString(), {
		size: 600,
		fill: 0x787878,
		weight: 1000,
		dropShadow: true,
		dropShadowAngle: Math.PI,
		dropShadowDistance: 10
	});
	levelText2.anchor.set(0.5, 0.5);
	levelText2.alpha = 0.2;
	levelText2.blendMode = 2;
	levelText2.x = centerX + 2048;
	levelText2.y = centerY + 2732;
	levelText2.visible = false;
	self.addChild(levelText2);
	// Method to update the level number
	self.updateLevel = function (newLevel, dirX, dirY) {
		if (newLevel != 1 && dirX && dirY) {
			if (newLevel == self.displayedLevel) {
				// When reseting current level show current level in text2
				levelText2.setText(self.displayedLevel.toString());
			}
			if (newLevel == 0) {
				// When reseting current level show current level in text2
				levelText2.setText("THE\nEND");
			}
			self.prepareTextTransition(dirX, dirY);
			var deltaX = -dirX * 2048;
			var deltaY = -dirY * 2732;
			tween(levelText, {
				x: levelText.x + deltaX,
				y: levelText.y + deltaY
			}, {
				duration: 1000,
				easing: tween.easeInOut
			});
			tween(levelText2, {
				x: levelText2.x + deltaX,
				y: levelText2.y + deltaY
			}, {
				duration: 1000,
				easing: tween.easeInOut,
				onFinish: function onFinish() {
					self.displayedLevel = newLevel;
					if (newLevel > 0) {
						levelText.setText(newLevel.toString());
						levelText2.setText((newLevel + 1).toString());
					} else {
						levelText.setText("THE\nEND");
						isOnLastScreen = true;
						if (!isPreviouslyWon) {
							playFinalAnimation();
						}
					}
					// Restore initial positions
					levelText.x = centerX;
					levelText.y = centerY;
					levelText2.x = centerX + 2048;
					levelText2.y = centerY + 2732;
				}
			});
		}
	};
	self.setText = function (text, text2) {
		levelText.setText(text);
		levelText2.setText(text2 || text);
	};
	// Method to show the level number
	self.show = function () {
		levelText.visible = true;
		levelText2.visible = true;
	};
	// Method to hide the level number
	self.hide = function () {
		levelText.visible = false;
		levelText2.visible = false;
	};
	self.prepareTextTransition = function (dirX, dirY) {
		// Position the next text depending on the currrent transition direction
		levelText2.x = centerX + dirX * 2048;
		levelText2.y = centerY + dirY * 2732;
	};
	return self;
});
// MenuBoard class to represent a grid of menuCell assets
var MenuBoard = Container.expand(function () {
	var self = Container.call(this);
	self.menuGrid = [];
	self.menuCells = [];
	self.isLevelSelected = false;
	// Define grid dimensions
	var rows = 7;
	var cols = 6;
	var cellSize = LK.getAsset('menuCell', {}).width;
	// Create grid of menuCell assets
	for (var row = 0; row < rows; row++) {
		self.menuCells[row] = [];
		for (var col = 0; col < cols; col++) {
			var menuCell = self.attachAsset('menuCell', {
				anchorX: 0.5,
				anchorY: 0.5,
				x: cellSize / 2 + col * cellSize,
				y: cellSize / 2 + row * cellSize,
				scaleX: col % 2 ? 1 : -1,
				scaleY: row % 2 ? 1 : -1
			});
			menuCell.baseX = menuCell.x;
			menuCell.baseY = menuCell.y;
			self.menuCells[row][col] = menuCell;
			self.addChild(menuCell);
		}
	}
	// Create grid of menuCell assets
	for (var row = 0; row < rows; row++) {
		self.menuGrid[row] = [];
		for (var col = 0; col < cols; col++) {
			if (row >= 1 && col < 6) {
				var lvl = col + (cols - 1) * (row - 1) + 1;
				var isDone = lvl < puzzleManager.maxReachedLevelNumber;
				var isReached = lvl == puzzleManager.maxReachedLevelNumber;
				var notReached = lvl > puzzleManager.maxReachedLevelNumber;
				var lvlColor = isDone ? 0x6ad100 : 0xF93827;
				lvlColor = notReached ? 0x787878 : lvlColor;
				var levelText = new Text2(lvl < 10 ? "0" + lvl : lvl, {
					size: 160,
					fill: 0xFFFFFF,
					//lvlColor,
					weight: 1000,
					dropShadow: true,
					dropShadowAngle: Math.PI,
					dropShadowDistance: 10
				});
				levelText.tint = lvlColor;
				levelText.lvl = lvl;
				levelText.alpha = lvl <= puzzleManager.maxReachedLevelNumber ? 1 : 0.6;
				levelText.blendMode = 2;
				levelText.x = col * cellSize * 1.0 + cellSize / 2 - 90;
				levelText.y = row * cellSize * 1.0 + cellSize / 4 + 10;
				levelText.baseX = levelText.x;
				levelText.baseY = levelText.y;
				levelText.down = function (levelText, level) {
					return function () {
						levelText.interactive = false;
						log("levelText currentState:", currentState, " isMenuReady=", isMenuReady); //{3F.2}
						if (!isMenuReady) {
							log("Menu not ready.", level); //{3F.2}
							return;
						}
						if (self.isLevelSelected) {
							log("Already selected!", level); //{3F.2}
							return;
						}
						log("Tapped level number:", level); //{3F.2}
						if (level <= puzzleManager.maxReachedLevelNumber) {
							self.isLevelSelected = true;
							LK.getSound("menuLevelSelect").play();
							// Store initial width and height
							var initialWidth = levelText.width;
							var initialHeight = levelText.height;
							levelText.blendMode = 0;
							//levelText.tint = tileColors[1];
							// Animate width and height to 10 times their size and fade out
							tween(levelText, {
								width: initialWidth * 2,
								height: initialHeight * 2,
								x: levelText.baseX - initialWidth * 0.5,
								y: levelText.baseY - initialHeight * 0.5
							}, {
								duration: 300,
								easing: tween.easeOut,
								onFinish: function onFinish() {
									tween(levelText, {
										width: initialWidth,
										height: initialHeight,
										x: levelText.baseX,
										y: levelText.baseY
									}, {
										duration: 300,
										easing: tween.easeOut,
										onFinish: function onFinish() {
											puzzleManager.selectLevel(level);
											levelText.blendMode = 2;
											levelNumberText.setText(level, level + 1);
											changeGameState(GAME_STATE.NEW_ROUND);
										}
									});
								}
							});
						}
					}; //{3F.3}
				}(levelText, lvl); //{3F.4}
				self.menuGrid[row][col] = levelText;
				self.addChild(levelText);
			}
		}
	}
	self.updateMenuGrid = function () {
		self.isLevelSelected = false;
		// Foreach levelText in menuGrid, update the level color depending on puzzleManager.maxReachedLevelNumber
		for (var row = 0; row < self.menuGrid.length; row++) {
			for (var col = 0; col < self.menuGrid[row].length; col++) {
				var levelText = self.menuGrid[row][col];
				if (levelText) {
					var lvl = levelText.lvl; //parseInt(levelText.text);
					log("Updating levelText for level:", lvl); // Log the level being updated
					var isDone = lvl < puzzleManager.maxReachedLevelNumber;
					var isReached = lvl == puzzleManager.maxReachedLevelNumber;
					var notReached = lvl > puzzleManager.maxReachedLevelNumber;
					var lvlColor = isDone ? 0x6ad100 : 0xF93827;
					lvlColor = notReached ? 0x787878 : lvlColor;
					log("Level color set to:", lvlColor.toString(16)); // Log the color being set
					// levelText.setStyle({
					// 	fill: lvlColor
					// });
					levelText.tint = lvlColor;
					levelText.interactive = true;
					levelText.alpha = lvl <= puzzleManager.maxReachedLevelNumber ? 1 : 0.6;
					log("Level alpha set to:", levelText.alpha); // Log the alpha value being set
				}
			}
		}
	};
	self.animateEntrance = function () {
		var animeDuration = 400;
		self.menuCells.forEach(function (row, rowIndex) {
			//{4e.1}
			row.forEach(function (cell, colIndex) {
				//{4e.2}
				// Start cells off-screen to the right//{4e.3}
				cell.x = 2048 + cell.baseX + cell.width; //{4e.4}
				cell.visible = true; //{4e.5}
				//log("Animating entrance for cell at initial position:", cell.x, cell.y); // Log initial position//{4e.6}
				// Animate cells to their base positions//{4e.7}
				LK.getSound("menuCellEnter").play();
				tween(cell, {
					//{4e.8}
					x: cell.baseX,
					//{4e.9}
					y: cell.baseY //{4e.a}
				}, {
					//{4e.b}
					duration: animeDuration,
					//{4e.c}
					easing: tween.bounceOut,
					//{4e.d}
					delay: colIndex * 150 + rowIndex * 150,
					//{4e.e}
					// Delay each column by 200ms//{4e.f}
					onFinish: function onFinish() {
						if (colIndex % 3 == 0 && rowIndex < self.menuCells.length - 1) {
							LK.getSound("menuCellEnter").play();
						}
						//{4e.g}
						//log("Completed animation for cell to base position:", cell.baseX, cell.baseY); // Log completion//{4e.h}
						isMenuReady = true; //{4e.i}
						if (colIndex == self.menuCells[0].length - 1 && rowIndex == self.menuCells.length - 1) {
							backgroundImage.hideWall();
						}
					} //{4e.j}
				}); //{4e.k}
			}); //{4e.l}
		}); //{4e.m}
		self.menuGrid.forEach(function (row, rowIndex) {
			row.forEach(function (levelText, colIndex) {
				// Start levelTexts off-screen to the right
				levelText.x = 2048 + levelText.baseX + levelText.width;
				levelText.visible = true;
				//log("Animating entrance for levelText at initial position:", levelText.x, levelText.y); // Log initial position
				// Animate levelTexts to their base positions
				tween(levelText, {
					x: levelText.baseX,
					y: levelText.baseY
				}, {
					duration: animeDuration,
					easing: tween.bounceOut,
					delay: colIndex * 150 + rowIndex * 150,
					// Delay each column by 200ms
					onFinish: function onFinish() {
						//log("Completed animation for levelText to base position:", levelText.baseX, levelText.baseY); // Log completion
					}
				});
			});
		});
	};
	self.animateExit = function (callback) {
		var interCellDelay = 100;
		var targetX = -2500;
		LK.getSound("resetSound").play();
		self.menuCells.forEach(function (row, rowIndex) {
			row.forEach(function (cell, colIndex) {
				// Animate cells to exit to the left
				tween(cell, {
					x: cell.baseX + targetX,
					y: cell.baseY
				}, {
					duration: 600,
					easing: tween.easeIn,
					delay: colIndex * interCellDelay + rowIndex * interCellDelay,
					onFinish: function onFinish() {
						log("Completed exit animation for cell at position:", cell.baseX - 2300, cell.baseY);
					}
				});
			});
		});
		self.menuGrid.forEach(function (row, rowIndex) {
			row.forEach(function (levelText, colIndex) {
				// Animate levelTexts to exit to the left
				tween(levelText, {
					x: levelText.baseX + targetX,
					y: levelText.baseY
				}, {
					duration: 600,
					easing: tween.easeIn,
					delay: colIndex * interCellDelay + rowIndex * interCellDelay,
					onFinish: function onFinish() {
						log("Completed exit animation for levelText at position:", levelText.baseX - 2300, levelText.baseY);
						if (rowIndex == self.menuGrid.length - 1 && colIndex == self.menuGrid[self.menuGrid.length - 1].length - 1 && callback) {
							callback();
						}
					}
				});
			});
		});
	};
	return self;
});
// MenuButton class to represent the menu button
var MenuButton = Container.expand(function () {
	var self = Container.call(this);
	// Asset Attachments
	var buttonShadow = self.attachAsset('menuButton', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 8,
		y: 8,
		scaleX: 1.0,
		scaleY: 1.0,
		tint: 0x000000,
		alpha: 0.25
	});
	var buttonGraphics = self.attachAsset('menuButton', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 0,
		y: 0,
		tint: 0x787878,
		blendMode: 1
	});
	self.down = function () {
		self.interactive = false;
		log("MenuButton Down...");
		puzzleManager.reset(true);
		LK.getSound("resetSound").play();
		resetButton.deactivate();
		menuBoard.updateMenuGrid();
		LK.setTimeout(function () {
			backgroundImage.showWall();
			tween(buttonGraphics, {
				scaleY: 0
			}, {
				duration: 500,
				easing: tween.easeOut,
				onFinish: function onFinish() {
					self.deactivate();
					buttonGraphics.scaleY = 1;
					changeGameState(GAME_STATE.MENU);
				}
			});
			tween(buttonShadow, {
				scaleY: 0
			}, {
				duration: 500,
				easing: tween.easeOut,
				onFinish: function onFinish() {
					buttonShadow.scaleY = 1;
				}
			});
		}, 400);
	};
	self.disable = function () {};
	self.enable = function () {};
	self.activate = function () {
		if (self.visible) {
			return;
		}
		self.interactive = true;
		self.visible = true;
		self.y = -300;
		tween(self, {
			y: 130
		}, {
			duration: 500,
			easing: tween.easeOut
		});
	};
	self.deactivate = function () {
		self.visible = false;
	};
	return self;
});
// OperationButton class to represent each operation button
var OperationButton = Container.expand(function (type, index) {
	var self = Container.call(this);
	// Properties
	self.type = type;
	self.index = index;
	self.isSelected = false;
	self.rotation = 0;
	self.baseX = 0;
	self.baseY = 0;
	self.baseR = 0;
	self.visible = false;
	self.interactive = true;
	self.alpha = 1;
	var buttonSize = LK.getAsset('operationButton', {}).width;
	// Asset Attachments
	var buttonGraphicsShadow = self.attachAsset('operationButton', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 10,
		y: 10,
		tint: 0x000000,
		alpha: 0.7
	});
	var buttonGraphics = self.attachAsset('operationButton', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 0,
		y: 0
	});
	var opColor;
	switch (self.type[0]) {
		case "+":
			opColor = 0x6ad100;
			break;
		case "-":
			opColor = 0xF93827;
			break;
		default:
			opColor = 0x1E90FF;
			break;
	}
	// Value Text
	self.valueText = new Text2(self.type, {
		size: buttonSize * 0.45,
		fill: opColor,
		dropShadow: true,
		dropShadowAngle: Math.PI,
		dropShadowDistance: 4,
		weight: 1000
	});
	self.valueText.anchor.set(0.5, 0.5);
	self.valueText.x = buttonGraphics.x;
	self.valueText.y = buttonGraphics.y;
	self.valueText = self.addChild(self.valueText);
	// Functions
	self.setBasePosition = function (x, y, r) {
		self.x = x;
		self.y = y;
		self.rotation = r;
		self.baseX = x;
		self.baseY = y;
		self.baseR = r;
	};
	self.preselect = function () {
		log("operation preselect...");
		var scaleRatio = 2; //{2S.1}
		tween(buttonGraphics, {
			scaleX: scaleRatio,
			scaleY: scaleRatio
		}, {
			duration: 500,
			easing: tween.easeOut
		}); //{2S.2}
		tween(buttonGraphicsShadow, {
			scaleX: scaleRatio,
			scaleY: scaleRatio
		}, {
			duration: 500,
			easing: tween.easeOut
		}); //{2S.3}
		tween(self.valueText, {
			width: self.valueText.width * scaleRatio,
			height: self.valueText.height * scaleRatio
		}, {
			duration: 500,
			easing: tween.easeOut
		});
		tween(self, {
			x: rightOperationPreselectX,
			y: rightOperationPreselectY,
			rotation: rightOperationPreselectR
		}, {
			duration: 500,
			easing: tween.easeOut
		}); //{2S.5}
		self.isSelected = true; //{2T.1}
		self.interactive = true;
		self.alpha = 1;
		self.parent.addChildAt(self, self.parent.children.length - 1); //{2T.2}
	};
	self.show = function () {
		self.visible = true;
	};
	self.pause = function (unpause) {
		tween(self, {
			scaleX: unpause ? 1 : 0.8,
			scaleY: unpause ? 1 : 0.8,
			alpha: unpause ? 1 : 0.5
		}, {
			duration: 300,
			easing: tween.easeOut
		});
	};
	return self;
});
// ResetButton class to represent the reset button
var ResetButton = Container.expand(function () {
	var self = Container.call(this);
	self.isEnabled = false;
	// Asset Attachments
	var buttonShadow = self.attachAsset('resetButton', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 10,
		y: 10,
		tint: 0x000000,
		alpha: 0.25
	});
	var buttonGraphics = self.attachAsset('resetButton', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 0,
		y: 0,
		tint: 0xEAEEE8
	});
	self.down = function () {
		self.disable();
		menuButton.deactivate();
		tween(self, {
			// Animate rotation
			rotation: Math.PI * 2 // Rotate 360 degrees
		}, {
			duration: 500,
			// Duration of the animation
			easing: tween.easeOut,
			// Easing function for smooth transition
			onFinish: function onFinish() {
				self.rotation = 0; // Restore rotation to 0
			}
		});
		LK.getSound("resetSound").play();
		puzzleManager.reset(); // Reset the level puzzle 
	};
	self.disable = function () {
		log("Reset button disable...");
		self.isEnabled = false;
		buttonGraphics.alpha = 0.5; // Dim the button to indicate it's disabled
		self.interactive = false; // Disable interaction
		tween(self, {
			scaleX: 0.8,
			scaleY: 0.8
		}, {
			duration: 300,
			easing: tween.easeOut
		});
	};
	self.enable = function () {
		log("Reset button enable...");
		self.isEnabled = true;
		buttonGraphics.alpha = 1.0; // Restore full opacity to indicate it's enabled
		self.interactive = true; // Enable interaction
		tween(self, {
			scaleX: 1.0,
			scaleY: 1.0
		}, {
			duration: 300,
			easing: tween.easeOut
		});
	};
	self.activate = function () {
		log("Reset button activate...");
		if (puzzleManager.currentLevel == 1) {
			log("No Reset in level 1...");
			return;
		}
		self.visible = true;
		self.y = -300;
		tween(self, {
			y: 130
		}, {
			duration: 500,
			easing: tween.easeOut
		});
		if (self.isEnabled) {
			// TODO : Remplacer par puzzel.made move!!!!!!!!
			self.enable();
		}
	};
	self.deactivate = function () {
		log("Reset button deactivate...");
		tween(self, {
			y: -300
		}, {
			duration: 300,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				log("Reset button deactivate : hiding");
				self.visible = false;
			}
		});
	};
	self.highlight = function () {
		tween(self, {
			scaleX: 1.2,
			scaleY: 1.2
		}, {
			duration: 300,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				tween(self, {
					scaleX: 1.0,
					scaleY: 1.0
				}, {
					duration: 300,
					easing: tween.easeOut
				});
			}
		});
	};
	return self;
});
// StartButton class to represent the start button
var StartButton = Container.expand(function () {
	var self = Container.call(this);
	// Asset Attachments
	self.buttonGraphics = self.attachAsset('startButton', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 0,
		y: 0,
		visible: true
	});
	self.letterGraphics = [];
	// Individual letter texts for "START"
	var letters = ['S', 'T', 'A', 'R', 'T'];
	var tileSpacing = 390;
	var letterPositions = {
		0: {
			'x': -585,
			'y': -300
		},
		1: {
			'x': -195,
			'y': -300
		},
		2: {
			'x': 0,
			'y': 0
		},
		3: {
			'x': 195,
			'y': 300
		},
		4: {
			'x': 585,
			'y': 300
		}
	};
	letters.forEach(function (letter, index) {
		var letterContainer = new Container();
		var tileGraphics = letterContainer.attachAsset('hexTile', {
			anchorX: 0.5,
			anchorY: 0.5,
			width: 390,
			height: 390,
			x: 0,
			y: 0,
			tint: tileColors[1 + index % 3],
			alpha: 1
		});
		var letterText = new Text2(letter, {
			size: 260,
			fill: 0xEAEEE8,
			weight: 1000,
			dropShadow: true,
			dropShadowAngle: Math.PI,
			dropShadowDistance: 10
		});
		letterText.anchor.set(0.5, 0.5);
		letterText.alpha = 0.9;
		letterText.blendMode = 0;
		letterText.visible = true;
		letterText.x = 0;
		letterContainer.addChild(tileGraphics);
		letterContainer.addChild(letterText);
		letterContainer.x = letterPositions[index].x; //(index - 2) * tileSpacing;
		letterContainer.y = letterPositions[index].y;
		log("letter:", letter, letterContainer.x);
		self.letterGraphics.push(letterContainer);
		self.addChild(letterContainer);
	});
	self.fadeOut = function () {
		LK.getSound('tileRemove').play();
		self.letterGraphics.forEach(function (letterContainer) {
			tween(letterContainer, {
				scaleX: 0,
				scaleY: 0,
				rotation: Math.PI / 2
			}, {
				duration: 1000,
				easing: tween.easeOut,
				onFinish: function onFinish() {
					tween(self.buttonGraphics, {
						alpha: 0
					}, {
						duration: 1000,
						easing: tween.easeOut,
						onFinish: function onFinish() {
							self.visible = false;
							self.destroy();
						}
					});
				}
			});
		});
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x000000 // Set game background to black 
});
/**** 
* Game Code
****/ 
function _typeof2(o) {
	"@babel/helpers - typeof";
	return _typeof2 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
		return typeof o;
	} : function (o) {
		return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
	}, _typeof2(o);
}
function _defineProperty3(e, r, t) {
	return (r = _toPropertyKey2(r)) in e ? Object.defineProperty(e, r, {
		value: t,
		enumerable: !0,
		configurable: !0,
		writable: !0
	}) : e[r] = t, e;
}
function _toPropertyKey2(t) {
	var i = _toPrimitive2(t, "string");
	return "symbol" == _typeof2(i) ? i : i + "";
}
function _toPrimitive2(t, r) {
	if ("object" != _typeof2(t) || !t) {
		return t;
	}
	var e = t[Symbol.toPrimitive];
	if (void 0 !== e) {
		var i = e.call(t, r || "default");
		if ("object" != _typeof2(i)) {
			return i;
		}
		throw new TypeError("@@toPrimitive must return a primitive value.");
	}
	return ("string" === r ? String : Number)(t);
}
function _typeof(o) {
	"@babel/helpers - typeof";
	return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
		return typeof o;
	} : function (o) {
		return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
	}, _typeof(o);
}
function _defineProperty(e, r, t) {
	return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
		value: t,
		enumerable: !0,
		configurable: !0,
		writable: !0
	}) : e[r] = t, e;
}
function _toPropertyKey(t) {
	var i = _toPrimitive(t, "string");
	return "symbol" == _typeof(i) ? i : i + "";
}
function _toPrimitive(t, r) {
	if ("object" != _typeof(t) || !t) {
		return t;
	}
	var e = t[Symbol.toPrimitive];
	if (void 0 !== e) {
		var i = e.call(t, r || "default");
		if ("object" != _typeof(i)) {
			return i;
		}
		throw new TypeError("@@toPrimitive must return a primitive value.");
	}
	return ("string" === r ? String : Number)(t);
}
function resetAdjacentTilesScale() {
	currentAdjacentTiles.forEach(function (adjTile) {
		adjTile.isHighlighted = false;
		tween(adjTile, {
			scaleX: 1,
			scaleY: 1
		}, {
			duration: 200,
			easing: tween.easeOut
		});
	});
	currentAdjacentTiles = []; // Clear the list after restoring scale
}
function playFinalAnimation() {
	LK.getSound("applause").play();
	// Create and animate confetti
	for (var i = 0; i < 100; i++) {
		var confetti = new Confetti();
		confetti.x = Math.random() * 2048;
		confetti.y = Math.random() * 2732;
		game.addChild(confetti);
	}
}
/***********************************************************************************************/ 
// Transition to menu state
function PuzzleManager(game) {
	var self = this;
	// Properties
	self.game = game;
	self.activeTileCount = 0; // Initialize active tile count
	self.levelBoardOffsetX = 0; // Initialize levelBoardOffsetX
	self.levelBoardOffsetY = 0; // Initialize levelBoardOffsetY
	self.currentLevel = debug ? 30 : 1;
	self.previousLevelNumber = 1;
	self.maxReachedLevelNumber = debug ? self.currentLevel : storage.maxReachedLevelNumber || 1; // Retrieve from storage or default to 1
	self.board = [];
	self.operations = [];
	self.isAnimating = false;
	self.selectedOperation = null;
	self.moveCount = 0;
	self.levelData = null;
	self.levelFailed = false;
	// Core Functions
	self.initPuzzle = function () {
		if (currentState != GAME_STATE.NEW_ROUND) {
			log("InitPuzzle in wrong state", currentState);
			return;
		}
		self.loadLevel(self.currentLevel);
	};
	self.selectLevel = function (level) {
		self.currentLevel = level;
		self.previousLevelNumber = level;
	};
	self.cleanAnimate = function () {
		// Remove all existing tiles
		self.board.forEach(function (tile) {
			// Animate tiles moving randomly out of screen
			tween(tile, {
				x: Math.random() > 0.5 ? -200 - Math.random() * 1000 : 2248 + Math.random() * 1000,
				y: Math.random() > 0.5 ? -200 - Math.random() * 1000 : 2732 + Math.random() * 1000
			}, {
				duration: 800,
				easing: tween.easeIn,
				onFinish: function onFinish() {
					tile.destroy();
				}
			});
		});
		// Remove all existing operations
		self.operations.forEach(function (operation) {
			// Animate operations moving randomly out of screen
			tween(operation, {
				x: Math.random() > 0.5 ? -200 - Math.random() * 1000 : 2248 + Math.random() * 1000,
				y: Math.random() > 0.5 ? -200 - Math.random() * 1000 : 2732 + Math.random() * 1000
			}, {
				duration: 800,
				easing: tween.easeIn,
				onFinish: function onFinish() {
					operation.destroy();
				}
			});
		});
	};
	self.reset = function (noContinue) {
		gameHints.removeHint();
		self.cleanAnimate();
		// // Remove all existing tiles
		// self.board.forEach(function (tile) {
		// 	// Animate tiles moving randomly out of screen
		// 	tween(tile, {
		// 		x: Math.random() > 0.5 ? -200 - Math.random() * 1000 : 2248 + Math.random() * 1000,
		// 		y: Math.random() > 0.5 ? -200 - Math.random() * 1000 : 2732 + Math.random() * 1000
		// 	}, {
		// 		duration: 800,
		// 		easing: tween.easeIn,
		// 		onFinish: function onFinish() {
		// 			tile.destroy();
		// 		}
		// 	});
		// });
		self.board = [];
		// Remove all existing operations
		// self.operations.forEach(function (operation) {
		// 	// Animate operations moving randomly out of screen
		// 	tween(operation, {
		// 		x: Math.random() > 0.5 ? -200 - Math.random() * 1000 : 2248 + Math.random() * 1000,
		// 		y: Math.random() > 0.5 ? -200 - Math.random() * 1000 : 2732 + Math.random() * 1000
		// 	}, {
		// 		duration: 800,
		// 		easing: tween.easeIn,
		// 		onFinish: function onFinish() {
		// 			operation.destroy();
		// 		}
		// 	});
		// });
		self.operations = [];
		self.levelFailed = false;
		// Load the current level
		self.previousLevelNumber = self.currentLevel;
		if (noContinue) {
			console.log("End Reset, but no continue. currentState", currentState);
			return;
		}
		LK.setTimeout(function () {
			console.log("End Reset, now loadLevel currentState ", currentState);
			self.loadLevel(self.currentLevel);
		}, 850);
	};
	self.loadLevel = function (levelNumber) {
		log("loadLevel...previousLevelNumber", self.previousLevelNumber, " new levelNumber:", levelNumber);
		// Load level configuration
		self.levelData = levelConfigs[levelNumber] || {
			tiles: [],
			operations: []
		};
		currentTransitionDirectionH = levelNumber > self.previousLevelNumber ? 1 : 0;
		currentTransitionDirectionV = levelNumber > self.previousLevelNumber ? Math.random() > 0.5 ? -1 : 1 : 0;
		log("transitions :", currentTransitionDirectionH, currentTransitionDirectionV);
		levelNumberText.updateLevel(levelNumber, currentTransitionDirectionH, currentTransitionDirectionV);
		backgroundImage.animateTransition(currentTransitionDirectionH, currentTransitionDirectionV);
		self.createBoard();
		self.fillTilesNeighbors();
		self.createOperations();
		//LK.setTimeout(self.animateTilesEntrance, levelNumber == 1 ? 0 : 800);
		//LK.setTimeout(self.animateOperationsEntrance, 900);
		//LK.setTimeout(self.updateOperations, 900);
		LK.setTimeout(function () {
			self.animateTilesEntrance();
			self.animateOperationsEntrance();
			resetButton.activate(); // Make resetButton visible in PLAYING state
			menuButton.activate();
		}, 800);
	};
	self.createBoard = function () {
		self.board = [];
		// Max grid for 200px tiles = 11x7
		var maxRows = self.levelData.tiles.length;
		var maxColsRowIndex = 0;
		var maxCols = 0; // Local variable to track the largest number of tiles in the level rows
		self.activeTileCount = 0; // Reset active tile count
		// Update levelBoardOffsets depending on level 
		for (var row = 0; row < self.levelData.tiles.length; row++) {
			var firstColWithValue = -1; // Initialize to -1 to indicate no value found yet
			var lastColWithValue = -1; // Initialize to -1 to indicate no value found yet
			for (var col = 0; col < self.levelData.tiles[row].length; col++) {
				var value = self.levelData.tiles[row][col]; //{4r.1}
				if (value !== "") {
					//{4r.2}
					if (firstColWithValue === -1) {
						// Check if this is the first value in the row
						firstColWithValue = col;
					}
					lastColWithValue = col; // Update lastColWithValue to the current column
					var tile = new HexTile(value, col, row, self.levelData); //{4r.3}
					self.board.push(tile); //{4r.4}
					boardContainer.addChild(tile); //{4r.5}
					self.activeTileCount++; // Increment active tile count //{4r.6}
				} //{4r.7}
			}
			var tempMaxCols = lastColWithValue - firstColWithValue + 1; // Calculate the number of columns with values
			log("tempMaxCols=", tempMaxCols, maxCols); //{4q.1}
			if (tempMaxCols > maxCols) {
				//{4q.2}
				maxCols = tempMaxCols; //{4q.3}
				maxColsRowIndex = row; //{4q.4}
			} //{4q.5}
		}
		log("boardContainer: ", boardContainer.x, boardContainer.y);
		if (self.board.length > 0) {
			log("createBoard calc: ", game.width, maxCols, self.board[0].tileSizeX, -maxCols * self.board[0].tileSizeX); //{5A.1}
			var actualTilesizeX = self.board[0].tileSizeX; //{5A.2}
			var actualTilesizeY = self.board[0].tileSizeY; //{5A.3}
		} else {
			log("createBoard calc: Board is empty, skipping tile size calculations.");
			var actualTilesizeX = 0;
			var actualTilesizeY = 0;
		}
		var fixOffsetX = 0;
		switch (maxCols) {
			case 3:
				fixOffsetX = -367; // -115 - 4 * 63;
				break;
			case 5:
				fixOffsetX = -265;
				break;
			case 6:
				fixOffsetX = -220;
				break;
			case 7:
				fixOffsetX = -175;
				break;
			default:
				fixOffsetX = -115 - Math.max(0, 7 - maxCols) * 63;
				break;
		}
		self.levelBoardOffsetX = (game.width - maxCols * actualTilesizeX) / 2 + fixOffsetX + (maxColsRowIndex % 2 != 0 ? -actualTilesizeX / 2 : 0);
		log("Cols: ", maxCols, " actualTilesizeX=", actualTilesizeX, " C x Size =>  ", actualTilesizeX * maxCols, " self.levelBoardOffsetX=", self.levelBoardOffsetX, " fix =", fixOffsetX);
		var fixOffsetY = 0;
		switch (maxRows) {
			case 3:
				fixOffsetY = -280;
				break;
			case 4:
				fixOffsetY = -180;
				break;
			case 5:
				fixOffsetY = -80;
				break;
			case 6:
				fixOffsetY = 0;
				break;
			case 7:
				fixOffsetY = 165;
				break;
			case 8:
				fixOffsetY = 250;
				break;
			case 9:
				fixOffsetY = 400;
				break;
			case 11:
				fixOffsetY = 615;
				break;
			default:
				fixOffsetY = maxRows * 0.4 * actualTilesizeY;
				break;
		}
		self.levelBoardOffsetY = (game.height - maxRows * actualTilesizeY) / 2 - maxRows * 0.5 * actualTilesizeY + fixOffsetY;
		log("Rows: ", maxRows, " actualTilesizeY=", actualTilesizeY, " R x Size =>  ", actualTilesizeY * maxRows, " self.levelBoardOffsetX=", self.levelBoardOffsetY, " fix =", fixOffsetY);
		log("createBoard max dimensions: ", maxRows, maxCols, " largest row #", maxColsRowIndex, " OffsetX=", self.levelBoardOffsetX, " OffsetY=", self.levelBoardOffsetY);
		for (var i = 0; i < self.board.length; i++) {
			var tile = self.board[i];
			//log("tile #" + i, tile); //{4q.1}
			var oddOffset = tile.row % 2 == 0 ? actualTilesizeX / 2 : 0;
			tile.setBasePosition(tile.x + self.levelBoardOffsetX + oddOffset, tile.y + self.levelBoardOffsetY);
		}
	};
	self.fillTilesNeighbors = function () {
		for (var i = 0; i < self.board.length; i++) {
			var tile = self.board[i];
			tile.neighbors = [];
			for (var j = 0; j < self.board.length; j++) {
				var potentialNeighbor = self.board[j];
				if (tile !== potentialNeighbor && self.areNeighbors(tile, potentialNeighbor)) {
					tile.neighbors.push(potentialNeighbor);
				}
			}
		}
	};
	self.areNeighbors = function (tile1, tile2) {
		if (tile1.value != tile2.value) {
			return false;
		}
		var dx = Math.abs(tile1.col - tile2.col); //{6b.1}
		var dy = Math.abs(tile1.row - tile2.row); //{6b.2}
		var areNeighbors = dx === 1 && dy === 0 || dx === 0 && dy === 1 || dx === 1 && dy === 1 && (tile1.row % 2 === 0 && tile2.col > tile1.col || tile1.row % 2 !== 0 && tile2.col < tile1.col); //{6b.4}
		//log("are neighbors: T1 row:", tile1.row, "col:", tile1.col, " val:", tile1.value, " vs T2 row:", tile2.row, "col:", tile2.col, " val:", tile2.value, " => dx:", dx, "dy:", dy, " => ", areNeighbors); //{6b.3}
		return areNeighbors; //{6b.6}
	};
	self.getAdjacentTiles = function (tile) {
		var adjacentTiles = [];
		var toCheck = [tile];
		var checked = [];
		while (toCheck.length > 0) {
			var currentTile = toCheck.pop();
			if (checked.includes(currentTile)) {
				continue;
			}
			checked.push(currentTile);
			currentTile.neighbors.forEach(function (neighbor) {
				if (neighbor.value === tile.value && !checked.includes(neighbor)) {
					adjacentTiles.push(neighbor);
					toCheck.push(neighbor);
				}
			});
		}
		return adjacentTiles;
	};
	self.createOperations = function () {
		self.operations.forEach(function (operation) {
			operation.destroy();
		});
		self.operations = [];
		var baseX = 100;
		var baseY = 2600;
		for (var i = 0; i < self.levelData.operations.length; i++) {
			var opType = self.levelData.operations[i];
			var operation = new OperationButton(opType, i);
			self.operations.push(operation);
			var operationX = operationsSlots[i].x;
			var operationY = operationsSlots[i].y;
			var operationR = operationsSlots[i].r;
			operation.setBasePosition(operationX, operationY, operationR); // Space buttons evenly and position near the bottom
			self.game.addChild(operation);
		}
	};
	self.pauseOperations = function (unpause) {
		log("pauseOperations:", self.operations);
		if (!self.operations || !self.operations.length) {
			return;
		}
		for (var i = 0; i < self.levelData.operations.length; i++) {
			if (self.operations[i]) {
				var op = self.operations[i];
				op.pause(unpause);
			}
		}
	};
	self.updateOperations = function () {
		log("updateOperations:", self.operations);
		if (!self.operations || !self.operations.length) {
			return;
		}
		for (var i = 0; i < self.levelData.operations.length; i++) {
			if (self.operations[i]) {
				var op = self.operations[i];
				op.show();
				var operationX = op.baseX; // operationsSlots[i].x;
				var operationY = op.baseY; // operationsSlots[i].y;
				var operationR = op.baseR; // operationsSlots[i].r;
				log("Updating :", i, " old x=", op.x, " => operationX:", operationX);
				tween(op, {
					x: operationX,
					y: operationY,
					rotation: operationR
				}, {
					//{4S.2}
					duration: 500,
					// Duration of the animation in milliseconds //{4S.3}
					easing: tween.easeOut // Easing function for smooth transition //{4S.4}
				}); //{4S.5}
			}
		}
	};
	self.applyOperation = function (operation, tile) {
		log("applyOperation... isAnimating:", self.isAnimating);
		if (self.isAnimating) {
			return false; // Exit if an operation is already in progress
		}
		self.pauseOperations();
		self.isAnimating = true; // Set animating flag
		self.propagateOperation(operation, tile);
		// Remove used operation from the list
		var operationIndex = self.operations.indexOf(operation);
		if (operationIndex > -1) {
			self.operations.splice(operationIndex, 1);
			if (operation) {
				operation.destroy();
			}
		}
		self.checkWinCondition();
		LK.setTimeout(function () {
			self.updateOperations();
			self.fillTilesNeighbors();
			log("applyOperation... Ok applied done:");
			self.isAnimating = false; // Reset animating flag after operation is done
			self.pauseOperations(true);
		}, 1000);
		return true;
	};
	self.propagateOperation = function (operation, startTile) {
		var visited = [];
		var toProcess = [{
			tile: startTile,
			depth: 0
		}];
		var targetValue = startTile.value;
		log("Starting propagateOperation with targetValue:", targetValue, " operation=", operation);
		while (toProcess.length > 0) {
			var current = toProcess.pop();
			var currentTile = current.tile;
			var startX = startTile.x;
			var startY = startTile.y;
			var dx = Math.abs(currentTile.col - startTile.col);
			var dy = Math.abs(currentTile.row - startTile.row);
			var normalizedDistance = Math.max(dx, dy); // Use the maximum of dx and dy to count the distance in tiles
			log("Processing tile at position:", currentTile.x, currentTile.y, "with value:", currentTile.value, "at normalized distance:", normalizedDistance);
			if (visited.includes(currentTile)) {
				log("Tile already visited:", currentTile);
				continue;
			}
			visited.push(currentTile);
			//var operationType = operation ? parseInt(operation.type) : 0;
			var operationType = 0;
			if (operation) {
				if (operation.type == "ร2" || operation.type == "x2") {
					operationType = currentTile.value;
				} else {
					operationType = parseInt(operation.type);
				}
			}
			if (!operationType) {
				log("Invalid operation !!!", operationType);
				return;
			}
			var newValue = Math.max(0, currentTile.value + operationType);
			if (newValue <= 0) {
				self.activeTileCount--;
			}
			resetButton.enable();
			currentTile.setValue(newValue, normalizedDistance);
			log("Applied operation. New value:", currentTile.value);
			// Check neighbors
			var _iterator = _createForOfIteratorHelper(currentTile.neighbors),
				_step;
			try {
				for (_iterator.s(); !(_step = _iterator.n()).done;) {
					var neighbor = _step.value;
					log("Checking neighbor at position:", neighbor.x, neighbor.y, "with value:", neighbor.value);
					if (neighbor.value === targetValue && !visited.includes(neighbor)) {
						log("Neighbor matches target value and is not visited. Adding to process list:", neighbor);
						toProcess.push({
							tile: neighbor,
							depth: normalizedDistance + 1
						});
					}
				}
			} catch (err) {
				_iterator.e(err);
			} finally {
				_iterator.f();
			}
		}
		log("Finished propagateOperation");
	};
	self.animateTilesEntrance = function () {
		self.board.forEach(function (tile, index) {
			// Place tiles randomly out of the screen
			tile.x = Math.random() > 0.5 ? -200 - Math.random() * 1000 : 2248 + Math.random() * 1000;
			tile.y = Math.random() > 0.5 ? -200 - Math.random() * 1000 : 2732 + Math.random() * 1000;
			//log("animateTilesEntrance #" + index, tile.x, tile.y);
			tile.visible = true;
			if (index < 6) {
				LK.setTimeout(function () {
					LK.getSound("tileEntrance").play();
				}, 100 + index * 75);
			}
			// Animate tiles to their base positions
			tween(tile, {
				x: tile.baseX + self.levelBoardOffsetX,
				y: tile.baseY + self.levelBoardOffsetY
			}, {
				duration: 800,
				easing: tween.bounceOut
			});
		});
	};
	self.animateOperationsEntrance = function () {
		self.operations.forEach(function (op, index) {
			// Place tiles randomly out of the screen
			op.x = Math.random() > 0.5 ? -200 - Math.random() * 1000 : 2248 + Math.random() * 1000;
			op.x = Math.random() > 0.5 ? -200 - Math.random() * 1000 : 2248 + Math.random() * 1000;
			op.rotation = Math.random() * Math.PI * 2;
			//log("animateOperationsEntrance #" + index, op.x, op.y);
			op.visible = true;
			// Animate tiles to their base positions
			tween(op, {
				x: op.baseX,
				y: op.baseY,
				rotation: op.baseR
			}, {
				duration: 800,
				easing: tween.bounceOut
			});
		});
	};
	self.checkWinCondition = function () {
		log("checkWinCondition... Active tiles:", self.activeTileCount);
		if (self.activeTileCount <= 0) {
			self.playVictoryAnimation();
			isPlaying = false;
			resetButton.disable();
			menuButton.deactivate();
			LK.setTimeout(function () {
				self.previousLevelNumber = self.currentLevel;
				self.currentLevel++; // Advance to the next level
				gameHints.removeHint();
				if (self.currentLevel > self.maxReachedLevelNumber) {
					self.maxReachedLevelNumber = self.currentLevel; //{b6.1}
					storage.maxReachedLevelNumber = self.maxReachedLevelNumber; // Store in storage
				} //{b6.2}
				changeGameState(GAME_STATE.NEW_ROUND); // Change state to newRound
			}, 2000);
			return true;
		}
		// if tiles remaning but no more operations play level failed animation 
		if (self.activeTileCount > 0 && self.operations.length === 0) {
			self.levelFailed = true;
			LK.setTimeout(self.playLevelFailedAnimation, 800);
			return false;
		}
	};
	// Animation Functions
	self.playVictoryAnimation = function () {
		log("playVictoryAnimation...previousLevelNumber", self.previousLevelNumber);
		// Play level complete animation
		playFinalAnimation(); // TEMP DEBUG
	};
	self.playLevelFailedAnimation = function () {
		log("playLevelFailedAnimation...");
		LK.getSound("levelFailed").play();
		self.board.forEach(function (tile) {
			if (tile.value > 0) {
				// Only shake tiles with a value greater than 0
				tile.shake();
			}
		});
		resetButton.highlight();
	};
}
/***********************************************************************************************/ 
/************************************* UTILITY FUNCTIONS ************************************/
/***********************************************************************************************/ 
function log() {
	if (debug) {
		console.log.apply(console, arguments);
	}
}
function _createForOfIteratorHelper(r, e) {
	var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
	if (!t) {
		if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) {
			t && (r = t);
			var _n = 0,
				F = function F() {};
			return {
				s: F,
				n: function n() {
					return _n >= r.length ? {
						done: !0
					} : {
						done: !1,
						value: r[_n++]
					};
				},
				e: function e(r) {
					throw r;
				},
				f: F
			};
		}
		throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
	}
	var o,
		a = !0,
		u = !1;
	return {
		s: function s() {
			t = t.call(r);
		},
		n: function n() {
			var r = t.next();
			return a = r.done, r;
		},
		e: function e(r) {
			u = !0, o = r;
		},
		f: function f() {
			try {
				a || null == t["return"] || t["return"]();
			} finally {
				if (u) {
					throw o;
				}
			}
		}
	};
}
function _unsupportedIterableToArray(r, a) {
	if (r) {
		if ("string" == typeof r) {
			return _arrayLikeToArray(r, a);
		}
		var t = {}.toString.call(r).slice(8, -1);
		return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;
	}
}
function _arrayLikeToArray(r, a) {
	(null == a || a > r.length) && (a = r.length);
	for (var e = 0, n = Array(a); e < a; e++) {
		n[e] = r[e];
	}
	return n;
}
// Business tools
function isPointInsideTile(x, y, tile) {
	var overlapOffsetX = 10; // Offset to prevent multiple tile selection on X-axis
	var overlapOffsetY = 45; // Offset to prevent multiple tile selection on Y-axis
	return x >= boardContainer.x + tile.x - tile.width / 2 + overlapOffsetX && x <= boardContainer.x + tile.x + tile.width / 2 - overlapOffsetX && y >= boardContainer.y + tile.y - tile.height / 2 + overlapOffsetY && y <= boardContainer.y + tile.y + tile.height / 2 - overlapOffsetY;
}
/***********************************************************************************************/ 
/************************************* GAME STATE MANAGEMENT ************************************/
/***********************************************************************************************/ 
function cleanInitState() {
	// Clean up the game state for MENU
	log("Cleaning INIT State");
	startButton.fadeOut();
}
function initMenuState() {
	// Initialize the game state for MENU
	log("Initializing MENU State");
	//menuBoard.x = 2048; // Start off-screen to the right
	menuBoard.visible = true;
	var delayAnim = startButton.visible ? 800 : 0;
	LK.setTimeout(function () {
		if (puzzleManager.maxReachedLevelNumber == 1)
			// First Launch => Auto-select level 1
			{
				backgroundImage.hideWall();
				menuBoard.visible = false;
				puzzleManager.selectLevel(1);
				levelNumberText.setText(1, 2);
				changeGameState(GAME_STATE.NEW_ROUND);
			} else {
			menuBoard.animateEntrance();
		}
	}, delayAnim);
	menuButton.deactivate();
}
function handleMenuLoop() {
	// Handle the game loop for MENU state
	log("Handling MENU Loop");
}
function cleanMenuState() {
	// Clean up the game state for MENU
	log("Cleaning MENU State");
	isMenuReady = false;
	menuBoard.animateExit(function () {
		menuBoard.visible = false;
		backgroundImage.hideWall();
	});
}
function initNewRoundState() {
	// Initialize the game state for NEW_ROUND
	log("Initializing NEW_ROUND State");
	if (!levelConfigs[puzzleManager.currentLevel]) {
		puzzleManager.cleanAnimate(); // in case of remaning tiles
		changeGameState(GAME_STATE.SCORE);
		return;
	}
	puzzleManager.initPuzzle();
	levelNumberText.show();
	changeGameState(GAME_STATE.PLAYING);
}
function handleNewRoundLoop() {
	// Handle the game loop for NEW_ROUND state
	log("Handling NEW_ROUND Loop");
}
function cleanNewRoundState() {
	// Clean up the game state for NEW_ROUND
	log("Cleaning NEW_ROUND State");
}
function initPlayingState() {
	// Initialize the game state for PLAYING
	log("Initializing PLAYING State");
	if (puzzleManager.currentLevel == 1) {
		showHintsInterval = LK.setTimeout(function () {
			gameHints.showHint1();
		}, 2000);
	}
	// LK.setTimeout(function () {
	// 	//resetButton.disable();
	// 	resetButton.activate(); // Make resetButton visible in PLAYING state
	// 	menuButton.activate();
	// }, 3000);
}
function handlePlayingLoop() {
	// Handle the game loop for PLAYING state
	log("Handling PLAYING Loop");
}
function cleanPlayingState() {
	// Clean up the game state for PLAYING
	log("Cleaning PLAYING State");
	if (showHintsInterval) {
		LK.clearTimeout(showHintsInterval);
	}
	menuButton.deactivate();
	resetButton.deactivate();
}
function initScoreState() {
	// Initialize the game state for SCORE
	log("Initializing SCORE State");
	levelNumberText.updateLevel(0, 1, 1);
	backgroundImage.animateTransition(1, 1);
}
function handleScoreLoop() {
	// Handle the game loop for SCORE state
	log("Handling SCORE Loop");
}
function cleanScoreState() {
	// Clean up the game state for SCORE
	log("Cleaning SCORE State");
}
function changeGameState(newState) {
	log("Changing game state from", currentState, "to", newState);
	// Clean up the current state
	switch (currentState) {
		case GAME_STATE.INIT:
			cleanInitState();
			break;
		case GAME_STATE.MENU:
			cleanMenuState();
			break;
		case GAME_STATE.NEW_ROUND:
			cleanNewRoundState();
			break;
		case GAME_STATE.PLAYING:
			cleanPlayingState();
			break;
		case GAME_STATE.SCORE:
			cleanScoreState();
			break;
		default:
			log("Unknown state:", currentState);
	}
	// Set the new state
	currentState = newState;
	// Initialize the new state
	switch (newState) {
		case GAME_STATE.INIT:
			// Do nothing
			break;
		case GAME_STATE.MENU:
			initMenuState();
			break;
		case GAME_STATE.NEW_ROUND:
			initNewRoundState();
			break;
		case GAME_STATE.PLAYING:
			initPlayingState();
			break;
		case GAME_STATE.SCORE:
			initScoreState();
			break;
		default:
			log("Unknown state:", newState);
	}
}
/***********************************************************************************************/ 
/****************************************** EVENT HANDLERS *************************************/
/***********************************************************************************************/ 
game.down = function (x, y, obj) {
	switch (currentState) {
		case GAME_STATE.INIT:
			handleInitStateDown(x, y, obj);
			break;
		case GAME_STATE.MENU:
			handleMenuStateDown(x, y, obj);
			break;
		case GAME_STATE.PLAYING:
			handlePlayingStateDown(x, y, obj);
			break;
		case GAME_STATE.SCORE:
			handleScoreStateDown(x, y, obj);
			break;
		default:
			log("Unknown state:", currentState);
	}
};
game.move = function (x, y, obj) {
	switch (currentState) {
		case GAME_STATE.INIT:
			// Do nothing
			break;
		case GAME_STATE.MENU:
			handleMenuStateMove(x, y, obj);
			break;
		case GAME_STATE.PLAYING:
			handlePlayingStateMove(x, y, obj);
			break;
		case GAME_STATE.SCORE:
			handleScoreStateMove(x, y, obj);
			break;
		default:
			log("Unknown state:", currentState);
	}
};
game.up = function (x, y, obj) {
	switch (currentState) {
		case GAME_STATE.INIT:
			// Do nothing
			break;
		case GAME_STATE.MENU:
			handleMenuStateUp(x, y, obj);
			break;
		case GAME_STATE.PLAYING:
			handlePlayingStateUp(x, y, obj);
			break;
		case GAME_STATE.SCORE:
			handleScoreStateUp(x, y, obj);
			break;
		default:
			log("Unknown state:", currentState);
	}
};
// Menu State Handlers
function handleInitStateDown(x, y, obj) {
	// Implement logic for handling down event in MENU state
	log("Handling down event in INIT state");
	changeGameState(GAME_STATE.MENU);
}
// Menu State Handlers
function handleMenuStateDown(x, y, obj) {
	// Implement logic for handling down event in MENU state
	log("Handling down event in MENU state");
}
function handleMenuStateMove(x, y, obj) {
	// Implement logic for handling move event in MENU state
	//log("Handling move event in MENU state");
}
function handleMenuStateUp(x, y, obj) {
	// Implement logic for handling up event in MENU state
	log("Handling up event in MENU state");
}
// Playing State Handlers
function handlePlayingStateDown(x, y, obj) {
	// Implement logic for handling down event in PLAYING state
	log("Handling down event in PLAYING state", obj);
	puzzleManager.operations.forEach(function (operation) {
		//operation.isSelected &&
		if (!dragNode && !isApplyingOperation && !puzzleManager.isAnimating && x >= operation.x - operation.width / 2 && x <= operation.x + operation.width / 2 && y >= operation.y - operation.height / 2 && y <= operation.y + operation.height / 2) {
			log("Ok Dragging operation ", operation);
			dragNode = operation;
			tween(operation, {
				rotation: 0,
				scaleX: 0.6,
				scaleY: 0.6
			}, {
				duration: 500,
				easing: tween.easeOut
			});
			LK.getSound('operationSelect').play();
			if (puzzleManager.currentLevel == 1 && gameHints.hasShowHint == 1) {
				LK.clearTimeout(showHintsInterval);
				showHintsInterval = LK.setTimeout(function () {
					gameHints.showHint2();
				}, 800);
			}
			return;
		}
	});
	if (!dragNode) {
		// Check if tapping a tile, if so play 'tick'
		puzzleManager.board.forEach(function (tile) {
			if (!tile.isHighlighted && isPointInsideTile(x, y, tile)) {
				if (puzzleManager.levelFailed) {
					puzzleManager.playLevelFailedAnimation();
					return;
				}
				tile.isHighlighted = true;
				if (typeof tile.previousZIndex === 'undefined') {
					tile.previousZIndex = boardContainer.getChildIndex(tile); // Store previous z-index
				}
				boardContainer.addChildAt(tile, boardContainer.children.length - 1); // Bring tile to the front
				tween(tile, {
					scaleX: 1.33,
					scaleY: 1.33
				}, {
					duration: 200,
					easing: tween.easeOut
				});
				// Play tick sound when a tile is highlighted
				LK.getSound('tick').play();
				currentHighlightedTile = tile; // Store the currently highlighted tile in a global variable
				if (currentAdjacentTiles && currentAdjacentTiles.length > 0 && currentAdjacentTiles[0].value != tile.value) {
					resetAdjacentTilesScale();
				}
				currentAdjacentTiles = puzzleManager.getAdjacentTiles(tile);
				currentAdjacentTiles.forEach(function (adjTile) {
					adjTile.isHighlighted = true;
					var dx = Math.abs(adjTile.col - tile.col);
					var dy = Math.abs(adjTile.row - tile.row);
					var normalizedDistance = Math.max(dx, dy);
					tween(adjTile, {
						scaleX: 1.33,
						scaleY: 1.33
					}, {
						duration: 200,
						easing: tween.easeOut,
						delay: normalizedDistance * 75 // Delay based on normalized distance
					});
				});
				return;
			}
		});
	}
}
function handlePlayingStateMove(x, y, obj) {
	//log("Handling move event in PLAYING state", dragNode);
	if (dragNode && !isAnimatingDragNode && !isApplyingOperation) {
		// Calculate rotation based on x delta
		var deltaX = x - dragNode.x; //{71.1}
		var rotationFactor = -0.1; // Adjust this factor to control rotation sensitivity//{71.2}
		var newRotation = deltaX * rotationFactor; //{71.3}
		if (Math.abs(deltaX) < 5) {
			//{71.4}
			newRotation = 0; //{71.5}
			tween(dragNode, {
				rotation: newRotation
			}, {
				duration: 200,
				easing: tween.easeOut
			});
		} else {
			//{71.6}
			newRotation = Math.max(-0.1, Math.min(0.1, newRotation)); //{71.7}
			dragNode.rotation = newRotation;
		} //{71.8}
		dragNode.x = x;
		dragNode.y = y;
		puzzleManager.board.forEach(function (tile) {
			// When moving...
			// Check if above a tile...
			if (isPointInsideTile(x, y, tile)) {
				// Above a tile...
				if (!tile.isHighlighted) {
					tile.isHighlighted = true;
					if (typeof tile.previousZIndex === 'undefined') {
						tile.previousZIndex = boardContainer.getChildIndex(tile); // Store previous z-index
					}
					boardContainer.addChildAt(tile, boardContainer.children.length - 1); // Bring tile to the front
					tween(tile, {
						scaleX: 1.33,
						scaleY: 1.33
					}, {
						duration: 200,
						easing: tween.easeOut
					});
					// Play tick sound when a tile is highlighted
					LK.getSound('tick').play();
					currentHighlightedTile = tile; // Store the currently highlighted tile in a global variable
					if (currentAdjacentTiles && currentAdjacentTiles.length > 0 && currentAdjacentTiles[0].value != tile.value) {
						resetAdjacentTilesScale();
					}
					currentAdjacentTiles = puzzleManager.getAdjacentTiles(tile);
					currentAdjacentTiles.forEach(function (adjTile) {
						adjTile.isHighlighted = true;
						var dx = Math.abs(adjTile.col - tile.col);
						var dy = Math.abs(adjTile.row - tile.row);
						var normalizedDistance = Math.max(dx, dy);
						tween(adjTile, {
							scaleX: 1.33,
							scaleY: 1.33
						}, {
							duration: 200,
							easing: tween.easeOut,
							delay: normalizedDistance * 75 // Delay based on normalized distance
						});
					});
				}
			} else if (tile.isHighlighted && !currentAdjacentTiles.includes(tile)) {
				tile.isHighlighted = false;
				if (typeof tile.previousZIndex === 'undefined') {
					tile.previousZIndex = boardContainer.getChildIndex(tile); // Set previousZIndex if undefined
				}
				if (typeof tile.previousZIndex !== 'undefined') {
					boardContainer.addChildAt(tile, tile.previousZIndex); // Restore tile's original z-index
				}
				tween(tile, {
					scaleX: 1,
					scaleY: 1
				}, {
					duration: 200,
					easing: tween.easeOut
				});
				if (currentAdjacentTiles && currentAdjacentTiles.length > 0 && currentAdjacentTiles[0].value == tile.value) {
					resetAdjacentTilesScale();
				}
			}
		});
	}
	//log("Handling move event in PLAYING state");
}
function handlePlayingStateUp(x, y, obj) {
	// Implement logic for handling up event in PLAYING state
	log("Handling up event in PLAYING state");
	if (dragNode && !isAnimatingDragNode) {
		// Check if the operation button is above a tile
		var tileFound = false;
		log("Operation dropped at ", x, y);
		log("boardContainer at ", boardContainer.x, boardContainer.y);
		var operationApplied = false; // Flag to track if operation is applied
		puzzleManager.board.forEach(function (tile) {
			if (operationApplied) {
				return;
			} // Exit loop if operation is applied
			log("Checking tile at position:", tile.x, tile.y); // Log tile position
			if (isPointInsideTile(x, y, tile)) {
				isApplyingOperation = true;
				log("YES Operation button IS ABOVE tile at position:", tile.x, tile.y); // Log when operation button is above a tile
				var applied = puzzleManager.applyOperation(dragNode, tile);
				if (!applied) {
					log("Operation NOT applied. Cancel");
					// Exit from loop
					log("Restore canceled Operation...");
					isAnimatingDragNode = true;
					tween(dragNode, {
						x: dragNode.baseX,
						//rightOperationPreselectX,
						y: dragNode.baseY,
						//rightOperationPreselectY,
						rotation: dragNode.baseR || 0,
						//rightOperationPreselectR,
						scaleX: 1,
						scaleY: 1
					}, {
						duration: 500,
						easing: tween.easeOut,
						onFinish: function onFinish() {
							log("Delete drag node from Cancel operation...");
							dragNode = null;
							isAnimatingDragNode = false;
							isApplyingOperation = false;
						}
					});
					return;
				}
				operationApplied = true; // Set flag to true when operation is applied
				tileFound = true;
				if (typeof tile.previousZIndex !== 'undefined') {
					boardContainer.addChildAt(tile, tile.previousZIndex); // Restore tile's original z-index
				}
				tween(tile, {
					// Restore tile size after operation is applied
					scaleX: 1,
					scaleY: 1
				}, {
					duration: 200,
					easing: tween.easeOut
				}); //{4x.1}
				if (currentAdjacentTiles) {
					resetAdjacentTilesScale();
				}
				isAnimatingDragNode = true;
				tween(dragNode, {
					alpha: 0
				}, {
					duration: 500,
					easing: tween.easeOut,
					onFinish: function onFinish() {
						if (dragNode) {
							log("Destroy used Operation...");
							dragNode.destroy();
							log("Delete drag node from Up event end...");
							dragNode = null;
							isAnimatingDragNode = false;
							isApplyingOperation = false;
						}
					}
				});
				if (puzzleManager.currentLevel == 1 && gameHints.hasShowHint == 2) {
					LK.clearInterval(showHintsInterval);
					gameHints.removeHint();
				}
				// Exit from loop
				return;
			} else {
				log("Operation button is FAR FROM tile at position:", tile.x, tile.y); // Log when operation button is not above a tile
			}
		});
		if (!tileFound) {
			log("Operation button not above any tile");
			LK.getSound('operationCancel').play();
			isAnimatingDragNode = true;
			tween(dragNode, {
				x: dragNode.baseX,
				//rightOperationPreselectX,
				y: dragNode.baseY,
				//rightOperationPreselectY,
				rotation: dragNode.baseR || 0,
				//rightOperationPreselectR,
				scaleX: 1,
				scaleY: 1
			}, {
				duration: 500,
				easing: tween.easeOut,
				onFinish: function onFinish() {
					isAnimatingDragNode = false;
					log("Delete drag node from Up event tile not found...");
					dragNode = null;
				}
			});
			if (currentAdjacentTiles) {
				currentAdjacentTiles.forEach(function (adjTile) {
					adjTile.isHighlighted = false;
					tween(adjTile, {
						scaleX: 1,
						scaleY: 1
					}, {
						duration: 200,
						easing: tween.easeOut
					});
				});
				currentAdjacentTiles = []; // Clear the list after restoring scale
			}
		}
	} else {
		puzzleManager.board.forEach(function (tile) {
			tile.isHighlighted = false;
			if (typeof tile.previousZIndex === 'undefined') {
				tile.previousZIndex = boardContainer.getChildIndex(tile); // Set previousZIndex if undefined
			}
			tween(tile, {
				scaleX: 1,
				scaleY: 1
			}, {
				duration: 200,
				easing: tween.easeOut
			});
			if (currentAdjacentTiles && currentAdjacentTiles.length > 0 && currentAdjacentTiles[0].value == tile.value) {
				resetAdjacentTilesScale();
			}
			return;
		});
	}
}
// Score State Handlers
function handleScoreStateDown(x, y, obj) {
	// Implement logic for handling down event in SCORE state
	log("Handling down event in SCORE state");
	if (isOnLastScreen) {
		LK.showGameOver();
	}
}
function handleScoreStateMove(x, y, obj) {
	// Implement logic for handling move event in SCORE state
	//log("Handling move event in SCORE state");
}
function handleScoreStateUp(x, y, obj) {
	// Implement logic for handling up event in SCORE state
	log("Handling up event in SCORE state");
}
// Initialize PuzzleManager
//<Assets used in the game will automatically appear here>
//<Write imports for supported plugins here>
/***********************************************************************************************/ 
/****************************************** GLOBAL VARIABLES ***********************************/
/***********************************************************************************************/ 
var debug = false;
var resetProgress = false;
var isPlaying = false;
var GAME_STATE = {
	INIT: 'INIT',
	MENU: 'MENU',
	NEW_ROUND: 'NEW_ROUND',
	PLAYING: 'PLAYING',
	SCORE: 'SCORE'
};
var currentState = GAME_STATE.INIT;
var boardContainer;
var puzzleManager;
var menuBoard;
var startButton;
var backgroundLayer;
var middleLayer;
var foregroundLayer;
var backgroundImage;
var centerX = 1024;
var centerY = 1366;
var currentTransitionDirectionH = 1;
var currentTransitionDirectionV = 1;
var rightOperationPreselectX = centerX + 650;
var rightOperationPreselectY = 2500;
var rightOperationPreselectR = -0.15;
var levelNumberText;
var isApplyingOperation = false;
var isAnimatingDragNode = false;
var currentHighlightedTile;
var currentAdjacentTiles = []; // Initialize currentAdjacentTiles as a global variable
var showHintsInterval; // Declare showHintsInterval as a global variable
var gameHints; // Declare gameHints as a global variable
var dragNode = null;
var isMenuReady = false;
var isOnLastScreen = false;
var isPreviouslyWon = false;
var hasShowHint = false;
var resetButton; // Declare resetButton as a global variable
var menuButton; // Declare menuButton as a global variable
var tileColors = {
	0: 0xEAEEE8,
	// White / Gray
	1: 0x1E90FF,
	// Blue
	2: 0xF93827,
	// Red
	3: 0xFF9D23,
	// Yellow / Orange
	4: 0xFFD65A,
	// Yellow light
	5: 0x90ff1e,
	// Green
	6: 0xFF00FF,
	// Magenta
	7: 0x00FFFF,
	// Cyan
	8: 0xFFFF00,
	// Yellow
	9: 0xFF0000,
	// Red
	10: 0x9d23ff,
	// Red
	"default": 0xFFFFFF // Default color to prevent undefined errors
};
var operationsSlots = {
	0: {
		x: 180,
		y: 2280,
		r: 0.15
	},
	1: {
		x: 430,
		y: 2450,
		r: 0.15
	},
	2: {
		x: 680,
		y: 2600,
		r: 0.15
	},
	3: {
		x: 1380,
		y: 2600,
		r: -0.15
	},
	4: {
		x: 1630,
		y: 2450,
		r: -0.15
	},
	5: {
		x: 1880,
		y: 2280,
		r: -0.15
	}
};
var levelConfigs = {
	1: {
		"tiles": [["", 1, ""], ["", 1, 1], [1, 1, 1], ["", 1, 1], ["", 1, ""]],
		"operations": ['-1']
	},
	2: {
		"tiles": [["", 1, ""], ["", 1, 1], [2, 2, 2], ["", 1, 1], ["", 1, ""]],
		"operations": ['-1', '-1']
	},
	3: {
		"tiles": [["", "", "", "", "", ""], ["", 2, 2, 1, 2, 2], [2, 1, 1, 1, 1, 2], ["", 2, "", "", "", 2], [3, 2, 3, 3, 2, 3], ["", 2, 3, "", 3, 2], [2, 3, 3, 3, 3, 2], ["", 2, 2, 3, 2, 2]],
		"operations": ["-1", "-2", "+1", "+1"]
	},
	4: {
		"tiles": [["", "", 2, 2, 2, ""], ["", "", 2, 1, 1, 2], ["", 2, 1, 2, 1, 2], ["", "", 2, 1, 1, 2], ["", "", 2, 2, 2, ""], ["", "", "", "", "", ""], ["", "", 2, 2, "", ""], ["", "", 2, 1, 2, ""], [1, 1, 2, 2, "", ""]],
		"operations": ["-1", "-1", "-1", "-1", "+1"]
	},
	5: {
		"tiles": [["", "", 3, 3, "", ""], ["", "", 3, 2, 3, ""], ["", 3, 2, 2, 3, ""], ["", 3, 2, 2, 2, 3], [3, 2, 2, 2, 2, 3], ["", "", "", 3, "", ""], ["", "", 3, 3, "", ""], ["", 1, 1, 1, 1, 1], ["", 1, 1, 1, 1, ""]],
		"operations": ["-2", "-1", "+1"]
	},
	6: {
		"tiles": [["", "", 1, "", ""], ["", "", 1, 1, ""], ["", 2, 2, 2, ""], ["", 2, 2, 2, 2], [3, 3, 3, 3, 3], ["", 2, 2, 2, 2], ["", 2, 2, 2, ""], ["", "", 1, 1, ""], ["", "", 1, "", ""]],
		"operations": ['-2', '-1', '+1', '+1']
	},
	7: {
		"tiles": [[2, "", "", "", "", 1], ["", 2, "", "", "", 3], [2, "", 2, 3, "", 3], ["", 2, 2, "", 3, 3], ["", 2, "", "", 3, ""], ["", "", 1, "", 1, ""], ["", "", 1, 1, "", ""], ["", "", "", 1, "", ""], ["", "", "", "", "", ""]],
		"operations": ["-2", "-1", "+1"]
	},
	8: {
		"tiles": [["", 3, 1, 2, 1, "", ""], ["", 3, 1, 2, 1, "", ""], [3, 1, 2, 1, "", "", ""], ["", "", "", "", 1, 1, ""], [3, 3, 3, 1, 1, 1, 1], ["", 3, 3, 1, 1, 2, ""], ["", 3, 1, 1, 2, 2, ""], ["", "", 1, 1, 2, 2, ""], ["", "", 1, 2, 2, "", ""]],
		"operations": ["-2", "-1", "-1", "-1", "+2"]
	},
	9: {
		"tiles": [["", "", "", "", "", "", ""], ["", 1, 3, 3, 3, 3, 1], [1, 1, 3, 3, 3, 1, 1], ["", 3, 3, 3, 3, 3, 3], [3, 2, 3, 2, 3, 2, 3], ["", 3, 3, 3, 3, 3, 3], [1, 1, 3, 3, 3, 1, 1], ["", 1, 3, 3, 3, 3, 1], ["", "", "", "", "", "", ""]],
		"operations": ["-2", "-2", "+1"]
	},
	10: {
		"tiles": [[1, 2, 1, 1, 1, 1, 1], ["", 3, 3, 3, 3, 2, 1], [1, 2, 1, 1, 1, 1, 1], ["", 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1], ["", 1, 1, 1, 2, 2, 1], [1, 2, 3, 3, 2, 1, 1], ["", 1, 1, 1, 2, 2, 1], [1, 3, 3, 1, 3, 3, 3], ["", 1, 3, 1, 3, 2, 3], [1, 1, 1, 3, 3, 3, 1]],
		"operations": ["-2", "-2", "+1", "+2"]
	},
	11: {
		"tiles": [[3, 3, 2, 3, 3, 4, 3], ["", 3, 2, 3, 3, 3, 3], [3, 2, 3, 3, 3, 4, 3], ["", 3, 2, 3, 3, 3, 3], [3, 2, 2, 2, 1, 2, 2], ["", 3, 2, 3, 3, 3, 3], [3, 2, 3, 3, 3, 4, 3], ["", 3, 2, 3, 3, 3, 3], [3, 3, 2, 3, 3, 4, 3]],
		"operations": ["-2", "-1", "-1", "-1", "+2", "+2"]
	},
	12: {
		"tiles": [["", 2, 2, 2, 2, 2, ""], ["", 2, 1, 1, 1, 1, 2], [2, 1, 3, 3, 3, 1, 2], ["", 1, 3, 2, 2, 3, 1], [2, 1, 3, 1, 3, 1, 2], ["", 1, 3, 2, 2, 3, 1], [2, 1, 3, 3, 3, 1, 2], ["", 2, 1, 1, 1, 1, 2], ["", 2, 2, 2, 2, 2, ""]],
		"operations": ["-1", "-1", "-1", "+1"]
	},
	13: {
		"tiles": [["", "", 3, 3, "", "", ""], ["", "", 3, 4, 3, "", ""], ["", "", 3, 3, "", "", ""], ["", "", "", "", 2, 2, ""], ["", "", "", 2, 3, 2, ""], ["", "", "", "", 2, 2, ""], ["", "", 1, 1, "", "", ""], ["", "", 1, 2, 1, "", ""], ["", "", 1, 1, "", "", ""]],
		"operations": ["-2", "-2", "-1", "-1", "+1"]
	},
	14: {
		"tiles": [[1, 1, 4, 4, 1, 1, 1], ["", 1, 4, 4, 1, 3, 1], [1, 4, 4, 1, 3, 1, 2], ["", 4, 4, 1, 3, 1, 2], [4, 4, 1, 3, 1, 2, 1], ["", 4, 4, 1, 3, 1, 2], [1, 4, 4, 1, 3, 1, 2], ["", 1, 4, 4, 1, 3, 1], [1, 1, 4, 4, 1, 1, 1]],
		"operations": ["-2", "-1", "-1", "-1", "+1"]
	},
	15: {
		"tiles": [["", "", 1, 2, 1, "", ""], ["", "", 1, 2, 2, 1, ""], ["", 1, 2, 2, 2, 1, ""], ["", 1, 2, 2, 2, 2, 1], [1, 1, 1, 1, 1, 1, 1], ["", "", 2, 3, 3, 2, ""], ["", 2, 2, 3, 2, 2, ""], ["", 4, 4, 4, 4, 4, 4], ["", "", "", "", "", "", ""]],
		"operations": ["-2", "-1", "-1", "+2"]
	},
	16: {
		"tiles": [[1, 2, 1, 1, 1, 2, 1], ["", 1, 2, 1, 1, 2, 1], [1, 2, 4, 4, 4, 2, 1], ["", 1, 4, 4, 4, 4, 1], [3, 2, 4, 4, 4, 2, 3], ["", 1, 4, 4, 4, 4, 1], [1, 1, 2, 4, 2, 1, 1], ["", 1, 2, 1, 1, 2, 1], [1, 2, 1, 1, 1, 2, 1]],
		"operations": ["-2", "-2", "-1", "+1"]
	},
	17: {
		"tiles": [["", 3, 3, 3, 3, 3, ""], ["", 3, 3, 3, 3, 3, 3], ["", "", 4, "", "", "", ""], ["", 3, 3, 3, 3, 3, 3], [3, 3, 3, 3, 3, 3, 3], ["", "", "", "", "", 2, ""], [3, 3, 3, 3, 3, 3, 3], ["", 3, 3, 3, 3, 3, 3], ["", 1, "", "", "", "", ""]],
		"operations": ["-2", "-1", "-1", "+1"]
	},
	18: {
		"tiles": [[2, 1, 1, 1, 1, 1, 2], ["", 2, 1, 1, 1, 1, 2], ["", 2, "", 1, "", 2, ""], ["", 2, 3, "", "", 3, 2], [2, 3, 4, 1, 4, 3, 2], ["", 2, 3, 1, 1, 3, 2], [2, 3, 4, 1, 4, 3, 2], ["", 2, 3, 1, 1, 3, 2], [2, 3, 4, 1, 4, 3, 2], ["", 2, 3, "", "", 3, 2], ["", 2, 3, 1, 3, 2, ""]],
		"operations": ["-2", "-1", "-1", "+1", "+2"]
	},
	19: {
		"tiles": [["", 1, "", "", "", 1, ""], ["", 1, 1, "", "", 1, 1], [1, 1, 1, "", 1, 1, 1], ["", 4, 4, 4, 4, 4, 4], [4, 2, 2, 2, 2, 2, 4], ["", 2, 4, 4, 4, 4, 2], [4, 2, 2, 2, 2, 2, 4], ["", 4, 4, 4, 4, 4, 4], [1, 1, 1, "", 1, 1, 1], ["", 1, 1, "", "", 1, 1], ["", 1, "", "", "", 1, ""]],
		"operations": ["-3", "-1", "+2"]
	},
	20: {
		"tiles": [["", "", "", 1, 2, 3, 1], ["", "", 1, 1, 2, 3, 1], [1, 1, 2, 2, 3, 1, 2], ["", 2, 2, 3, 3, 1, 2], [3, 3, 3, 1, 1, 2, 2], ["", 1, 1, 1, 2, 2, 2], [2, 2, 2, 2, 2, 2, 3], ["", 2, 2, 2, 2, 3, 3], [3, 3, 3, 3, 3, 2, 2], ["", 2, 2, 2, 2, 2, 1], [1, 1, 1, 1, 1, 1, ""]],
		"operations": ["-1", "-1", "-1", "-1", "+2"]
	},
	21: {
		"tiles": [["", "", "", "", "", "", ""], ["", "", 1, 1, 2, 2, 3], ["", 1, 1, 2, 2, 3, 3], ["", 1, 1, 2, 2, 3, 3], ["", "", 2, "", "", 3, ""], ["", "", "", 2, "", "", ""], ["", 3, "", 2, "", "", ""], ["", 3, 3, 2, 2, 1, 1], [3, 3, 2, 2, 1, 1, ""], ["", 3, 2, 2, 1, 1, ""], ["", "", "", "", "", "", ""]],
		"operations": ["-3", "-1", "+2"]
	},
	22: {
		"tiles": [["", "", "", "", "", "", ""], ["", 4, "", 4, "", 4, ""], ["", 4, 4, 4, 4, "", ""], ["", 1, 4, 1, 4, 1, ""], ["", 1, 1, 1, 1, 2, ""], ["", 2, 1, 2, 1, 2, 1], [2, "", 2, "", 2, "", 2], ["", 3, 1, 3, 1, 3, 1], ["", 3, 3, 3, 3, 3, 3], ["", "", 3, "", 3, "", 3], ["", "", "", "", "", "", ""]],
		"operations": ["-2", "-2", "-1", "-1", "+1"]
	},
	23: {
		"tiles": [["", "", "", "", "", "", ""], ["", "", "", 4, 4, "", ""], ["", "", 4, "", 4, "", ""], ["", "", 4, 2, 1, 4, ""], ["", 4, "", 3, "", 4, ""], ["", 4, 2, "", "", 3, 4], [4, "", 2, "", 3, "", 4], ["", 4, "", 1, 1, "", 4], ["", 4, 1, "", 1, 4, ""], ["", "", 4, 4, 4, 4, ""], ["", "", "", "", "", "", ""]],
		"operations": ["-2", "-1", "-1", "+1", "+1", "+1"]
	},
	24: {
		"tiles": [["", "", "", "", 2, "", 1], ["", "", 2, "", 2, 1, 1], ["", 2, "", 1, 1, "", ""], ["", "", 2, 1, "", 2, ""], [1, 1, 2, "", 2, 3, 3], ["", "", 2, "", 3, 3, ""], ["", "", 2, 3, "", 2, ""], ["", 3, 3, 2, "", 2, 3], ["", "", "", 2, 3, 3, 3], ["", "", "", 3, 2, "", 2], ["", 3, 3, "", 2, "", 2]],
		"operations": ["-2", "-1", "-1", "+1", "+1"]
	},
	25: {
		"tiles": [["", "", "", "", "", "", ""], ["", 4, 4, 4, 2, 1, 2], [4, 4, 4, 2, 2, 2, ""], ["", 2, 4, 2, 2, 2, ""], ["", 2, 4, 2, 2, "", ""], ["", "", 2, 2, "", "", ""], ["", "", "", 4, 3, 3, ""], ["", 1, 1, 3, 3, 1, 3], [1, 1, 3, 3, 3, 1, 3], ["", 1, 3, 3, 3, 1, 1], ["", 3, 1, 3, 1, 1, ""]],
		"operations": ["-2", "-1", "-1", "-1", "+1"]
	},
	26: {
		"tiles": [["", "", "", 1, 1, 1, ""], ["", "", "", "", "", 1, ""], ["", "", "", "", 4, 1, 1], ["", "", 3, 3, 3, "", 1], ["", "", "", 3, "", "", ""], ["", "", "", 4, 3, 3, ""], [2, 2, 2, "", 3, "", ""], ["", "", 2, "", "", "", ""], ["", 4, 2, 2, "", "", ""], ["", "", "", 2, "", "", ""], ["", "", 2, "", "", "", ""]],
		"operations": ["-2", "-1", "-1", "+1", "+2"]
	},
	27: {
		"tiles": [["", "", "", "", "", "", ""], ["", "", "", 1, 1, 3, ""], ["", "", 1, 1, 3, 3, ""], ["", "", 1, 1, 3, 3, 3], ["", 2, 2, 2, 3, 3, 1], ["", 2, 2, 2, 4, 3, 1], [2, 2, 2, 4, 4, 1, ""], ["", "", 1, 3, 3, 1, ""], ["", "", 1, 3, 1, "", ""], ["", "", "", 1, 1, "", ""], ["", "", "", 1, "", "", ""]],
		"operations": ["-2", "-1", "-1", "+2"]
	},
	28: {
		"tiles": [["", 2, 2, 2, 2, 2, ""], ["", 2, 3, 4, 4, 3, 2], [2, 2, 2, 2, 2, 2, 2], ["", 2, 3, 1, 1, 3, 2], [2, 2, 2, 2, 2, 2, 2], ["", 2, 3, 1, 1, 3, 2], [2, 2, 2, 2, 2, 2, 2], ["", 2, 3, 4, 4, 3, 2], [2, 2, 2, 2, 2, 2, 2], ["", 2, 2, 2, 2, 2, 2], ["", "", "", "", "", "", ""]],
		"operations": ["-2", "-1", "-1", "+2"]
	},
	29: {
		"tiles": [["", 3, 4, "", 3, 3, ""], ["", 1, 3, 4, "", 3, 2], [1, 1, 4, "", 3, 2, 2], ["", 1, 3, 4, "", 3, 2], [3, 3, 4, "", 3, 3, 3], ["", 3, 3, 4, 3, 3, 3], [3, 3, 4, "", 3, 3, 3], ["", 2, 3, 4, "", 3, 1], [2, 2, 3, "", 3, 1, 1], ["", 2, 3, 4, "", 3, 1], ["", 3, 4, "", 3, 3, ""]],
		"operations": ["-3", "-1", "-1", "-1", "-1"]
	},
	30: {
		"tiles": [["", "", "", 4, "", "", ""], ["", 3, 3, 4, 4, 3, 3], [1, 3, 4, 4, 4, 3, 1], ["", 1, 3, 4, 4, 3, 1], [1, 3, 4, 1, 4, 3, 1], ["", 4, 4, 1, 1, 4, 4], [4, 4, 1, 4, 1, 4, 4], ["", 1, 3, 4, 4, 2, 1], [1, 3, 2, 4, 3, 2, 1], ["", 1, 3, 2, 3, 2, 1], ["", 1, 3, 1, 2, 1, ""]],
		"operations": ["-2", "-1", "-1", "+1", "ร2"]
	}
};
/***********************************************************************************************/ 
/***************************************** GAME INITIALISATION *********************************/
/***********************************************************************************************/ 
function initializeGame() {
	backgroundLayer = new Container();
	middleLayer = new Container();
	foregroundLayer = new Container();
	backgroundImage = new BackgroundImage();
	backgroundLayer.addChild(backgroundImage);
	game.addChild(backgroundLayer);
	game.addChild(middleLayer);
	game.addChild(foregroundLayer);
	backgroundImage.showWall();
	boardContainer = new Container();
	middleLayer.addChild(boardContainer);
	boardContainer.x = 0;
	boardContainer.y = 0;
	puzzleManager = new PuzzleManager(game);
	if (debug && resetProgress) {
		puzzleManager.maxReachedLevelNumber = 1;
	}
	isPreviouslyWon = puzzleManager.maxReachedLevelNumber >= 30;
	startButton = new StartButton();
	startButton.x = centerX; // Center horizontally
	startButton.y = centerY; // Center vertically
	startButton.visible = true;
	game.addChild(startButton);
	resetButton = new ResetButton();
	resetButton.x = game.width - 150; // Position at top right
	resetButton.y = 130;
	resetButton.visible = false; // Keep it non-visible initially
	// Initialize levelNumberText using LevelNumberText class
	levelNumberText = new LevelNumberText(puzzleManager.currentLevel);
	backgroundLayer.addChild(levelNumberText);
	foregroundLayer.addChild(resetButton);
	menuButton = new MenuButton();
	menuButton.x = 350; // Position at top left
	menuButton.y = 130;
	menuButton.visible = true; // Make it visible initially
	foregroundLayer.addChild(menuButton);
	menuBoard = new MenuBoard();
	middleLayer.addChild(menuBoard);
	gameHints = new GameHints(); // Instantiate GameHints
	foregroundLayer.addChild(gameHints); // Add gameHints to the foreground layer
}
initializeGame(); ===================================================================
--- original.js
+++ change.js
@@ -147,9 +147,9 @@
 		anchorX: 0.5,
 		anchorY: 0.5
 	});
 	// Set initial properties
-	self.speed = Math.random() * 5 + 2; // Random speed between 2 and 7
+	self.speed = Math.random() * 5 + 4; // Random speed between 2 and 7
 	self.rotationSpeed = Math.random() * 0.1 - 0.05; // Random rotation speed
 	lineGraphics.tint = Math.random() * 0xFFFFFF; // Random tint color
 	self.update = function () {
 		// Update position and rotation
tick
Sound effect
tileEntrance
Sound effect
tileRemove
Sound effect
operationSelect
Sound effect
operationCancel
Sound effect
tileChangeValue
Sound effect
resetSound
Sound effect
levelFailed
Sound effect
menuLevelSelect
Sound effect
menuCellEnter
Sound effect
applause
Sound effect
bgMusic
Music
tada
Sound effect