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;
// Add vertical space above icons
var pickerTopPadding = 36; // extra space above icons
// Create 9 unicorn icons
for (var i = 0; i < 9; i++) {
var icon = self.attachAsset('unicorn' + i, {
width: pickerIconSize,
height: pickerIconSize,
anchorX: -1,
anchorY: -1,
x: i * (pickerIconSize + pickerGap),
y: pickerTopPadding // shift icons down by padding
});
icon.idx = i;
self.icons.push(icon);
}
// Background
var pickerBg = self.attachAsset('pickerBg', {
width: 9 * pickerIconSize + 8 * pickerGap + 32,
height: pickerIconSize + 32 + pickerTopPadding,
// increase height for top padding
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
****/
// --- Game State ---
/****
* Game Constants
****/
// Board layout
// Add unicorn image assets (replace with your actual unicorn image asset ids or use placeholder images)
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++) {
if (typeof board[r][c].setSelected === "function") {
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++) {
// Ensure UnicornCell is defined before this point and all cells are instances of UnicornCell
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 ---
// Place picker at the bottom of the board, centered horizontally, with margin from the board
picker = new UnicornPicker();
picker.visible = false;
// Calculate picker position: center horizontally, below the board with margin
var pickerMargin = 60;
picker.x = boardOffsetX + (boardSize - (9 * pickerIconSize + 8 * pickerGap + 32)) / 2;
picker.y = boardOffsetY + boardSize + pickerMargin;
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();
if (typeof cell.setSelected === "function") {
cell.setSelected(true);
}
selectedCell = cell;
// Show picker below the cell, but keep inside screen
// Defensive: cell.position may be undefined, so fallback to cell.x/cell.y
var cellPos = cell && cell.position ? cell.position : {
x: cell.x,
y: cell.y
};
var global = boardContainer.toGlobal(cellPos);
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
@@ -111,10 +111,10 @@
for (var i = 0; i < 9; i++) {
var icon = self.attachAsset('unicorn' + i, {
width: pickerIconSize,
height: pickerIconSize,
- anchorX: 1,
- anchorY: 1,
+ anchorX: -1,
+ anchorY: -1,
x: i * (pickerIconSize + pickerGap),
y: pickerTopPadding // shift icons down by padding
});
icon.idx = i;
@@ -344,10 +344,15 @@
solutionBoard[r][c] = staticSolution[r][c];
}
}
// --- Picker UI ---
+// Place picker at the bottom of the board, centered horizontally, with margin from the board
picker = new UnicornPicker();
picker.visible = false;
+// Calculate picker position: center horizontally, below the board with margin
+var pickerMargin = 60;
+picker.x = boardOffsetX + (boardSize - (9 * pickerIconSize + 8 * pickerGap + 32)) / 2;
+picker.y = boardOffsetY + boardSize + pickerMargin;
game.addChild(picker);
// --- Timer UI ---
timerTxt = new Text2('00:00', {
size: 90,