document.addEventListener('DOMContentLoaded', () => { // DOM elements const canvas = document.getElementById('unscramble-canvas'); const ctx = canvas.getContext('2d'); const loadingMessage = document.getElementById('loading-message'); // Prevent right-click on the canvas canvas.oncontextmenu = (e) => { e.preventDefault(); return false; }; // --- Main Unscrambling Logic --- async function unscramble() { try { // 1. Fetch the map data and the scrambled image simultaneously const [mapResponse, scrambledImage] = await Promise.all([ fetch('assets/map.json'), loadImage('assets/scrambled.png') ]); if (!mapResponse.ok) { throw new Error(`Failed to load map.json: ${mapResponse.statusText}`); } const mapData = await mapResponse.json(); const { gridSize, scrambleMap, width, height } = mapData; // Hide the loading message and set canvas dimensions loadingMessage.style.display = 'none'; canvas.width = width; canvas.height = height; // 2. Calculate the tile dimensions const tileW = canvas.width / gridSize; const tileH = canvas.height / gridSize; // 3. Create an "inverse map" for easy unscrambling. // The scrambleMap tells us: new_position -> original_position // We need to know where the tile for an original_position is located now. const inverseMap = new Array(scrambleMap.length); for (let newIndex = 0; newIndex < scrambleMap.length; newIndex++) { const originalIndex = scrambleMap[newIndex]; inverseMap[originalIndex] = newIndex; } // 4. Loop through each TILE of the FINAL image and draw it on the canvas for (let originalIndex = 0; originalIndex < scrambleMap.length; originalIndex++) { // Find where this tile is located in the SCRAMBLED image const scrambledIndex = inverseMap[originalIndex]; // Calculate source (from scrambled.png) and destination (on canvas) coordinates const sourceX = (scrambledIndex % gridSize) * tileW; const sourceY = Math.floor(scrambledIndex / gridSize) * tileH; const destX = (originalIndex % gridSize) * tileW; const destY = Math.floor(originalIndex / gridSize) * tileH; // Copy the rectangular tile from the hidden scrambled image to the visible canvas ctx.drawImage( scrambledImage, // The source image sourceX, sourceY, // Top-left corner of the source tile tileW, tileH, // Dimensions of the source tile destX, destY, // Top-left corner of the destination on the canvas tileW, tileH // Dimensions of the destination tile ); } } catch (error) { console.error("Unscrambling failed:", error); loadingMessage.textContent = `Error: ${error.message}`; loadingMessage.style.color = 'red'; } } // Helper function to load an image and return a promise function loadImage(src) { return new Promise((resolve, reject) => { const img = new Image(); img.onload = () => resolve(img); img.onerror = (err) => reject(new Error(`Failed to load image: ${src}`)); img.src = src; }); } // Run the main function unscramble(); });