1(function() { 2 try { 3 var e = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof globalThis ? globalThis : "undefined" != typeof self ? self : {}; 4 e.SENTRY_RELEASE = { id: "63139fb4359a32dff6e65ef9c1c4be204da0c121" }; 5 var n = new e.Error().stack; 6 n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "0c2c20ec-f21b-4a2b-ab47-ffc14348389f", e._sentryDebugIdIdentifier = "sentry-dbid-0c2c20ec-f21b-4a2b-ab47-ffc14348389f"); 7 } catch (e) {} 8})(); 9import { i as __toESM } from "./0xK-A0pq.js"; 10import { Rn as expose, Un as coordStr2Int, Wn as coordToStr, er as wordToString, rr as scoreWord, tr as getTileId, zn as require_localforage } from "./CvEu9crO.js"; 11//#region src/algorithms/trie.ts 12var import_localforage = /* @__PURE__ */ __toESM(require_localforage(), 1); 13var Trie = class { 14 root; 15 elements; 16 constructor() { 17 this.root = { 18 terminal: false, 19 children: {} 20 }; 21 this.elements = 0; 22 } 23 get length() { 24 return this.elements; 25 } 26 get(key) { 27 const node = this.getNode(key); 28 if (node) return node.value; 29 } 30 contains(key) { 31 return !!this.getNode(key); 32 } 33 insert(key, value) { 34 let node = this.root; 35 for (const char of [...key]) { 36 if (!node.children[char]) node.children[char] = { 37 terminal: false, 38 children: {} 39 }; 40 node = node.children[char]; 41 } 42 node.terminal = true; 43 node.value = value; 44 if (!node.terminal) { 45 node.terminal = true; 46 this.elements += 1; 47 } 48 node.value = value; 49 } 50 remove(key) { 51 const node = this.getNode(key); 52 if (node) { 53 node.terminal = false;
54 this.elements -= 1; 55 } 56 } 57 getNode(key) { 58 let node = this.root; 59 for (const char of [...key]) { 60 node = node.children[char]; 61 if (!node) return; 62 } 63 return node; 64 } 65}; 66//#endregion 67//#region src/algorithms/words.md5?raw 68var words_default = "3da1b1098126b0b32ec79967e05c3a2a\n"; 69//#endregion 70//#region src/algorithms/dictionary-worker.ts 71var sortLetters = (w) => [...w].sort((a, b) => a.localeCompare(b)).join(""); 72var wordList = []; 73var dictionary = new Trie(); 74var letters = new Trie(); 75var shouldUpdateDictionary = async () => { 76 return words_default !== await import_localforage.default.getItem("dictionary-md5"); 77}; 78var getIntersections = (w1, w2) => { 79 const c1 = w1.coords.map(coordToStr); 80 const c2 = w2.coords.map(coordToStr); 81 const [long, short] = c1.length > c2.length ? [c1, c2] : [c2, c1]; 82 return long.filter((c) => short.includes(c)).map((i) => i.split(",").map((x) => parseInt(x))); 83}; 84var removeOverlappingWords = (axis) => { 85 const filteredWords = []; 86 for (const [idx, words] of Object.entries(axis)) { 87 for (const [i1, w1] of Object.entries(words)) for (const [i2, w2] of Object.entries(words).slice(+i1 + 1)) { 88 const intersections = getIntersections(w1, w2); 89 if (intersections.length) { 90 if (w1.word.length === intersections.length) filteredWords.push(+i1); 91 else if (w2.word.length === intersections.length) filteredWords.push(+i2); 92 } 93 } 94 axis[idx] = words.filter((w, i) => !filteredWords.includes(i)); 95 } 96}; 97var findWord = (board, i, j, axis, gameType) => { 98 const currWord = []; 99 let longestWord = []; 100 let node = dictionary.getNode(""); 101 const [start, end] = axis === "row" ? [i, board.length] : [j, board[0].length]; 102 for (let k = start; k < end && node; k++) { 103 const tile = board[axis === "row" ? k : i][axis === "col" ? k : j]; 104 if (tile == void 0) break; 105 const nextLetter = tile.letter.toLowerCase(); 106 currWord.push(tile); 107 node = node.children[nextLetter.charAt(0)]; 108 if (node && nextLetter.length > 1) node = node.children[nextLetter.charAt(1)]; 109 if (node?.terminal) longestWord = [...currWord]; 110 } 111 if (gameType === "daily" || longestWord.map((t) => t.letter).join("").length >= 4) return longestWord; 112 else return []; 113}; 114var isFullLength = (w, board) => { 115 return w.axis === "row" && w.word.length === board.length || w.axis === "col" && w.word.length === board[0].length; 116}; 117var Dictionary = { 118 load: async () => { 119 if (!import_localforage.default.supports(import_localforage.default.INDEXEDDB)) throw Error("load locally"); 120 import_localforage.default.config({ 121 driver: [ 122 import_localforage.default.INDEXEDDB, 123 import_localforage.default.WEBSQL, 124 import_localforage.default.LOCALSTORAGE 125 ], 126 name: "dictionary", 127 version: 4, 128 storeName: "dictionary" 129 }); 130 let words; 131 if (await shouldUpdateDictionary()) { 132 words = await (await fetch("/words.json")).json(); 133 await import_localforage.default.setItem("dictionary", words); 134 await import_localforage.default.setItem("dictionary-md5", words_default); 135 } else words = await import_localforage.default.getItem("dictionary") ?? []; 136 wordList = words; 137 const start = Date.now(); 138 dictionary = new Trie(); 139 letters = new Trie(); 140 words.forEach((w) => { 141 dictionary.insert(w, w); 142 letters.insert(sortLetters(w), w); 143 }); 144 return (Date.now() - start) / 1e3; 145 }, 146 findWords: (board, gameType, coords) => { 147 const rows = {}; 148 const cols = {}; 149 if (!coords) coords = board.flatMap((col, i) => col.map((row, j) => [i, j])); 150 for (const [i, j] of coords.filter((c) => c != null)) for (const axis of ["row", "col"]) { 151 const word = findWord(board, i, j, axis, gameType); 152 if (word.length) { 153 const coords = word.map((_, offset) => [i + (axis === "col" ? 0 : offset), j + (axis === "row" ? 0 : offset)]); 154 const s = wordToString({ word }); 155 const match = { 156 word, 157 coords, 158 axis, 159 ...scoreWord(word, gameType), 160 length: s.length,
161 alpha: s, 162 intersectingIds: [] 163 }; 164 if (axis === "row") rows[j] = (rows[j] ?? []).concat([match]); 165 else cols[i] = (cols[i] ?? []).concat([match]); 166 } 167 } 168 if (gameType !== "daily") { 169 removeOverlappingWords(rows); 170 removeOverlappingWords(cols); 171 } 172 let rowWords = Object.values(rows).flat(); 173 let colWords = Object.values(cols).flat(); 174 if (gameType === "daily") { 175 rowWords = rowWords.filter((w) => isFullLength(w, board)); 176 colWords = colWords.filter((w) => isFullLength(w, board)); 177 if (board.length === 1 && colWords.length === 1) rowWords = []; 178 else if (board[0]?.length === 1 && rowWords.length === 1) colWords = []; 179 } 180 const wordsByCoord = /* @__PURE__ */ new Map(); 181 for (const word of [...rowWords, ...colWords]) for (const c of word.coords) { 182 const key = coordToStr(c); 183 wordsByCoord.set(key, (wordsByCoord.get(key) ?? []).concat([word])); 184 } 185 const intersecting = new Set([...wordsByCoord.values()].filter((ws) => ws.length > 1).flat()); 186 const words = [...rowWords, ...colWords].sort((a, b) => { 187 if (intersecting.has(a) && intersecting.has(b)) return a.axis === "row" ? -1 : 1; 188 return a.coords[0][1] - b.coords[0][1]; 189 }); 190 const intersections = {}; 191 for (const [key, sharing] of wordsByCoord) { 192 if (sharing.length < 2) continue; 193 const coord = coordStr2Int(key); 194 const tile = board[coord[0]][coord[1]]; 195 const ordered = [...sharing].sort((a, b) => words.indexOf(a) - words.indexOf(b)); 196 const last = ordered.pop(); 197 for (const word of ordered) { 198 const intersectingId = getTileId(); 199 intersections[intersectingId] = { 200 tile, 201 coord 202 }; 203 const tileIdx = word.coords.findIndex((c) => coordToStr(c) === key); 204 word.word[tileIdx] = { 205 ...word.word[tileIdx], 206 id: intersectingId 207 }; 208 word.intersectingIds.push(intersectingId); 209 } 210 last.intersectingIds.push(tile.id); 211 } 212 return { 213 words, 214 intersections 215 }; 216 }, 217 boardHasWord: (board) => { 218 const key = sortLetters(board.flatMap((col) => col.flatMap((t) => [...t.letter.toLowerCase()])).join("")); 219 const q = [[letters.getNode(""), key]]; 220 while (q.length) { 221 const [node, key] = q.pop(); 222 if (node.terminal && [board.length, board[0].length].includes(node.value.length)) return node.value; 223 for (const [letter, child] of Object.entries(node.children)) { 224 const idx = key.indexOf(letter); 225 if (idx !== -1) q.push([child, key.slice(idx + 1)]); 226 } 227 } 228 }, 229 searchRegex: (search, lenRange) => { 230 const suggestions = []; 231 if (search.includes("(")) search = search.replaceAll("(", ""); 232 else if (search.includes("]")) search = search.replaceAll("]", "") + "$"; 233 else search = "^" + search; 234 let wildSearch = search.replaceAll("*", "[A-Za-z]"); 235 if (!/[A-Za-z]/.test(wildSearch)) return []; 236 try { 237 const re = new RegExp(wildSearch, "i"); 238 return wordList.filter((w) => re.test(w)).filter((w) => w.length >= lenRange[0] && w.length <= lenRange[1]).sort((a, b) => a.length - b.length).slice(0, 5); 239 } catch (err) { 240 return suggestions; 241 } 242 }, 243 searchTrie: (search, lenRange) => { 244 const w = dictionary.getNode(search.toLowerCase()); 245 let q = []; 246 let head = w; 247 let suggestions = []; 248 while (head && suggestions.length < 5) { 249 if (head.children) q = q.concat(Object.values(head.children) ?? []); 250 if (head.terminal && head.value && head.value.length >= lenRange[0] && head.value.length <= lenRange[1]) suggestions.push(head.value); 251 head = q.shift(); 252 } 253 return suggestions; 254 } 255}; 256if (typeof WorkerGlobalScope !== "undefined" && self instanceof WorkerGlobalScope) expose(Dictionary); 257//#endregion 258export { Dictionary }; 259 260//# sourceMappingURL=D8x9GurF.js.map
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.