User prompt
make it 4x4, insider squares will be 2x2
User prompt
4x4 ölç
User prompt
when filled cell clicked do not take any action
User prompt
title and timer are overlapped place them side to side
User prompt
when correct unicorn selected, place it to the cell and remove from the possible options
User prompt
when i selected a empty cell, just show possible unicorns
User prompt
show selectable unicorns at the bottom of sudoku table with some margin
Code edit (1 edits merged)
Please save this source code
User prompt
when empty cell selected, options are not shown fully. please give a space top of the selectable unicorns
User prompt
i just can see purple squares instead of uniorn images
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'x')' in or related to this line: 'var global = boardContainer.toGlobal(cell.position);' Line Number: 392
User prompt
Please fix the bug: 'Uncaught TypeError: cell.setSelected is not a function' in or related to this line: 'cell.setSelected(true);' Line Number: 384
Code edit (1 edits merged)
Please save this source code
User prompt
Unicorn Sudoku
Initial prompt
create a sudoku game but use unicorn character icons instead of numbers
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// UnicornCell: Represents a single cell in the Sudoku grid
var UnicornCell = Container.expand(function () {
var self = Container.call(this);
// Cell background (for selection/highlight)
var bg = self.attachAsset('cellBg', {
width: cellSize - 8,
height: cellSize - 8,
color: 0xffffff,
shape: 'box',
anchorX: 0.5,
anchorY: 0.5
});
self.bg = bg;
// The unicorn icon (if any)
self.icon = null;
self.unicornIndex = null; // 0-8, or null if empty
// Row, col for logic
self.row = 0;
self.col = 0;
// Is this a given (pre-filled) cell?
self.isGiven = false;
// Show error highlight
self.showError = function (on) {
if (on) {
tween(self.bg, {
color: 0xffaaaa
}, {
duration: 200,
easing: tween.easeIn
});
} else {
tween(self.bg, {
color: 0xffffff
}, {
duration: 200,
easing: tween.easeOut
});
}
};
// Set unicorn icon
self.setUnicorn = function (idx, animate) {
if (self.icon) {
self.removeChild(self.icon);
self.icon = null;
}
self.unicornIndex = idx;
if (idx !== null) {
var icon = self.attachAsset('unicorn' + idx, {
width: cellSize * 0.7,
height: cellSize * 0.7,
anchorX: 0.5,
anchorY: 0.5
});
self.icon = icon;
if (animate) {
icon.scaleX = 0.2;
icon.scaleY = 0.2;
tween(icon, {
scaleX: 1,
scaleY: 1
}, {
duration: 180,
easing: tween.bounceOut
});
}
}
};
// Remove unicorn icon
self.clearUnicorn = function () {
if (self.icon) {
self.removeChild(self.icon);
self.icon = null;
}
self.unicornIndex = null;
};
// Selection highlight
self.setSelected = function (on) {
if (on) {
tween(self.bg, {
color: 0xcce6ff
}, {
duration: 120
});
} else {
tween(self.bg, {
color: 0xffffff
}, {
duration: 120
});
}
};
return self;
});
// UnicornPicker: The row of unicorn icons for selection
var UnicornPicker = Container.expand(function () {
var self = Container.call(this);
self.icons = [];
self.visible = false;
self.selectedIdx = null;
// Create 9 unicorn icons
for (var i = 0; i < 9; i++) {
var icon = self.attachAsset('unicorn' + i, {
width: pickerIconSize,
height: pickerIconSize,
anchorX: 0.5,
anchorY: 0.5,
x: i * (pickerIconSize + pickerGap),
y: 0
});
icon.idx = i;
self.icons.push(icon);
}
// Background
var pickerBg = self.attachAsset('pickerBg', {
width: 9 * pickerIconSize + 8 * pickerGap + 32,
height: pickerIconSize + 32,
color: 0xf7e6ff,
shape: 'box',
anchorX: 0,
anchorY: 0
});
pickerBg.x = -16;
pickerBg.y = -16;
self.setChildIndex(pickerBg, 0);
// Highlight selected
self.setSelected = function (idx) {
for (var i = 0; i < self.icons.length; i++) {
self.icons[i].alpha = i === idx ? 1 : 0.7;
self.icons[i].scaleX = self.icons[i].scaleY = i === idx ? 1.15 : 1;
}
self.selectedIdx = idx;
};
// Show/hide
self.show = function (x, y) {
self.x = x;
self.y = y;
self.visible = true;
};
self.hide = function () {
self.visible = false;
};
return self;
});
/****
* Initialize Game
****/
/****
* Game Constants
****/
// Board layout
// --- Game Initialization ---
var game = new LK.Game({
backgroundColor: 0xf7e6ff
});
/****
* Game Code
****/
// Board layout
/****
* Game Constants
****/
// --- Game State ---
var gridSize = 9;
var cellSize = 180; // 9*180 = 1620, fits well in 2048 width
var boardSize = cellSize * gridSize;
var boardOffsetX = (2048 - boardSize) / 2;
var boardOffsetY = 220;
// Picker
var pickerIconSize = 120;
var pickerGap = 18;
// For error highlight
var errorFlashDuration = 400;
// --- Asset Initialization ---
// 9 unicorn icons
for (var i = 0; i < 9; i++) {}
// Cell background
// Picker background
var board = []; // 2D array of UnicornCell
var givenBoard = []; // 2D array of unicorn indices (0-8) or null
var solutionBoard = []; // 2D array of unicorn indices (0-8)
var selectedCell = null;
var picker = null;
var timerTxt = null;
var startTime = null;
var timerInterval = null;
var errorCells = [];
var completed = false;
// --- Sudoku Puzzle Generation ---
// For MVP, use a static puzzle and solution (easy level)
var staticPuzzle = [[null, null, 2, null, 3, null, 7, null, null], [6, null, null, 1, 9, 5, null, null, null], [null, 9, 8, null, null, null, null, 6, null], [8, null, null, null, 6, null, null, null, 3], [4, null, null, 8, null, 3, null, null, 1], [7, null, null, null, 2, null, null, null, 6], [null, 6, null, null, null, null, 2, 8, null], [null, null, null, 4, 1, 9, null, null, 5], [null, null, 5, null, 8, null, null, 7, 9]];
// Solution for the above puzzle (0-8 for unicorn indices)
var staticSolution = [[0, 1, 2, 6, 3, 8, 7, 5, 4], [6, 7, 4, 1, 9, 5, 8, 2, 3], [5, 9, 8, 7, 4, 2, 1, 6, 0], [8, 5, 1, 2, 6, 7, 4, 0, 3], [4, 2, 6, 8, 5, 3, 9, 7, 1], [7, 3, 9, 5, 2, 4, 0, 8, 6], [1, 6, 3, 9, 7, 0, 5, 4, 2], [2, 8, 7, 4, 1, 9, 6, 3, 5], [9, 4, 5, 3, 8, 6, 2, 1, 7]];
// --- Helper Functions ---
// Returns true if placing unicornIdx at (row, col) is valid
function isValidMove(row, col, unicornIdx) {
// Check row
for (var c = 0; c < gridSize; c++) {
if (c !== col && board[row][c].unicornIndex === unicornIdx) return false;
}
// Check col
for (var r = 0; r < gridSize; r++) {
if (r !== row && board[r][col].unicornIndex === unicornIdx) return false;
}
// Check 3x3 box
var boxRow = Math.floor(row / 3) * 3;
var boxCol = Math.floor(col / 3) * 3;
for (var r = boxRow; r < boxRow + 3; r++) {
for (var c = boxCol; c < boxCol + 3; c++) {
if ((r !== row || c !== col) && board[r][c].unicornIndex === unicornIdx) return false;
}
}
return true;
}
// Returns true if the board is completely and correctly filled
function isBoardComplete() {
for (var r = 0; r < gridSize; r++) {
for (var c = 0; c < gridSize; c++) {
var cell = board[r][c];
if (cell.unicornIndex === null) return false;
if (!isValidMove(r, c, cell.unicornIndex)) return false;
}
}
return true;
}
// Highlight errors for current board state
function highlightErrors() {
// Clear previous
for (var i = 0; i < errorCells.length; i++) {
errorCells[i].showError(false);
}
errorCells = [];
// Check for errors
for (var r = 0; r < gridSize; r++) {
for (var c = 0; c < gridSize; c++) {
var cell = board[r][c];
if (cell.unicornIndex === null) continue;
// Only highlight if not a given
if (!cell.isGiven && !isValidMove(r, c, cell.unicornIndex)) {
cell.showError(true);
errorCells.push(cell);
}
}
}
}
// Deselect all cells
function deselectAllCells() {
for (var r = 0; r < gridSize; r++) {
for (var c = 0; c < gridSize; c++) {
board[r][c].setSelected(false);
}
}
selectedCell = null;
}
// --- UI Setup ---
// Board container
var boardContainer = new Container();
boardContainer.x = boardOffsetX;
boardContainer.y = boardOffsetY;
game.addChild(boardContainer);
// Draw grid lines (thick for boxes, thin for cells)
for (var i = 0; i <= gridSize; i++) {
// Vertical
var lineW = i % 3 === 0 ? 8 : 3;
var lineColor = i % 3 === 0 ? 0x9b59b6 : 0xd1b3e0;
var vLine = LK.getAsset('vLine' + i, {
width: lineW,
height: boardSize,
color: lineColor,
shape: 'box',
anchorX: 0.5,
anchorY: 0
});
vLine.x = i * cellSize;
vLine.y = 0;
boardContainer.addChild(vLine);
// Horizontal
var hLine = LK.getAsset('hLine' + i, {
width: boardSize,
height: lineW,
color: lineColor,
shape: 'box',
anchorX: 0,
anchorY: 0.5
});
hLine.x = 0;
hLine.y = i * cellSize;
boardContainer.addChild(hLine);
}
// Create cells
for (var r = 0; r < gridSize; r++) {
board[r] = [];
for (var c = 0; c < gridSize; c++) {
var cell = new UnicornCell();
cell.x = c * cellSize + cellSize / 2;
cell.y = r * cellSize + cellSize / 2;
cell.row = r;
cell.col = c;
boardContainer.addChild(cell);
board[r][c] = cell;
}
}
// Fill in given cells and solution
for (var r = 0; r < gridSize; r++) {
givenBoard[r] = [];
solutionBoard[r] = [];
for (var c = 0; c < gridSize; c++) {
var idx = staticPuzzle[r][c];
var cell = board[r][c];
if (idx !== null) {
cell.setUnicorn(idx, false);
cell.isGiven = true;
cell.bg.alpha = 0.7;
}
givenBoard[r][c] = idx;
solutionBoard[r][c] = staticSolution[r][c];
}
}
// --- Picker UI ---
picker = new UnicornPicker();
picker.visible = false;
game.addChild(picker);
// --- Timer UI ---
timerTxt = new Text2('00:00', {
size: 90,
fill: 0x7D3C98
});
timerTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(timerTxt);
// --- Title UI ---
var titleTxt = new Text2('Unicorn Sudoku', {
size: 110,
fill: 0xA569BD
});
titleTxt.anchor.set(0.5, 0);
titleTxt.y = 10;
LK.gui.top.addChild(titleTxt);
// --- Instructions UI ---
var instrTxt = new Text2('Tap a cell, then pick a unicorn to fill it!', {
size: 60,
fill: 0x7D3C98
});
instrTxt.anchor.set(0.5, 0);
instrTxt.y = 120;
LK.gui.top.addChild(instrTxt);
// --- Event Handlers ---
// Cell tap: select cell and show picker
function onCellDown(x, y, obj) {
if (completed) return;
var cell = obj;
if (cell.isGiven) return;
deselectAllCells();
cell.setSelected(true);
selectedCell = cell;
// Show picker below the cell, but keep inside screen
var global = boardContainer.toGlobal(cell.position);
var pickerX = Math.max(40, Math.min(global.x - pickerIconSize * 4, 2048 - pickerIconSize * 9 - 40));
var pickerY = Math.min(global.y + cellSize / 2 + 30, 2732 - pickerIconSize - 80);
picker.show(pickerX, pickerY);
picker.setSelected(null);
}
// Picker tap: set unicorn in selected cell
function onPickerDown(x, y, obj) {
if (!selectedCell || completed) return;
var idx = obj.idx;
if (idx === undefined) return;
// If already has this unicorn, clear
if (selectedCell.unicornIndex === idx) {
selectedCell.clearUnicorn();
picker.setSelected(null);
} else {
selectedCell.setUnicorn(idx, true);
picker.setSelected(idx);
}
highlightErrors();
// Check for win
if (isBoardComplete()) {
completed = true;
picker.hide();
deselectAllCells();
LK.effects.flashScreen(0x7d3c98, 800);
LK.setTimeout(function () {
LK.showYouWin();
}, 900);
}
}
// Hide picker if tap outside
function onGameDown(x, y, obj) {
// If tap is not on a cell or picker, hide picker and deselect
if (obj && (obj instanceof UnicornCell || obj === picker || picker.icons.indexOf(obj) !== -1)) return;
picker.hide();
deselectAllCells();
}
// --- Attach event handlers ---
// Attach to each cell
for (var r = 0; r < gridSize; r++) {
for (var c = 0; c < gridSize; c++) {
var cell = board[r][c];
cell.down = onCellDown;
}
}
// Attach to picker icons
for (var i = 0; i < picker.icons.length; i++) {
picker.icons[i].down = onPickerDown;
}
// Attach to game for outside tap
game.down = onGameDown;
// --- Timer Logic ---
function formatTime(secs) {
var m = Math.floor(secs / 60);
var s = secs % 60;
return (m < 10 ? '0' : '') + m + ':' + (s < 10 ? '0' : '') + s;
}
function updateTimer() {
if (completed) return;
var now = Date.now();
var elapsed = Math.floor((now - startTime) / 1000);
timerTxt.setText(formatTime(elapsed));
}
// --- Game Start ---
function startGame() {
completed = false;
deselectAllCells();
picker.hide();
highlightErrors();
startTime = Date.now();
timerTxt.setText('00:00');
if (timerInterval) LK.clearInterval(timerInterval);
timerInterval = LK.setInterval(updateTimer, 1000);
}
startGame();
// --- Game Update (not used for logic, but required) ---
game.update = function () {
// No per-frame logic needed for MVP
}; ===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,444 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+
+/****
+* Classes
+****/
+// UnicornCell: Represents a single cell in the Sudoku grid
+var UnicornCell = Container.expand(function () {
+ var self = Container.call(this);
+ // Cell background (for selection/highlight)
+ var bg = self.attachAsset('cellBg', {
+ width: cellSize - 8,
+ height: cellSize - 8,
+ color: 0xffffff,
+ shape: 'box',
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.bg = bg;
+ // The unicorn icon (if any)
+ self.icon = null;
+ self.unicornIndex = null; // 0-8, or null if empty
+ // Row, col for logic
+ self.row = 0;
+ self.col = 0;
+ // Is this a given (pre-filled) cell?
+ self.isGiven = false;
+ // Show error highlight
+ self.showError = function (on) {
+ if (on) {
+ tween(self.bg, {
+ color: 0xffaaaa
+ }, {
+ duration: 200,
+ easing: tween.easeIn
+ });
+ } else {
+ tween(self.bg, {
+ color: 0xffffff
+ }, {
+ duration: 200,
+ easing: tween.easeOut
+ });
+ }
+ };
+ // Set unicorn icon
+ self.setUnicorn = function (idx, animate) {
+ if (self.icon) {
+ self.removeChild(self.icon);
+ self.icon = null;
+ }
+ self.unicornIndex = idx;
+ if (idx !== null) {
+ var icon = self.attachAsset('unicorn' + idx, {
+ width: cellSize * 0.7,
+ height: cellSize * 0.7,
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.icon = icon;
+ if (animate) {
+ icon.scaleX = 0.2;
+ icon.scaleY = 0.2;
+ tween(icon, {
+ scaleX: 1,
+ scaleY: 1
+ }, {
+ duration: 180,
+ easing: tween.bounceOut
+ });
+ }
+ }
+ };
+ // Remove unicorn icon
+ self.clearUnicorn = function () {
+ if (self.icon) {
+ self.removeChild(self.icon);
+ self.icon = null;
+ }
+ self.unicornIndex = null;
+ };
+ // Selection highlight
+ self.setSelected = function (on) {
+ if (on) {
+ tween(self.bg, {
+ color: 0xcce6ff
+ }, {
+ duration: 120
+ });
+ } else {
+ tween(self.bg, {
+ color: 0xffffff
+ }, {
+ duration: 120
+ });
+ }
+ };
+ return self;
+});
+// UnicornPicker: The row of unicorn icons for selection
+var UnicornPicker = Container.expand(function () {
+ var self = Container.call(this);
+ self.icons = [];
+ self.visible = false;
+ self.selectedIdx = null;
+ // Create 9 unicorn icons
+ for (var i = 0; i < 9; i++) {
+ var icon = self.attachAsset('unicorn' + i, {
+ width: pickerIconSize,
+ height: pickerIconSize,
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: i * (pickerIconSize + pickerGap),
+ y: 0
+ });
+ icon.idx = i;
+ self.icons.push(icon);
+ }
+ // Background
+ var pickerBg = self.attachAsset('pickerBg', {
+ width: 9 * pickerIconSize + 8 * pickerGap + 32,
+ height: pickerIconSize + 32,
+ color: 0xf7e6ff,
+ shape: 'box',
+ anchorX: 0,
+ anchorY: 0
+ });
+ pickerBg.x = -16;
+ pickerBg.y = -16;
+ self.setChildIndex(pickerBg, 0);
+ // Highlight selected
+ self.setSelected = function (idx) {
+ for (var i = 0; i < self.icons.length; i++) {
+ self.icons[i].alpha = i === idx ? 1 : 0.7;
+ self.icons[i].scaleX = self.icons[i].scaleY = i === idx ? 1.15 : 1;
+ }
+ self.selectedIdx = idx;
+ };
+ // Show/hide
+ self.show = function (x, y) {
+ self.x = x;
+ self.y = y;
+ self.visible = true;
+ };
+ self.hide = function () {
+ self.visible = false;
+ };
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
+/****
+* Game Constants
+****/
+// Board layout
+// --- Game Initialization ---
var game = new LK.Game({
- backgroundColor: 0x000000
-});
\ No newline at end of file
+ backgroundColor: 0xf7e6ff
+});
+
+/****
+* Game Code
+****/
+// Board layout
+/****
+* Game Constants
+****/
+// --- Game State ---
+var gridSize = 9;
+var cellSize = 180; // 9*180 = 1620, fits well in 2048 width
+var boardSize = cellSize * gridSize;
+var boardOffsetX = (2048 - boardSize) / 2;
+var boardOffsetY = 220;
+// Picker
+var pickerIconSize = 120;
+var pickerGap = 18;
+// For error highlight
+var errorFlashDuration = 400;
+// --- Asset Initialization ---
+// 9 unicorn icons
+for (var i = 0; i < 9; i++) {}
+// Cell background
+// Picker background
+var board = []; // 2D array of UnicornCell
+var givenBoard = []; // 2D array of unicorn indices (0-8) or null
+var solutionBoard = []; // 2D array of unicorn indices (0-8)
+var selectedCell = null;
+var picker = null;
+var timerTxt = null;
+var startTime = null;
+var timerInterval = null;
+var errorCells = [];
+var completed = false;
+// --- Sudoku Puzzle Generation ---
+// For MVP, use a static puzzle and solution (easy level)
+var staticPuzzle = [[null, null, 2, null, 3, null, 7, null, null], [6, null, null, 1, 9, 5, null, null, null], [null, 9, 8, null, null, null, null, 6, null], [8, null, null, null, 6, null, null, null, 3], [4, null, null, 8, null, 3, null, null, 1], [7, null, null, null, 2, null, null, null, 6], [null, 6, null, null, null, null, 2, 8, null], [null, null, null, 4, 1, 9, null, null, 5], [null, null, 5, null, 8, null, null, 7, 9]];
+// Solution for the above puzzle (0-8 for unicorn indices)
+var staticSolution = [[0, 1, 2, 6, 3, 8, 7, 5, 4], [6, 7, 4, 1, 9, 5, 8, 2, 3], [5, 9, 8, 7, 4, 2, 1, 6, 0], [8, 5, 1, 2, 6, 7, 4, 0, 3], [4, 2, 6, 8, 5, 3, 9, 7, 1], [7, 3, 9, 5, 2, 4, 0, 8, 6], [1, 6, 3, 9, 7, 0, 5, 4, 2], [2, 8, 7, 4, 1, 9, 6, 3, 5], [9, 4, 5, 3, 8, 6, 2, 1, 7]];
+// --- Helper Functions ---
+// Returns true if placing unicornIdx at (row, col) is valid
+function isValidMove(row, col, unicornIdx) {
+ // Check row
+ for (var c = 0; c < gridSize; c++) {
+ if (c !== col && board[row][c].unicornIndex === unicornIdx) return false;
+ }
+ // Check col
+ for (var r = 0; r < gridSize; r++) {
+ if (r !== row && board[r][col].unicornIndex === unicornIdx) return false;
+ }
+ // Check 3x3 box
+ var boxRow = Math.floor(row / 3) * 3;
+ var boxCol = Math.floor(col / 3) * 3;
+ for (var r = boxRow; r < boxRow + 3; r++) {
+ for (var c = boxCol; c < boxCol + 3; c++) {
+ if ((r !== row || c !== col) && board[r][c].unicornIndex === unicornIdx) return false;
+ }
+ }
+ return true;
+}
+// Returns true if the board is completely and correctly filled
+function isBoardComplete() {
+ for (var r = 0; r < gridSize; r++) {
+ for (var c = 0; c < gridSize; c++) {
+ var cell = board[r][c];
+ if (cell.unicornIndex === null) return false;
+ if (!isValidMove(r, c, cell.unicornIndex)) return false;
+ }
+ }
+ return true;
+}
+// Highlight errors for current board state
+function highlightErrors() {
+ // Clear previous
+ for (var i = 0; i < errorCells.length; i++) {
+ errorCells[i].showError(false);
+ }
+ errorCells = [];
+ // Check for errors
+ for (var r = 0; r < gridSize; r++) {
+ for (var c = 0; c < gridSize; c++) {
+ var cell = board[r][c];
+ if (cell.unicornIndex === null) continue;
+ // Only highlight if not a given
+ if (!cell.isGiven && !isValidMove(r, c, cell.unicornIndex)) {
+ cell.showError(true);
+ errorCells.push(cell);
+ }
+ }
+ }
+}
+// Deselect all cells
+function deselectAllCells() {
+ for (var r = 0; r < gridSize; r++) {
+ for (var c = 0; c < gridSize; c++) {
+ board[r][c].setSelected(false);
+ }
+ }
+ selectedCell = null;
+}
+// --- UI Setup ---
+// Board container
+var boardContainer = new Container();
+boardContainer.x = boardOffsetX;
+boardContainer.y = boardOffsetY;
+game.addChild(boardContainer);
+// Draw grid lines (thick for boxes, thin for cells)
+for (var i = 0; i <= gridSize; i++) {
+ // Vertical
+ var lineW = i % 3 === 0 ? 8 : 3;
+ var lineColor = i % 3 === 0 ? 0x9b59b6 : 0xd1b3e0;
+ var vLine = LK.getAsset('vLine' + i, {
+ width: lineW,
+ height: boardSize,
+ color: lineColor,
+ shape: 'box',
+ anchorX: 0.5,
+ anchorY: 0
+ });
+ vLine.x = i * cellSize;
+ vLine.y = 0;
+ boardContainer.addChild(vLine);
+ // Horizontal
+ var hLine = LK.getAsset('hLine' + i, {
+ width: boardSize,
+ height: lineW,
+ color: lineColor,
+ shape: 'box',
+ anchorX: 0,
+ anchorY: 0.5
+ });
+ hLine.x = 0;
+ hLine.y = i * cellSize;
+ boardContainer.addChild(hLine);
+}
+// Create cells
+for (var r = 0; r < gridSize; r++) {
+ board[r] = [];
+ for (var c = 0; c < gridSize; c++) {
+ var cell = new UnicornCell();
+ cell.x = c * cellSize + cellSize / 2;
+ cell.y = r * cellSize + cellSize / 2;
+ cell.row = r;
+ cell.col = c;
+ boardContainer.addChild(cell);
+ board[r][c] = cell;
+ }
+}
+// Fill in given cells and solution
+for (var r = 0; r < gridSize; r++) {
+ givenBoard[r] = [];
+ solutionBoard[r] = [];
+ for (var c = 0; c < gridSize; c++) {
+ var idx = staticPuzzle[r][c];
+ var cell = board[r][c];
+ if (idx !== null) {
+ cell.setUnicorn(idx, false);
+ cell.isGiven = true;
+ cell.bg.alpha = 0.7;
+ }
+ givenBoard[r][c] = idx;
+ solutionBoard[r][c] = staticSolution[r][c];
+ }
+}
+// --- Picker UI ---
+picker = new UnicornPicker();
+picker.visible = false;
+game.addChild(picker);
+// --- Timer UI ---
+timerTxt = new Text2('00:00', {
+ size: 90,
+ fill: 0x7D3C98
+});
+timerTxt.anchor.set(0.5, 0);
+LK.gui.top.addChild(timerTxt);
+// --- Title UI ---
+var titleTxt = new Text2('Unicorn Sudoku', {
+ size: 110,
+ fill: 0xA569BD
+});
+titleTxt.anchor.set(0.5, 0);
+titleTxt.y = 10;
+LK.gui.top.addChild(titleTxt);
+// --- Instructions UI ---
+var instrTxt = new Text2('Tap a cell, then pick a unicorn to fill it!', {
+ size: 60,
+ fill: 0x7D3C98
+});
+instrTxt.anchor.set(0.5, 0);
+instrTxt.y = 120;
+LK.gui.top.addChild(instrTxt);
+// --- Event Handlers ---
+// Cell tap: select cell and show picker
+function onCellDown(x, y, obj) {
+ if (completed) return;
+ var cell = obj;
+ if (cell.isGiven) return;
+ deselectAllCells();
+ cell.setSelected(true);
+ selectedCell = cell;
+ // Show picker below the cell, but keep inside screen
+ var global = boardContainer.toGlobal(cell.position);
+ var pickerX = Math.max(40, Math.min(global.x - pickerIconSize * 4, 2048 - pickerIconSize * 9 - 40));
+ var pickerY = Math.min(global.y + cellSize / 2 + 30, 2732 - pickerIconSize - 80);
+ picker.show(pickerX, pickerY);
+ picker.setSelected(null);
+}
+// Picker tap: set unicorn in selected cell
+function onPickerDown(x, y, obj) {
+ if (!selectedCell || completed) return;
+ var idx = obj.idx;
+ if (idx === undefined) return;
+ // If already has this unicorn, clear
+ if (selectedCell.unicornIndex === idx) {
+ selectedCell.clearUnicorn();
+ picker.setSelected(null);
+ } else {
+ selectedCell.setUnicorn(idx, true);
+ picker.setSelected(idx);
+ }
+ highlightErrors();
+ // Check for win
+ if (isBoardComplete()) {
+ completed = true;
+ picker.hide();
+ deselectAllCells();
+ LK.effects.flashScreen(0x7d3c98, 800);
+ LK.setTimeout(function () {
+ LK.showYouWin();
+ }, 900);
+ }
+}
+// Hide picker if tap outside
+function onGameDown(x, y, obj) {
+ // If tap is not on a cell or picker, hide picker and deselect
+ if (obj && (obj instanceof UnicornCell || obj === picker || picker.icons.indexOf(obj) !== -1)) return;
+ picker.hide();
+ deselectAllCells();
+}
+// --- Attach event handlers ---
+// Attach to each cell
+for (var r = 0; r < gridSize; r++) {
+ for (var c = 0; c < gridSize; c++) {
+ var cell = board[r][c];
+ cell.down = onCellDown;
+ }
+}
+// Attach to picker icons
+for (var i = 0; i < picker.icons.length; i++) {
+ picker.icons[i].down = onPickerDown;
+}
+// Attach to game for outside tap
+game.down = onGameDown;
+// --- Timer Logic ---
+function formatTime(secs) {
+ var m = Math.floor(secs / 60);
+ var s = secs % 60;
+ return (m < 10 ? '0' : '') + m + ':' + (s < 10 ? '0' : '') + s;
+}
+function updateTimer() {
+ if (completed) return;
+ var now = Date.now();
+ var elapsed = Math.floor((now - startTime) / 1000);
+ timerTxt.setText(formatTime(elapsed));
+}
+// --- Game Start ---
+function startGame() {
+ completed = false;
+ deselectAllCells();
+ picker.hide();
+ highlightErrors();
+ startTime = Date.now();
+ timerTxt.setText('00:00');
+ if (timerInterval) LK.clearInterval(timerInterval);
+ timerInterval = LK.setInterval(updateTimer, 1000);
+}
+startGame();
+// --- Game Update (not used for logic, but required) ---
+game.update = function () {
+ // No per-frame logic needed for MVP
+};
\ No newline at end of file