Download puzzle_visualizer.html from Code2aum/HRM_sudoku: direct link, hf CLI and curl.
- Browser
- Download file 14.1 kB
-
https://huggingface.co/Code2aum/HRM_sudoku/resolve/main/puzzle_visualizer.html
- Command line
-
hf download hf://Code2aum/HRM_sudoku/puzzle_visualizer.html
-
curl -L -o puzzle_visualizer.html https://huggingface.co/Code2aum/HRM_sudoku/resolve/main/puzzle_visualizer.html
14.1 kB
| <html> | |
| <head> | |
| <meta charset="UTF-8" /> | |
| <title>ARC‐Converted Dataset Visualizer (Upload Local Folder)</title> | |
| <style> | |
| body { | |
| font-family: sans-serif; | |
| margin: 16px; | |
| } | |
| .selector-area { | |
| margin-bottom: 1rem; | |
| } | |
| .grid-canvas { | |
| margin: 4px; | |
| border: 1px solid #ccc; | |
| } | |
| .example-container { | |
| display: inline-block; | |
| margin: 0 16px 16px 0; | |
| vertical-align: top; | |
| } | |
| .puzzle-display { | |
| margin-top: 1rem; | |
| } | |
| .puzzle-id { | |
| font-weight: bold; | |
| margin-bottom: 0.5rem; | |
| } | |
| #groupList, #puzzleList { | |
| margin: 1rem 0; | |
| } | |
| .group-item, .puzzle-item { | |
| cursor: pointer; | |
| margin: 4px 8px 4px 0; | |
| padding: 2px 6px; | |
| border: 1px solid #aaa; | |
| display: inline-block; | |
| } | |
| .group-item:hover, .puzzle-item:hover { | |
| background: #eef; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <h1>ARC‐Converted Dataset Visualizer (Local Directory)</h1> | |
| <div class="selector-area"> | |
| <!-- 1) Directory input with webkitdirectory, mozdirectory --> | |
| <label>Upload ARC Folder:</label> | |
| <input type="file" id="folderInput" | |
| webkitdirectory mozdirectory multiple | |
| onchange="onFolderSelected(event)" /> | |
| <br><br> | |
| <!-- 2) We'll enable set/subset selection after user chooses a folder and data is validated --> | |
| <label>Set:</label> | |
| <select id="setSelect" disabled> | |
| <option value="train">train</option> | |
| <option value="test">test</option> | |
| </select> | |
| <label> Subset:</label> | |
| <select id="subsetSelect" disabled> | |
| <option value="all">all</option> | |
| </select> | |
| <button id="loadBtn" disabled>Load</button> | |
| </div> | |
| <div> | |
| <div id="groupList"></div> | |
| <div id="puzzleList"></div> | |
| <div class="puzzle-display" id="puzzleView"></div> | |
| </div> | |
| <!-- | |
| 3) Use local 'assets/npyjs.js' from your project folder instead of a CDN. | |
| Make sure 'assets/npyjs.js' is the unbundled or UMD version that doesn't | |
| contain "import" statements. | |
| --> | |
| <script src="assets/npyjs.js"></script> | |
| <script> | |
| /*************************************************************************** | |
| * Global Maps & Variables | |
| ***************************************************************************/ | |
| // Map from "train/all__inputs.npy" => File, etc. | |
| let filesByPath = {}; | |
| // Once loaded, we store typed arrays for the chosen set/subset | |
| let inputsArr, labelsArr; | |
| let puzzleIndicesArr, groupIndicesArr, puzzleIdentifiersArr; | |
| let identifiersJson; | |
| // The shape of inputs is [N_examples, seqLen], so we discover seqLen & gridSize | |
| let seqLen = 0; | |
| let gridSize = 0; | |
| /*************************************************************************** | |
| * 1) Handle folder selection: read all files, find identifiers.json, | |
| * remove topmost folder from each file path, validate. | |
| ***************************************************************************/ | |
| function onFolderSelected(event) { | |
| filesByPath = {}; | |
| const fileList = event.target.files; | |
| if (!fileList || fileList.length === 0) { | |
| alert("No files selected!"); | |
| return; | |
| } | |
| // We'll gather all webkitRelativePaths | |
| const paths = []; | |
| for (let i = 0; i < fileList.length; i++) { | |
| // Typically "arc-aug-10/train/all__inputs.npy", etc. | |
| const file = fileList[i]; | |
| const relPath = file.webkitRelativePath || file.mozRelativePath || file.name; | |
| paths.push(relPath); | |
| } | |
| // 1. Check if we have "identifiers.json" somewhere. | |
| const idPath = paths.find(p => p.endsWith("identifiers.json")); | |
| if (!idPath) { | |
| alert("Error: No 'identifiers.json' found in the uploaded folder."); | |
| return; | |
| } | |
| // 2. Derive the top-level directory from that file's path | |
| // e.g. if idPath = "arc-aug-10/identifiers.json", topDir = "arc-aug-10" | |
| // If there's no slash, topDir = "" => do nothing | |
| let topDir = ""; | |
| const lastSlash = idPath.lastIndexOf("/"); | |
| if (lastSlash >= 0) { | |
| topDir = idPath.substring(0, lastSlash); | |
| } | |
| // 3. Rebuild filesByPath with the top folder removed. | |
| // For example, if topDir = "arc-aug-10", then "arc-aug-10/train/all__inputs.npy" | |
| // becomes "train/all__inputs.npy" | |
| for (let i = 0; i < fileList.length; i++) { | |
| const file = fileList[i]; | |
| let relPath = file.webkitRelativePath || file.mozRelativePath || file.name; | |
| // If relPath starts with "arc-aug-10/", remove that prefix | |
| if (topDir && relPath.startsWith(topDir + "/")) { | |
| relPath = relPath.substring(topDir.length + 1); | |
| } | |
| filesByPath[relPath] = file; | |
| } | |
| // Enable set/subset selection and "Load" | |
| document.getElementById("setSelect").disabled = false; | |
| document.getElementById("subsetSelect").disabled = false; | |
| document.getElementById("loadBtn").disabled = false; | |
| } | |
| // When user clicks "Load," parse the .npy for the chosen set/subset | |
| document.getElementById("loadBtn").addEventListener("click", async () => { | |
| document.getElementById("groupList").innerHTML = ""; | |
| document.getElementById("puzzleList").innerHTML = ""; | |
| document.getElementById("puzzleView").innerHTML = ""; | |
| const setName = document.getElementById("setSelect").value; // e.g. "train" | |
| const subsetName = document.getElementById("subsetSelect").value; // e.g. "all" | |
| try { | |
| await loadDataset(setName, subsetName); | |
| buildGroupList(); // show groups | |
| } catch (err) { | |
| console.error(err); | |
| alert("Error while loading dataset: " + err); | |
| } | |
| }); | |
| /*************************************************************************** | |
| * 2) Load .npy from local files using Npyjs + FileReader (ArrayBuffer) | |
| ***************************************************************************/ | |
| async function loadDataset(setName, subsetName) { | |
| const prefix = `${setName}/${subsetName}__`; | |
| // e.g. "train/all__inputs.npy" | |
| const inputsPath = prefix + "inputs.npy"; | |
| const labelsPath = prefix + "labels.npy"; | |
| const pIdxPath = prefix + "puzzle_indices.npy"; | |
| const gIdxPath = prefix + "group_indices.npy"; | |
| const pIdsPath = prefix + "puzzle_identifiers.npy"; | |
| const identifiersPath = "identifiers.json"; | |
| // Check existence | |
| const needed = [inputsPath, labelsPath, pIdxPath, gIdxPath, pIdsPath, identifiersPath]; | |
| for (const f of needed) { | |
| if (!filesByPath[f]) { | |
| throw new Error(`Missing file: ${f}`); | |
| } | |
| } | |
| // parseNpy => read from File -> ArrayBuffer -> Npyjs => typed array | |
| const inputsNpy = await parseNpy(filesByPath[inputsPath]); | |
| const labelsNpy = await parseNpy(filesByPath[labelsPath]); | |
| const puzzleIndicesNpy= await parseNpy(filesByPath[pIdxPath]); | |
| const groupIndicesNpy = await parseNpy(filesByPath[gIdxPath]); | |
| const puzzleIdsNpy = await parseNpy(filesByPath[pIdsPath]); | |
| inputsArr = inputsNpy.data; | |
| labelsArr = labelsNpy.data; | |
| puzzleIndicesArr = puzzleIndicesNpy.data; | |
| groupIndicesArr = groupIndicesNpy.data; | |
| puzzleIdentifiersArr = puzzleIdsNpy.data; | |
| // shape e.g. [N_examples, seqLen] | |
| seqLen = inputsNpy.shape[1]; | |
| gridSize = Math.sqrt(seqLen); | |
| // read JSON | |
| identifiersJson = await readJsonFile(filesByPath[identifiersPath]); | |
| } | |
| /*************************************************************************** | |
| * parseNpy => read a File as ArrayBuffer, parse with npyjs | |
| ***************************************************************************/ | |
| function parseNpy(file) { | |
| return new Promise((resolve, reject) => { | |
| const reader = new FileReader(); | |
| reader.onload = async () => { | |
| try { | |
| const arrayBuffer = reader.result; | |
| const npy = new npyjs(); | |
| resolve(await npy.parse(arrayBuffer)); | |
| } catch (err) { | |
| reject(err); | |
| } | |
| }; | |
| reader.onerror = err => reject(err); | |
| reader.readAsArrayBuffer(file); | |
| }); | |
| } | |
| /*************************************************************************** | |
| * readJsonFile => read a local JSON file into object | |
| ***************************************************************************/ | |
| function readJsonFile(file) { | |
| return new Promise((resolve, reject) => { | |
| const reader = new FileReader(); | |
| reader.onload = () => { | |
| try { | |
| const obj = JSON.parse(reader.result); | |
| resolve(obj); | |
| } catch (err) { | |
| reject(err); | |
| } | |
| }; | |
| reader.onerror = (err) => reject(err); | |
| reader.readAsText(file); | |
| }); | |
| } | |
| /*************************************************************************** | |
| * 3) Build group list in UI | |
| ***************************************************************************/ | |
| function buildGroupList() { | |
| document.getElementById("groupList").innerHTML = "<h3>Groups</h3>"; | |
| const groupListDiv = document.getElementById("groupList"); | |
| const nGroups = groupIndicesArr.length - 1; | |
| for (let g = 0; g < nGroups; g++) { | |
| const div = document.createElement("span"); | |
| div.className = "group-item"; | |
| div.textContent = `Group ${g}`; | |
| div.onclick = () => onSelectGroup(g); | |
| groupListDiv.appendChild(div); | |
| } | |
| } | |
| /*************************************************************************** | |
| * onSelectGroup => show puzzles in that group | |
| ***************************************************************************/ | |
| function onSelectGroup(groupIndex) { | |
| document.getElementById("puzzleList").innerHTML = ""; | |
| document.getElementById("puzzleView").innerHTML = ""; | |
| const puzzleListDiv = document.getElementById("puzzleList"); | |
| puzzleListDiv.innerHTML = `<h4>Puzzles in Group ${groupIndex}</h4>`; | |
| const firstPuzzle = groupIndicesArr[groupIndex]; | |
| const lastPuzzle = groupIndicesArr[groupIndex + 1]; | |
| for (let p = firstPuzzle; p < lastPuzzle; p++) { | |
| const puzzleIntId = puzzleIdentifiersArr[p]; | |
| const puzzleStrId = (puzzleIntId < identifiersJson.length) | |
| ? identifiersJson[puzzleIntId] | |
| : "<unknown>"; | |
| const div = document.createElement("span"); | |
| div.className = "puzzle-item"; | |
| div.textContent = `Puzzle #${p} [ID=${puzzleIntId}: ${puzzleStrId}]`; | |
| div.onclick = () => onSelectPuzzle(p); | |
| puzzleListDiv.appendChild(div); | |
| } | |
| } | |
| /*************************************************************************** | |
| * onSelectPuzzle => show each example | |
| ***************************************************************************/ | |
| function onSelectPuzzle(puzzleIndex) { | |
| const puzzleView = document.getElementById("puzzleView"); | |
| puzzleView.innerHTML = ""; | |
| // puzzle ID | |
| const puzzleIntId = puzzleIdentifiersArr[puzzleIndex]; | |
| const puzzleStrId = (puzzleIntId < identifiersJson.length) | |
| ? identifiersJson[puzzleIntId] | |
| : "<unknown>"; | |
| const titleDiv = document.createElement("div"); | |
| titleDiv.className = "puzzle-id"; | |
| titleDiv.textContent = `Puzzle #${puzzleIndex} — ID: ${puzzleStrId}`; | |
| puzzleView.appendChild(titleDiv); | |
| // Examples are [puzzleIndicesArr[p], puzzleIndicesArr[p+1]) | |
| const firstExample = puzzleIndicesArr[puzzleIndex]; | |
| const lastExample = puzzleIndicesArr[puzzleIndex + 1]; | |
| for (let e = firstExample; e < lastExample; e++) { | |
| const inputSeq = slice1D(inputsArr, e*seqLen, (e+1)*seqLen); | |
| const outputSeq = slice1D(labelsArr, e*seqLen, (e+1)*seqLen); | |
| const inputGrid = decodeGrid(inputSeq); | |
| const outputGrid = decodeGrid(outputSeq); | |
| const exDiv = document.createElement("div"); | |
| exDiv.className = "example-container"; | |
| exDiv.appendChild(document.createTextNode(`Example ${e}`)); | |
| exDiv.appendChild(document.createElement("br")); | |
| exDiv.appendChild(renderGrid(inputGrid)); | |
| exDiv.appendChild(renderGrid(outputGrid)); | |
| puzzleView.appendChild(exDiv); | |
| } | |
| } | |
| /*************************************************************************** | |
| * slice1D => typed array slicing | |
| ***************************************************************************/ | |
| function slice1D(arr, start, end) { | |
| const result = new Uint32Array(end - start); | |
| for (let i = start; i < end; i++) { | |
| result[i - start] = Number(arr[i]); | |
| } | |
| return result; | |
| } | |
| /*************************************************************************** | |
| * decodeGrid => turn the flattened seq of length=gridSize^2 into 2D | |
| ***************************************************************************/ | |
| function decodeGrid(seq) { | |
| const grid = []; | |
| let idx = 0; | |
| for (let r = 0; r < gridSize; r++) { | |
| const row = []; | |
| for (let c = 0; c < gridSize; c++) { | |
| row.push(seq[idx]); | |
| idx++; | |
| } | |
| grid.push(row); | |
| } | |
| return grid; | |
| } | |
| /*************************************************************************** | |
| * renderGrid => draws a 2D grid to <canvas> | |
| ***************************************************************************/ | |
| function renderGrid(grid2d) { | |
| const rows = grid2d.length; | |
| const cols = grid2d[0].length; | |
| const scale = 10; | |
| const canvas = document.createElement("canvas"); | |
| canvas.width = cols * scale; | |
| canvas.height = rows * scale; | |
| canvas.className = "grid-canvas"; | |
| const ctx = canvas.getContext("2d"); | |
| for (let r = 0; r < rows; r++) { | |
| for (let c = 0; c < cols; c++) { | |
| const val = grid2d[r][c]; | |
| ctx.fillStyle = indexToColor(val); | |
| ctx.fillRect(c * scale, r * scale, scale, scale); | |
| } | |
| } | |
| return canvas; | |
| } | |
| /*************************************************************************** | |
| * indexToColor => color palette: | |
| * 0 => pad => white | |
| * 1 => eos => light gray | |
| * 2..11 => original color(0..9) | |
| ***************************************************************************/ | |
| function indexToColor(value) { | |
| if (value === 0) return "#FFFFFF"; // pad => white | |
| if (value === 1) return "#DDDDDD"; // eos => light gray | |
| // shift by 2 => original color in [0..9] | |
| const colorIdx = value - 2; | |
| const palette = [ | |
| "#000000", // color0 => black | |
| "#FF0000", // color1 => red | |
| "#00FF00", // color2 => green | |
| "#0000FF", // color3 => blue | |
| "#FFFF00", // color4 => yellow | |
| "#FFA500", // color5 => orange | |
| "#800080", // color6 => purple | |
| "#00FFFF", // color7 => cyan | |
| "#FFC0CB", // color8 => pink | |
| "#808080" // color9 => gray | |
| ]; | |
| if (colorIdx >= 0 && colorIdx < palette.length) { | |
| return palette[colorIdx]; | |
| } | |
| return "#FFFFFF"; // fallback | |
| } | |
| </script> | |
| </body> | |
| </html> | |