Please bookmark this page to avoid losing your image tool!

Image Gagará Game

(Free & Supports Bulk Upload)

Drag & drop your images here or

The result will appear here...
You can edit the below JavaScript code to customize the image tool.
function processImage(originalImg, gridSizeStr = "4") {
    const gridSize = parseInt(gridSizeStr, 10) || 4;
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');

    // Scale canvas if image is too large for comfortable playing
    const maxDim = 800; 
    let w = originalImg.width;
    let h = originalImg.height;
    if (w > maxDim || h > maxDim) {
        if (w > h) {
            h = Math.floor(h * maxDim / w);
            w = maxDim;
        } else {
            w = Math.floor(w * maxDim / h);
            h = maxDim;
        }
    }
    canvas.width = w;
    canvas.height = h;
    canvas.style.cursor = 'pointer';
    canvas.style.maxWidth = '100%';
    canvas.style.display = 'block';

    const cellW = w / gridSize;
    const cellH = h / gridSize;
    const totalCells = gridSize * gridSize;
    let emptyIdx = totalCells - 1;
    let state = Array.from({length: totalCells}, (_, i) => i);
    let lastSwap = -1;

    // Shuffle the board by simulating random valid moves (guarantees a solvable puzzle)
    const shuffleMoves = totalCells * 150;
    for(let i = 0; i < shuffleMoves; i++) {
        let emptyCol = emptyIdx % gridSize;
        let emptyRow = Math.floor(emptyIdx / gridSize);
        let neighbors = [];
        
        // Prevent moving the tile back to the immediate last position to speed up shuffling
        if (emptyCol > 0 && (emptyIdx - 1) !== lastSwap) neighbors.push(emptyIdx - 1);
        if (emptyCol < gridSize - 1 && (emptyIdx + 1) !== lastSwap) neighbors.push(emptyIdx + 1);
        if (emptyRow > 0 && (emptyIdx - gridSize) !== lastSwap) neighbors.push(emptyIdx - gridSize);
        if (emptyRow < gridSize - 1 && (emptyIdx + gridSize) !== lastSwap) neighbors.push(emptyIdx + gridSize);

        // Fallback in rare stuck case
        if (neighbors.length === 0) {
            if (emptyCol > 0) neighbors.push(emptyIdx - 1);
            else neighbors.push(emptyIdx + 1);
        }

        let swapWith = neighbors[Math.floor(Math.random() * neighbors.length)];
        state[emptyIdx] = state[swapWith];
        state[swapWith] = totalCells - 1;
        lastSwap = emptyIdx;
        emptyIdx = swapWith;
    }

    let isWin = false;

    // Draw the current state of the puzzle board
    function draw() {
        ctx.fillStyle = "#222";
        ctx.fillRect(0, 0, w, h);

        const srcCellW = originalImg.width / gridSize;
        const srcCellH = originalImg.height / gridSize;

        for (let i = 0; i < totalCells; i++) {
            let val = state[i];
            // Don't draw the empty cell unless the puzzle is completely solved
            if (val === totalCells - 1 && !isWin) continue;

            let destCol = i % gridSize;
            let destRow = Math.floor(i / gridSize);
            let srcCol = val % gridSize;
            let srcRow = Math.floor(val / gridSize);

            // Draw the image slice for this tile
            ctx.drawImage(
                originalImg,
                srcCol * srcCellW,
                srcRow * srcCellH,
                srcCellW,
                srcCellH,
                destCol * cellW,
                destRow * cellH,
                cellW,
                cellH
            );

            // Draw tile borders
            if (!isWin) {
                ctx.strokeStyle = "rgba(255, 255, 255, 0.4)";
                ctx.lineWidth = 1;
                ctx.strokeRect(destCol * cellW, destRow * cellH, cellW, cellH);
            }
        }

        // Overlay winning message
        if (isWin) {
            ctx.fillStyle = "rgba(0, 0, 0, 0.7)";
            ctx.fillRect(0, 0, w, h);
            ctx.fillStyle = "#ffffff";
            ctx.font = "bold Math.max(30, Math.floor(w/15))px Arial, sans-serif";
            ctx.textAlign = "center";
            ctx.textBaseline = "middle";
            ctx.fillText("Поздравляем!", w / 2, h / 2 - 20);
            ctx.font = "Math.max(16, Math.floor(w/30))px Arial, sans-serif";
            ctx.fillText("Игра в гагару пройдена", w / 2, h / 2 + 30);
            canvas.style.cursor = 'default';
        }
    }

    // Handle clicks to move puzzle tiles
    canvas.addEventListener('click', (e) => {
        if (isWin) return;
        
        const rect = canvas.getBoundingClientRect();
        // Scale mouse coords to account for any CSS max-width/height scaling
        const scaleX = canvas.width / rect.width;
        const scaleY = canvas.height / rect.height;
        const mouseX = (e.clientX - rect.left) * scaleX;
        const mouseY = (e.clientY - rect.top) * scaleY;

        const col = Math.floor(mouseX / cellW);
        const row = Math.floor(mouseY / cellH);
        const idx = row * gridSize + col;

        const emptyCol = emptyIdx % gridSize;
        const emptyRow = Math.floor(emptyIdx / gridSize);

        // Check if the clicked tile is adjacent (horizontally or vertically) to the empty spot
        const isAdj = (col === emptyCol && Math.abs(row - emptyRow) === 1) ||
                      (row === emptyRow && Math.abs(col - emptyCol) === 1);

        if (isAdj) {
            // Swap tile with empty spot
            state[emptyIdx] = state[idx];
            state[idx] = totalCells - 1;
            emptyIdx = idx;

            // Determine if the game is won
            isWin = true;
            for (let i = 0; i < totalCells; i++) {
                if (state[i] !== i) {
                    isWin = false;
                    break;
                }
            }
            
            draw();
        }
    });

    // Initial render
    draw();
    
    return canvas;
}

Free Image Tool Creator

Can't find the image tool you're looking for?
Create one based on your own needs now!

Description

The Image Gagará Game is an interactive tool that transforms any uploaded image into a playable sliding tile puzzle. The tool automatically slices your image into a grid and shuffles the pieces, creating a challenging game where the goal is to rearrange the tiles to reconstruct the original picture. This tool is ideal for creating personalized digital puzzles for entertainment, educational brain training, or as a fun way to engage with your favorite photos.

Leave a Reply

Your email address will not be published. Required fields are marked *