worker.mjs (6042B)
1 import Nissy from "./nissy_web_module.mjs" 2 3 const nissy = await Nissy(); 4 5 const log = (cstr) => postMessage({ 6 command: "log", 7 id: -1, 8 object: nissy.UTF8ToString(cstr) 9 }); 10 nissy.setLogger(nissy.addFunction(log, "vp")); 11 12 var solveStatus = nissy.statusRUN; // For now this is a global variable 13 const pollStatus = () => solveStatus; 14 const pollStatusCallback = nissy.addFunction(pollStatus, "i"); 15 16 const commands = [ 17 { name: "load solver data", exec: loadSolverDataFromStorage }, 18 { name: "download solver data", exec: downloadSolverData }, 19 { name: "generate solver data", exec: generateSolverData }, 20 { name: "validate scramble", exec: validateScramble }, 21 { name: "solve", exec: solve }, 22 { name: "update status", exec: updateStatus }, 23 ]; 24 25 // Message structure: 26 // { 27 // command: string // The function to run. 28 // id: number // An identification number for the command, used for 29 // // sending responses back to the caller and having them 30 // // caught by the correct handler. 31 // arg: object // The actual argument of the message, command-specific. 32 // // See below for details. 33 // } 34 onmessage = (event) => { 35 for (var i = 0; i < commands.length; i++) { 36 if (commands[i].name == event.data.command) { 37 commands[i].exec(event.data.id, event.data.arg); 38 console.log("[worker] Received '" + commands[i].name + "'"); 39 return; 40 } 41 } 42 43 console.log("[nissy worker] unknown command " + event.data.command); 44 }; 45 46 // Load solver data from storage. 47 // Argument: string (the name of the solver) 48 async function loadSolverDataFromStorage(id, solver) { 49 const async_return = (success, message = "") => postMessage({ 50 command: "load solver data", 51 id: id, 52 arg: { 53 success: success, 54 message: message 55 } 56 }); 57 58 if (!(await nissy.isSolverAvailable(solver))) { 59 async_return(false, "Error: solver " + solver + 60 " is not available in this version of nissy."); 61 return; 62 } 63 64 if (await nissy.isSolverLoaded(solver)) { 65 async_return(true); 66 return; 67 } 68 69 if (await nissy.initSolverFromStorage(solver)) { 70 async_return(true); 71 } else { 72 async_return(false, "Could not read data for " + solver + 73 " from local storage"); 74 } 75 } 76 77 // Download solver data. 78 // Argument: string (the name of the solver) 79 async function downloadSolverData(id, solver) { 80 const async_return = (success, message = "") => postMessage({ 81 command: "download solver data", 82 id: id, 83 arg: { 84 success: success, 85 message: message 86 } 87 }); 88 89 if (!(await nissy.isSolverAvailable(solver))) { 90 async_return(false, "Error: solver " + arg.solver + 91 " is not available in this version of nissy."); 92 return; 93 } 94 95 if (await nissy.initSolverDownload(solver, "/tables")) { 96 async_return(true); 97 } else { 98 async_return(false, "Error retrieving solver data"); 99 } 100 } 101 102 // Generate solver data locally. 103 // Argument: string (the name of the solver) 104 async function generateSolverData(id, solver) { 105 const async_return = (success, message = "") => postMessage({ 106 command: "generate solver data", 107 id: id, 108 arg: { 109 success: success, 110 message: message 111 } 112 }); 113 114 if (!(await nissy.isSolverAvailable(solver))) { 115 async_return(false, "Error: solver " + arg.solver + 116 " is not available in this version of nissy."); 117 return; 118 } 119 120 if (await nissy.initSolverGenerate(solver)) { 121 async_return(true); 122 } else { 123 async_return(false, "Error generating solver data"); 124 } 125 } 126 127 // Check if the scramble is valid. 128 // Argument: string (the scramble). 129 async function validateScramble(id, arg) { 130 const async_return = (success) => postMessage({ 131 command: "validate scramble", 132 id: id, 133 arg: success 134 }); 135 136 var cube = new nissy.Cube(); 137 async_return(cube.move(arg).ok()); 138 } 139 140 // Solve the cube with the given options. 141 // Argument: { 142 // solver: string 143 // scramble: string 144 // minmoves: number 145 // maxmoves: number 146 // maxsolutions: number 147 // optimal: number 148 // threads: number 149 // } 150 async function solve(id, arg) { 151 const async_return = (success, solutions = [], message = "") => postMessage({ 152 command: "solve", 153 id: id, 154 arg: { 155 success: success, 156 solutions: solutions, 157 message: message 158 } 159 }); 160 161 if (!(await nissy.isSolverAvailable(arg.solver))) { 162 async_return(false, [], "Error: solver " + arg.solver + 163 " is not available in this version of nissy."); 164 return; 165 } 166 167 if (!(await nissy.isSolverLoaded(arg.solver)) && 168 !(await nissy.initSolverFromStorage(arg.solver))) { 169 async_return(false, [], "Error: solver " + arg.solver + " has not been " + 170 "loaded. Its data must be donwloaded or generated before using it."); 171 return; 172 } 173 174 solveStatus = nissy.statusRUN; 175 176 var cube = new nissy.Cube(); 177 cube.move(arg.scramble); 178 179 const nissFlag = ((str) => { 180 switch (str) { 181 case "inverse": return nissy.NissFlag.inverse; 182 case "mixed": return nissy.NissFlag.mixed; 183 case "linear": return nissy.NissFlag.linear; 184 case "all": return nissy.NissFlag.all; 185 default: return nissy.NissFlag.normal; 186 } 187 })(arg.nissFlag); 188 189 const result = await nissy.solve(arg.solver, cube, nissFlag, arg.minmoves, 190 arg.maxmoves, arg.maxsolutions, arg.optimal, arg.threads, 191 pollStatusCallback); 192 193 if (result.err.ok()) { 194 var solutions = result.solutions == "" ? [] : result.solutions.split("\n"); 195 solutions.pop(); // Solver always returns string ending in newline 196 for (var i = 0; i < solutions.length; i++) { 197 const movecount = await nissy.countMoves(solutions[i]); 198 solutions[i] += " (" + movecount.value + ")"; 199 } 200 async_return(true, solutions); 201 } else { 202 async_return(false, [], 203 "Error while solving (error " + result.err.value + ")"); 204 } 205 }; 206 207 function updateStatus(id, arg) { 208 if (arg == "stop") { 209 solveStatus = nissy.statusSTOP; 210 } else if (arg == "pause") { 211 solveStatus = nissy.statusPAUSE; 212 } else { 213 solveStatus = nissy.statusRUN; 214 } 215 };