scrabble-solver 2.16.6 → 2.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (293) hide show
  1. package/.github/workflows/bunx.yml +26 -2
  2. package/.github/workflows/npx.yml +26 -2
  3. package/.nx/workspace-data/d/server-process.json +3 -3
  4. package/.nx/workspace-data/file-map.json +441 -465
  5. package/.nx/workspace-data/lockfile-dependencies.hash +1 -1
  6. package/.nx/workspace-data/lockfile-nodes.hash +1 -1
  7. package/.nx/workspace-data/nx_files.nxt +0 -0
  8. package/.nx/workspace-data/parsed-lock-file.dependencies.json +2671 -2121
  9. package/.nx/workspace-data/parsed-lock-file.nodes.json +3846 -5277
  10. package/.nx/workspace-data/project-graph.json +7089 -7924
  11. package/.nx/workspace-data/source-maps.json +351 -255
  12. package/.oxlintrc.json +6 -0
  13. package/CLAUDE.md +25 -20
  14. package/README.md +9 -0
  15. package/bun.lock +1054 -2897
  16. package/bunfig.toml +6 -0
  17. package/cypress/e2e/app.spec.cy.ts +4 -4
  18. package/cypress/e2e/features/solver-paths.ts +66 -0
  19. package/cypress/e2e/features.spec.cy.ts +1 -0
  20. package/cypress/support/lib/actions.ts +28 -9
  21. package/cypress.config.ts +7 -0
  22. package/lerna.json +1 -1
  23. package/nx.json +3 -1
  24. package/package.json +18 -18
  25. package/packages/configs/package.json +4 -4
  26. package/packages/constants/package.json +2 -2
  27. package/packages/dictionaries/README.md +1 -1
  28. package/packages/dictionaries/build/Dictionaries.d.ts +2 -2
  29. package/packages/dictionaries/build/Dictionaries.js +6 -6
  30. package/packages/dictionaries/build/lib/DiskCache.d.ts +11 -4
  31. package/packages/dictionaries/build/lib/DiskCache.js +27 -10
  32. package/packages/dictionaries/build/lib/LayeredCache.d.ts +4 -4
  33. package/packages/dictionaries/build/lib/LayeredCache.js +3 -3
  34. package/packages/dictionaries/build/lib/MemoryCache.d.ts +4 -4
  35. package/packages/dictionaries/build/lib/MemoryCache.js +2 -2
  36. package/packages/dictionaries/build/lib/createCacheTimestampComparator.d.ts +2 -2
  37. package/packages/dictionaries/build/lib/downloadDictionary.d.ts +2 -2
  38. package/packages/dictionaries/build/lib/downloadDictionary.js +4 -3
  39. package/packages/dictionaries/build/lib/getDictionaryFilepath.d.ts +3 -1
  40. package/packages/dictionaries/build/lib/getDictionaryFilepath.js +8 -3
  41. package/packages/dictionaries/package.json +8 -7
  42. package/packages/dictionaries/src/Dictionaries.ts +12 -12
  43. package/packages/dictionaries/src/lib/DiskCache.test.ts +85 -0
  44. package/packages/dictionaries/src/lib/DiskCache.ts +34 -14
  45. package/packages/dictionaries/src/lib/LayeredCache.ts +7 -7
  46. package/packages/dictionaries/src/lib/MemoryCache.ts +6 -6
  47. package/packages/dictionaries/src/lib/createCacheTimestampComparator.ts +2 -2
  48. package/packages/dictionaries/src/lib/downloadDictionary.ts +5 -4
  49. package/packages/dictionaries/src/lib/getDictionaryFilepath.ts +7 -2
  50. package/packages/gaddag/build/Gaddag.d.ts +39 -0
  51. package/packages/gaddag/build/Gaddag.js +128 -0
  52. package/packages/gaddag/build/buildGaddag.d.ts +10 -0
  53. package/packages/gaddag/build/buildGaddag.js +360 -0
  54. package/packages/gaddag/build/constants.d.ts +12 -0
  55. package/packages/gaddag/build/constants.js +15 -0
  56. package/packages/gaddag/build/index.d.ts +3 -0
  57. package/packages/gaddag/build/index.js +13 -0
  58. package/packages/logger/package.json +2 -2
  59. package/packages/scrabble-solver/.next/BUILD_ID +1 -1
  60. package/packages/scrabble-solver/.next/build-manifest.json +17 -17
  61. package/packages/scrabble-solver/.next/cache/.previewinfo +1 -1
  62. package/packages/scrabble-solver/.next/cache/.rscinfo +1 -1
  63. package/packages/scrabble-solver/.next/cache/.tsbuildinfo +1 -1
  64. package/packages/scrabble-solver/.next/cache/webpack/client-production/0.pack +0 -0
  65. package/packages/scrabble-solver/.next/cache/webpack/client-production/index.pack +0 -0
  66. package/packages/scrabble-solver/.next/cache/webpack/client-production/index.pack.old +0 -0
  67. package/packages/scrabble-solver/.next/cache/webpack/edge-server-production/index.pack +0 -0
  68. package/packages/scrabble-solver/.next/cache/webpack/edge-server-production/index.pack.old +0 -0
  69. package/packages/scrabble-solver/.next/cache/webpack/server-production/0.pack +0 -0
  70. package/packages/scrabble-solver/.next/cache/webpack/server-production/index.pack +0 -0
  71. package/packages/scrabble-solver/.next/cache/webpack/server-production/index.pack.old +0 -0
  72. package/packages/scrabble-solver/.next/diagnostics/framework.json +1 -1
  73. package/packages/scrabble-solver/.next/next-minimal-server.js.nft.json +1 -1
  74. package/packages/scrabble-solver/.next/next-server.js.nft.json +1 -1
  75. package/packages/scrabble-solver/.next/prerender-manifest.json +7 -4
  76. package/packages/scrabble-solver/.next/required-server-files.js +29 -10
  77. package/packages/scrabble-solver/.next/required-server-files.json +29 -10
  78. package/packages/scrabble-solver/.next/routes-manifest.json +1 -1
  79. package/packages/scrabble-solver/.next/server/chunks/129.js +1 -0
  80. package/packages/scrabble-solver/.next/server/chunks/30.js +2 -2
  81. package/packages/scrabble-solver/.next/server/chunks/318.js +3 -3
  82. package/packages/scrabble-solver/.next/server/chunks/392.js +1 -1
  83. package/packages/scrabble-solver/.next/server/chunks/671.js +1 -1
  84. package/packages/scrabble-solver/.next/server/chunks/712.js +1 -1
  85. package/packages/scrabble-solver/.next/server/chunks/785.js +1 -0
  86. package/packages/scrabble-solver/.next/server/chunks/791.js +3 -3
  87. package/packages/scrabble-solver/.next/server/middleware-build-manifest.js +1 -1
  88. package/packages/scrabble-solver/.next/server/pages/404.html +1 -1
  89. package/packages/scrabble-solver/.next/server/pages/500.html +1 -1
  90. package/packages/scrabble-solver/.next/server/pages/_app.js +1 -1
  91. package/packages/scrabble-solver/.next/server/pages/_app.js.nft.json +1 -1
  92. package/packages/scrabble-solver/.next/server/pages/_document.js.nft.json +1 -1
  93. package/packages/scrabble-solver/.next/server/pages/_error.js +1 -1
  94. package/packages/scrabble-solver/.next/server/pages/_error.js.nft.json +1 -1
  95. package/packages/scrabble-solver/.next/server/pages/api/dictionary/[locale]/[word].js +1 -1
  96. package/packages/scrabble-solver/.next/server/pages/api/dictionary/[locale]/[word].js.nft.json +1 -1
  97. package/packages/scrabble-solver/.next/server/pages/api/dictionary/[locale].js +1 -1
  98. package/packages/scrabble-solver/.next/server/pages/api/dictionary/[locale].js.nft.json +1 -1
  99. package/packages/scrabble-solver/.next/server/pages/api/solve.js +1 -1
  100. package/packages/scrabble-solver/.next/server/pages/api/solve.js.nft.json +1 -1
  101. package/packages/scrabble-solver/.next/server/pages/api/verify.js +1 -1
  102. package/packages/scrabble-solver/.next/server/pages/api/verify.js.nft.json +1 -1
  103. package/packages/scrabble-solver/.next/server/pages/api/visit.js +1 -1
  104. package/packages/scrabble-solver/.next/server/pages/api/visit.js.nft.json +1 -1
  105. package/packages/scrabble-solver/.next/server/pages/index.html +1 -1
  106. package/packages/scrabble-solver/.next/server/pages/index.js +1 -1
  107. package/packages/scrabble-solver/.next/server/pages/index.js.nft.json +1 -1
  108. package/packages/scrabble-solver/.next/server/pages/index.json +1 -1
  109. package/packages/scrabble-solver/.next/server/pages/not-found.html +1 -1
  110. package/packages/scrabble-solver/.next/server/pages/not-found.js.nft.json +1 -1
  111. package/packages/scrabble-solver/.next/server/pages-manifest.json +1 -1
  112. package/packages/scrabble-solver/.next/server/webpack-runtime.js +1 -1
  113. package/packages/scrabble-solver/.next/static/{js6-w0PwySs2PyOSeCYfi → OLE8_ZInlGH7ENU0NIOpf}/_buildManifest.js +1 -1
  114. package/packages/scrabble-solver/.next/static/chunks/583.7a46807be14c377e.js +1 -0
  115. package/packages/scrabble-solver/.next/static/chunks/830.661816bf0de8c2f1.js +1 -0
  116. package/packages/scrabble-solver/.next/static/chunks/framework-3cf15b8041c59dd3.js +1 -0
  117. package/packages/scrabble-solver/.next/static/chunks/main-5b999f3f24ebfa84.js +5 -0
  118. package/packages/scrabble-solver/.next/static/chunks/pages/_app-7024e7a27ffbb2fa.js +7 -0
  119. package/packages/scrabble-solver/.next/static/chunks/pages/{index-bdf5e1e44cea16f6.js → index-8b398b0a5d870773.js} +1 -1
  120. package/packages/scrabble-solver/.next/static/chunks/webpack-3943d624bbb47a64.js +1 -0
  121. package/packages/scrabble-solver/.next/static/css/aedeaada218d7280.css +2 -0
  122. package/packages/scrabble-solver/.next/trace +21 -21
  123. package/packages/scrabble-solver/.next/trace-build +1 -1
  124. package/packages/scrabble-solver/.next/types/cache-life.d.ts +1 -0
  125. package/packages/scrabble-solver/.next/types/root-params.d.ts +3 -0
  126. package/packages/scrabble-solver/next-env.d.ts +1 -0
  127. package/packages/scrabble-solver/next.config.js +0 -1
  128. package/packages/scrabble-solver/package.json +19 -19
  129. package/packages/scrabble-solver/public/service-worker.js +2 -2
  130. package/packages/scrabble-solver/public/service-worker.js.map +1 -1
  131. package/packages/scrabble-solver/src/components/Board/components/Cell/Cell.tsx +4 -1
  132. package/packages/scrabble-solver/src/components/Board/hooks/useGrid.ts +17 -6
  133. package/packages/scrabble-solver/src/components/Dictionary/Dictionary.module.scss +7 -22
  134. package/packages/scrabble-solver/src/components/Dictionary/Dictionary.tsx +1 -8
  135. package/packages/scrabble-solver/src/components/Results/Result.tsx +0 -3
  136. package/packages/scrabble-solver/src/components/Results/Results.module.scss +0 -1
  137. package/packages/scrabble-solver/src/components/Results/Results.tsx +10 -2
  138. package/packages/scrabble-solver/src/components/Results/types.ts +3 -3
  139. package/packages/scrabble-solver/src/components/Solver/Solver.tsx +4 -3
  140. package/packages/scrabble-solver/src/components/Tooltip/useTooltip.ts +1 -1
  141. package/packages/scrabble-solver/src/pages/api/dictionary/[locale]/[word].ts +2 -2
  142. package/packages/scrabble-solver/src/pages/api/dictionary/[locale]/index.ts +80 -3
  143. package/packages/scrabble-solver/src/pages/api/solve.ts +2 -2
  144. package/packages/scrabble-solver/src/pages/api/verify.ts +12 -3
  145. package/packages/scrabble-solver/src/sdk/solve.ts +13 -7
  146. package/packages/scrabble-solver/src/sdk/verify.ts +12 -6
  147. package/packages/scrabble-solver/src/service-worker/appShell.test.ts +86 -0
  148. package/packages/scrabble-solver/src/service-worker/appShell.ts +39 -0
  149. package/packages/scrabble-solver/src/service-worker/index.ts +4 -5
  150. package/packages/scrabble-solver/src/serviceWorkerManager.ts +1 -18
  151. package/packages/scrabble-solver/src/solver-worker/client.test.ts +151 -0
  152. package/packages/scrabble-solver/src/solver-worker/client.ts +106 -0
  153. package/packages/scrabble-solver/src/solver-worker/dictionaries/constants.ts +9 -0
  154. package/packages/scrabble-solver/src/solver-worker/dictionaries/getDictionary.ts +21 -0
  155. package/packages/scrabble-solver/src/solver-worker/dictionaries/index.ts +2 -0
  156. package/packages/scrabble-solver/src/solver-worker/dictionaries/revalidateDictionary.test.ts +199 -0
  157. package/packages/scrabble-solver/src/solver-worker/dictionaries/revalidateDictionary.ts +86 -0
  158. package/packages/scrabble-solver/src/solver-worker/dictionaries/revalidatedAt.ts +43 -0
  159. package/packages/scrabble-solver/src/solver-worker/getGaddag.test.ts +109 -0
  160. package/packages/scrabble-solver/src/solver-worker/getGaddag.ts +62 -0
  161. package/packages/scrabble-solver/src/solver-worker/index.ts +1 -0
  162. package/packages/scrabble-solver/src/solver-worker/index.worker.ts +124 -0
  163. package/packages/scrabble-solver/src/solver-worker/messages.ts +20 -0
  164. package/packages/scrabble-solver/src/state/index.ts +1 -0
  165. package/packages/scrabble-solver/src/state/sagas.ts +19 -9
  166. package/packages/scrabble-solver/src/state/useTypedStore.ts +6 -0
  167. package/packages/scrabble-solver/src/types/api.ts +1 -2
  168. package/packages/scrabble-solver/tsconfig.json +4 -0
  169. package/packages/scrabble-solver/tsconfig.tsbuildinfo +1 -1
  170. package/packages/solver/README.md +24 -0
  171. package/packages/solver/benchmarks/index.ts +15 -0
  172. package/packages/solver/benchmarks/lib.ts +31 -0
  173. package/packages/solver/benchmarks/renderChart.ts +165 -0
  174. package/packages/solver/benchmarks/results/chart.svg +65 -0
  175. package/packages/solver/benchmarks/runBenchmarks.ts +66 -0
  176. package/packages/solver/benchmarks/scenarios.ts +64 -0
  177. package/packages/solver/benchmarks/types.ts +16 -0
  178. package/packages/solver/benchmarks/updateReadme.ts +53 -0
  179. package/packages/solver/build/MoveGenerator.d.ts +116 -0
  180. package/packages/solver/build/MoveGenerator.js +686 -0
  181. package/packages/solver/build/index.d.ts +0 -13
  182. package/packages/solver/build/index.js +1 -27
  183. package/packages/solver/build/solve.d.ts +2 -2
  184. package/packages/solver/build/solve.js +3 -19
  185. package/packages/solver/package.json +8 -7
  186. package/packages/solver/src/MoveGenerator.test.ts +1009 -0
  187. package/packages/solver/src/MoveGenerator.ts +926 -0
  188. package/packages/solver/src/ReferenceSolver.ts +401 -0
  189. package/packages/solver/src/index.ts +0 -13
  190. package/packages/solver/src/solve.test.ts +21 -21
  191. package/packages/solver/src/solve.ts +4 -22
  192. package/packages/solver/tsconfig.json +1 -1
  193. package/packages/types/build/Cell.d.ts +1 -0
  194. package/packages/types/build/Cell.js +3 -0
  195. package/packages/types/build/Result.d.ts +3 -2
  196. package/packages/types/build/Result.js +11 -6
  197. package/packages/types/build/ResultJson.d.ts +5 -4
  198. package/packages/types/build/index.d.ts +0 -6
  199. package/packages/types/build/index.js +1 -9
  200. package/packages/types/build/readResultCells.d.ts +5 -0
  201. package/packages/types/build/readResultCells.js +75 -0
  202. package/packages/types/package.json +5 -4
  203. package/packages/types/src/Cell.ts +4 -0
  204. package/packages/types/src/Result.ts +15 -6
  205. package/packages/types/src/ResultJson.ts +5 -5
  206. package/packages/types/src/index.ts +0 -6
  207. package/packages/types/src/readResultCells.test.ts +140 -0
  208. package/packages/types/src/readResultCells.ts +90 -0
  209. package/packages/word-definitions/package.json +3 -3
  210. package/packages/word-lists/package.json +4 -4
  211. package/packages/scrabble-solver/.next/static/chunks/framework-a23f7f643b59a2ca.js +0 -1
  212. package/packages/scrabble-solver/.next/static/chunks/main-92448bb08bb6bf1f.js +0 -5
  213. package/packages/scrabble-solver/.next/static/chunks/pages/_app-4ae86f006f6b9fe7.js +0 -7
  214. package/packages/scrabble-solver/.next/static/chunks/webpack-1a7a166b34ed8d24.js +0 -1
  215. package/packages/scrabble-solver/.next/static/css/0af35adb4bab56f0.css +0 -2
  216. package/packages/scrabble-solver/src/sdk/getDictionary.ts +0 -9
  217. package/packages/scrabble-solver/src/service-worker/average.ts +0 -7
  218. package/packages/scrabble-solver/src/service-worker/dictionaries/constants.ts +0 -5
  219. package/packages/scrabble-solver/src/service-worker/dictionaries/getDictionary.ts +0 -20
  220. package/packages/scrabble-solver/src/service-worker/dictionaries/index.ts +0 -2
  221. package/packages/scrabble-solver/src/service-worker/dictionaries/revalidateDictionary.ts +0 -33
  222. package/packages/scrabble-solver/src/service-worker/getTrie.ts +0 -24
  223. package/packages/scrabble-solver/src/service-worker/routeSolveRequests.ts +0 -91
  224. package/packages/scrabble-solver/src/service-worker/routeVerifyRequests.ts +0 -37
  225. package/packages/solver/build/areDigraphsValid.d.ts +0 -2
  226. package/packages/solver/build/areDigraphsValid.js +0 -17
  227. package/packages/solver/build/fillPattern.d.ts +0 -6
  228. package/packages/solver/build/fillPattern.js +0 -52
  229. package/packages/solver/build/generateEndIndices.d.ts +0 -2
  230. package/packages/solver/build/generateEndIndices.js +0 -17
  231. package/packages/solver/build/generateHorizontalPatterns.d.ts +0 -2
  232. package/packages/solver/build/generateHorizontalPatterns.js +0 -16
  233. package/packages/solver/build/generatePattern.d.ts +0 -7
  234. package/packages/solver/build/generatePattern.js +0 -20
  235. package/packages/solver/build/generatePatterns.d.ts +0 -2
  236. package/packages/solver/build/generatePatterns.js +0 -11
  237. package/packages/solver/build/generateStartIndices.d.ts +0 -2
  238. package/packages/solver/build/generateStartIndices.js +0 -16
  239. package/packages/solver/build/generateVectors.d.ts +0 -7
  240. package/packages/solver/build/generateVectors.js +0 -7
  241. package/packages/solver/build/generateVerticalPatterns.d.ts +0 -2
  242. package/packages/solver/build/generateVerticalPatterns.js +0 -16
  243. package/packages/solver/build/getCellsScore.d.ts +0 -2
  244. package/packages/solver/build/getCellsScore.js +0 -18
  245. package/packages/solver/build/getPatternHash.d.ts +0 -2
  246. package/packages/solver/build/getPatternHash.js +0 -14
  247. package/packages/solver/build/getPatternScore.d.ts +0 -2
  248. package/packages/solver/build/getPatternScore.js +0 -22
  249. package/packages/solver/build/getUniquePatterns.d.ts +0 -2
  250. package/packages/solver/build/getUniquePatterns.js +0 -17
  251. package/packages/solver/src/areDigraphsValid.ts +0 -18
  252. package/packages/solver/src/fillPattern.test.ts +0 -107
  253. package/packages/solver/src/fillPattern.ts +0 -68
  254. package/packages/solver/src/generateEndIndices.test.ts +0 -23
  255. package/packages/solver/src/generateEndIndices.ts +0 -19
  256. package/packages/solver/src/generateHorizontalPatterns.test.ts +0 -31
  257. package/packages/solver/src/generateHorizontalPatterns.ts +0 -15
  258. package/packages/solver/src/generatePattern.ts +0 -33
  259. package/packages/solver/src/generatePatterns.test.ts +0 -13
  260. package/packages/solver/src/generatePatterns.ts +0 -11
  261. package/packages/solver/src/generateStartIndices.test.ts +0 -19
  262. package/packages/solver/src/generateStartIndices.ts +0 -17
  263. package/packages/solver/src/generateVectors.test.ts +0 -12
  264. package/packages/solver/src/generateVectors.ts +0 -10
  265. package/packages/solver/src/generateVerticalPatterns.test.ts +0 -32
  266. package/packages/solver/src/generateVerticalPatterns.ts +0 -15
  267. package/packages/solver/src/getCellsScore.ts +0 -21
  268. package/packages/solver/src/getPatternHash.test.ts +0 -17
  269. package/packages/solver/src/getPatternHash.ts +0 -12
  270. package/packages/solver/src/getPatternScore.test.ts +0 -204
  271. package/packages/solver/src/getPatternScore.ts +0 -23
  272. package/packages/solver/src/getUniquePatterns.ts +0 -19
  273. package/packages/types/build/CollisionJson.d.ts +0 -2
  274. package/packages/types/build/CollisionJson.js +0 -2
  275. package/packages/types/build/FinalPattern.d.ts +0 -6
  276. package/packages/types/build/FinalPattern.js +0 -14
  277. package/packages/types/build/HorizontalPattern.d.ts +0 -5
  278. package/packages/types/build/HorizontalPattern.js +0 -34
  279. package/packages/types/build/Pattern.d.ts +0 -20
  280. package/packages/types/build/Pattern.js +0 -50
  281. package/packages/types/build/PatternJson.d.ts +0 -6
  282. package/packages/types/build/PatternJson.js +0 -2
  283. package/packages/types/build/VerticalPattern.d.ts +0 -5
  284. package/packages/types/build/VerticalPattern.js +0 -34
  285. package/packages/types/src/CollisionJson.ts +0 -3
  286. package/packages/types/src/FinalPattern.ts +0 -14
  287. package/packages/types/src/HorizontalPattern.ts +0 -37
  288. package/packages/types/src/Pattern.ts +0 -71
  289. package/packages/types/src/PatternJson.ts +0 -7
  290. package/packages/types/src/VerticalPattern.ts +0 -37
  291. /package/packages/scrabble-solver/.next/static/{js6-w0PwySs2PyOSeCYfi → OLE8_ZInlGH7ENU0NIOpf}/_ssgManifest.js +0 -0
  292. /package/packages/scrabble-solver/src/{service-worker → solver-worker}/dictionaries/expirationManager.ts +0 -0
  293. /package/packages/scrabble-solver/src/{service-worker → solver-worker}/dictionaries/getDictionaryUrl.ts +0 -0
@@ -1,14 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getPatternHash = void 0;
4
- const getPatternHash = (pattern) => {
5
- return pattern.cells
6
- .filter((cell) => cell.isEmpty)
7
- .map((cell) => {
8
- const blank = cell.tile.isBlank ? '!' : '';
9
- const tile = cell.tile.character + blank;
10
- return [cell.x, cell.y, tile].join(',');
11
- })
12
- .join('-');
13
- };
14
- exports.getPatternHash = getPatternHash;
@@ -1,2 +0,0 @@
1
- import { type Config, type Pattern } from '@scrabble-solver/types';
2
- export declare const getPatternScore: (config: Config, pattern: Pattern) => number;
@@ -1,22 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getPatternScore = void 0;
4
- const types_1 = require("@scrabble-solver/types");
5
- const getCellsScore_1 = require("./getCellsScore");
6
- const getPatternScore = (config, pattern) => {
7
- const areAllTilesUsed = pattern.getEmptyCellsCount() === config.rackSize;
8
- const baseScore = (0, getCellsScore_1.getCellsScore)(config, pattern.cells);
9
- const collisionsScore = pattern
10
- .getCollisions()
11
- .reduce((sum, collision) => sum + (0, getCellsScore_1.getCellsScore)(config, collision.cells), 0);
12
- if (areAllTilesUsed) {
13
- if ((0, types_1.isScoreBingo)(config.bingo)) {
14
- return baseScore + collisionsScore + config.bingo.score;
15
- }
16
- if ((0, types_1.isMultiplierBingo)(config.bingo)) {
17
- return baseScore * config.bingo.multiplier + collisionsScore;
18
- }
19
- }
20
- return baseScore + collisionsScore;
21
- };
22
- exports.getPatternScore = getPatternScore;
@@ -1,2 +0,0 @@
1
- import { type Pattern } from '@scrabble-solver/types';
2
- export declare const getUniquePatterns: (patterns: Pattern[]) => Pattern[];
@@ -1,17 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getUniquePatterns = void 0;
4
- const getPatternHash_1 = require("./getPatternHash");
5
- const getUniquePatterns = (patterns) => {
6
- const hashes = new Set();
7
- const uniquePatterns = [];
8
- for (const pattern of patterns) {
9
- const hash = (0, getPatternHash_1.getPatternHash)(pattern);
10
- if (!hashes.has(hash)) {
11
- hashes.add(hash);
12
- uniquePatterns.push(pattern);
13
- }
14
- }
15
- return uniquePatterns;
16
- };
17
- exports.getUniquePatterns = getUniquePatterns;
@@ -1,18 +0,0 @@
1
- import { type Config, type Pattern } from '@scrabble-solver/types';
2
-
3
- export const areDigraphsValid = (config: Config, pattern: Pattern): boolean => {
4
- const { twoCharacterTiles } = config;
5
- const { cells } = pattern;
6
-
7
- for (let index = 0; index < cells.length - 1; ++index) {
8
- const current = cells[index];
9
- const next = cells[index + 1];
10
- const digraphCandidate = current.tile.character + next.tile.character;
11
-
12
- if (twoCharacterTiles.includes(digraphCandidate)) {
13
- return false;
14
- }
15
- }
16
-
17
- return true;
18
- };
@@ -1,107 +0,0 @@
1
- import { type Trie } from '@kamilmielnik/trie';
2
- import { getConfig } from '@scrabble-solver/configs';
3
- import { dictionaries } from '@scrabble-solver/dictionaries';
4
- import { Board, Cell, FinalPattern, Game, Locale, type Pattern, Tile, VerticalPattern } from '@scrabble-solver/types';
5
-
6
- import { fillPattern, fillPatternRecursive } from './fillPattern';
7
-
8
- const board = Board.fromStringArray([' t ', 'do ', ' ']);
9
- const locale = Locale.PL_PL;
10
- const config = getConfig(Game.Literaki, locale);
11
-
12
- describe('fillPattern', () => {
13
- let trie: Trie | undefined;
14
-
15
- beforeAll(() => {
16
- return dictionaries.get(locale).then((loadedTrie) => {
17
- trie = loadedTrie;
18
- });
19
- });
20
-
21
- it('fills patterns', () => {
22
- const pattern = new VerticalPattern(board, [
23
- new Cell({ x: 0, y: 0 }),
24
- new Cell({ x: 0, y: 1, tile: new Tile({ character: 'd', isBlank: false }) }),
25
- new Cell({ x: 0, y: 2 }),
26
- ]);
27
- const tiles = [
28
- new Tile({ character: 'o', isBlank: false }),
29
- new Tile({ character: 'a', isBlank: false }),
30
- new Tile({ character: 'd', isBlank: false }),
31
- ];
32
- const filledPatterns = fillPattern(trie!, config, pattern, tiles);
33
-
34
- expect(filledPatterns.length).toBe(1);
35
- });
36
-
37
- it('fills patterns with blanks', () => {
38
- const pattern = new VerticalPattern(board, [board.rows[0][1], board.rows[1][1], board.rows[2][1]]);
39
- const tiles = [new Tile({ character: ' ', isBlank: true }), new Tile({ character: 'ó', isBlank: false })];
40
- const filledPatterns = fillPattern(trie!, config, pattern, tiles);
41
-
42
- expect(filledPatterns.map(String)).toEqual([
43
- 'toć',
44
- 'tog',
45
- 'toi',
46
- 'tok',
47
- 'tom',
48
- 'ton',
49
- 'toń',
50
- 'top',
51
- 'tor',
52
- 'tos',
53
- 'toy',
54
- 'toż',
55
- ]);
56
- });
57
-
58
- it('does not modify filled patterns', () => {
59
- const pattern = new FinalPattern(
60
- new VerticalPattern(board, [
61
- new Cell({ x: 0, y: 0, isEmpty: false, tile: new Tile({ character: 'o', isBlank: false }) }),
62
- new Cell({ x: 0, y: 1, isEmpty: false, tile: new Tile({ character: 'k', isBlank: false }) }),
63
- new Cell({ x: 0, y: 2, isEmpty: false, tile: new Tile({ character: 'o', isBlank: false }) }),
64
- ]),
65
- );
66
- const tiles = [new Tile({ character: 'ń', isBlank: false })];
67
- const filledPatterns = fillPattern(trie!, config, pattern, tiles);
68
-
69
- expect(filledPatterns.length).toBe(1);
70
- expect(filledPatterns[0]).toEqual(pattern);
71
- });
72
-
73
- it('does not accept non-placeable filled patterns', () => {
74
- const pattern = new VerticalPattern(board, [
75
- new Cell({ x: 0, y: 0, isEmpty: false, tile: new Tile({ character: 'd', isBlank: false }) }),
76
- new Cell({ x: 0, y: 1, isEmpty: false, tile: new Tile({ character: 'd', isBlank: false }) }),
77
- new Cell({ x: 0, y: 2, isEmpty: false, tile: new Tile({ character: 'd', isBlank: false }) }),
78
- ]);
79
- const tiles = [new Tile({ character: 'ń', isBlank: false })];
80
- const filledPatterns = fillPattern(trie!, config, pattern, tiles);
81
-
82
- expect(filledPatterns.length).toBe(0);
83
- });
84
- });
85
-
86
- describe('fillPatternRecursive', () => {
87
- let trie: Trie | undefined;
88
-
89
- beforeAll(() => {
90
- return dictionaries.get(locale).then((loadedTrie) => {
91
- trie = loadedTrie;
92
- });
93
- });
94
-
95
- it('checks collisions', () => {
96
- const pattern = new VerticalPattern(board, [
97
- new Cell({ x: 2, y: 0, isEmpty: true, tile: new Tile({ character: 'k', isBlank: false }) }),
98
- new Cell({ x: 2, y: 1, isEmpty: true, tile: new Tile({ character: 'o', isBlank: false }) }),
99
- new Cell({ x: 2, y: 2, isEmpty: true, tile: new Tile({ character: 't', isBlank: false }) }),
100
- ]);
101
- const results: Pattern[] = [];
102
- const tiles = [new Tile({ character: 'ń', isBlank: false })];
103
- fillPatternRecursive(results, trie!, config, pattern, pattern.toString(), tiles);
104
-
105
- expect(results.length).toBe(0);
106
- });
107
- });
@@ -1,68 +0,0 @@
1
- /* eslint-disable max-params, max-statements */
2
- import { type Trie } from '@kamilmielnik/trie';
3
- import { EMPTY_CELL } from '@scrabble-solver/constants';
4
- import { type Config, FinalPattern, type Pattern, type Tile } from '@scrabble-solver/types';
5
-
6
- export const fillPattern = (trie: Trie, config: Config, pattern: Pattern, tiles: Tile[]): Pattern[] => {
7
- if (pattern.getEmptyCellsCount() > tiles.length) {
8
- return [];
9
- }
10
-
11
- const results: Pattern[] = [];
12
-
13
- fillPatternRecursive(results, trie, config, pattern, pattern.toString(), tiles);
14
-
15
- return results;
16
- };
17
-
18
- export const fillPatternRecursive = (
19
- /** gets mutated when this function is called */
20
- results: Pattern[],
21
- trie: Trie,
22
- config: Config,
23
- pattern: Pattern,
24
- word: string,
25
- tiles: Tile[],
26
- ): void => {
27
- const indexOfFirstCellWithoutTile = pattern.getIndexOfFirstCellWithoutTile();
28
-
29
- if (indexOfFirstCellWithoutTile === -1) {
30
- if (trie.has(word) && pattern.getCollisions().every((collision) => trie.has(collision.toString()))) {
31
- results.push(new FinalPattern(pattern.clone()));
32
- }
33
-
34
- return;
35
- }
36
-
37
- for (let index = 0; index < tiles.length; ++index) {
38
- const tile = tiles[index];
39
- const previousTile = pattern.cells[indexOfFirstCellWithoutTile].tile;
40
-
41
- pattern.cells[indexOfFirstCellWithoutTile].tile = tile;
42
-
43
- const indexOfNextCellWithoutTile = pattern.getIndexOfFirstCellWithoutTile();
44
- const indexOfFirstEmptyLetter = word.indexOf(EMPTY_CELL);
45
- const prefix = word.substring(0, indexOfFirstEmptyLetter);
46
- const suffix = word.substring(indexOfFirstEmptyLetter + 1);
47
- const characters = tile.isBlank ? config.alphabet : [tile.character];
48
-
49
- for (const character of characters) {
50
- const newWordPrefix = prefix + character;
51
- const newWord = newWordPrefix + suffix;
52
-
53
- tile.character = character;
54
-
55
- if (indexOfNextCellWithoutTile === -1) {
56
- if (trie.has(newWord) && pattern.getCollisions().every((collision) => trie.has(collision.toString()))) {
57
- results.push(new FinalPattern(pattern.clone()));
58
- }
59
- } else if (trie.hasPrefix(newWordPrefix)) {
60
- tiles.splice(index, 1);
61
- fillPatternRecursive(results, trie, config, pattern, newWord, tiles);
62
- tiles.splice(index, 0, tile);
63
- }
64
- }
65
-
66
- pattern.cells[indexOfFirstCellWithoutTile].tile = previousTile;
67
- }
68
- };
@@ -1,23 +0,0 @@
1
- import { type Cell } from '@scrabble-solver/types';
2
-
3
- import { generateEndIndices } from './generateEndIndices';
4
-
5
- describe('generateEndIndices', () => {
6
- const emptyCell: Cell = { hasTile: () => false } as Cell;
7
- const filledCell: Cell = { hasTile: () => true } as Cell;
8
-
9
- it('returns empty array when no cells given', () => {
10
- const cells: Cell[] = [];
11
- expect(generateEndIndices(cells, 0).length).toBe(0);
12
- });
13
-
14
- it('finds indices where a new word can end - XXOOOX', () => {
15
- const cells = [filledCell, filledCell, emptyCell, emptyCell, emptyCell, filledCell];
16
- expect(generateEndIndices(cells, 3)).toEqual([5]);
17
- });
18
-
19
- it('finds indices where a new word can end - XXOOOXO', () => {
20
- const cells = [filledCell, filledCell, emptyCell, emptyCell, emptyCell, filledCell, emptyCell];
21
- expect(generateEndIndices(cells, 3)).toEqual([5, 6]);
22
- });
23
- });
@@ -1,19 +0,0 @@
1
- import { type Cell } from '@scrabble-solver/types';
2
-
3
- export const generateEndIndices = (cells: Cell[], startIndex: number): number[] => {
4
- if (cells.length === 0) {
5
- return [];
6
- }
7
-
8
- const endIndices: number[] = [];
9
-
10
- for (let endIndex = startIndex + 1; endIndex < cells.length - 1; ++endIndex) {
11
- if (!cells[endIndex + 1].hasTile()) {
12
- endIndices.push(endIndex);
13
- }
14
- }
15
-
16
- endIndices.push(cells.length - 1);
17
-
18
- return endIndices;
19
- };
@@ -1,31 +0,0 @@
1
- import { EMPTY_CELL } from '@scrabble-solver/constants';
2
- import { Board, type Config } from '@scrabble-solver/types';
3
-
4
- import { generateHorizontalPatterns } from './generateHorizontalPatterns';
5
-
6
- const board = Board.fromStringArray([' t ', 'do ', ' ']);
7
-
8
- const config = {
9
- boardHeight: 3,
10
- boardWidth: 3,
11
- rackSize: 7,
12
- } as Config;
13
-
14
- describe('generateHorizontalPatterns', () => {
15
- it('generates some horizontal patterns', () => {
16
- expect(generateHorizontalPatterns(config, board).length).toBeGreaterThan(0);
17
- });
18
-
19
- it('generates proper horizontal patterns', () => {
20
- const horizontal = generateHorizontalPatterns(config, board);
21
- expect(horizontal.map(({ cells }) => cells.map(String))).toEqual([
22
- [EMPTY_CELL, 't'],
23
- [EMPTY_CELL, 't', EMPTY_CELL],
24
- ['t', EMPTY_CELL],
25
- ['d', 'o', EMPTY_CELL],
26
- [EMPTY_CELL, EMPTY_CELL],
27
- [EMPTY_CELL, EMPTY_CELL, EMPTY_CELL],
28
- [EMPTY_CELL, EMPTY_CELL],
29
- ]);
30
- });
31
- });
@@ -1,15 +0,0 @@
1
- import { type Board, type Config, HorizontalPattern, type Pattern } from '@scrabble-solver/types';
2
-
3
- import { generatePattern } from './generatePattern';
4
- import { generateVectors } from './generateVectors';
5
-
6
- export const generateHorizontalPatterns = (config: Config, board: Board): Pattern[] => {
7
- const getNthVector = (index: number) => board.getRow(index);
8
- const vectorsCount = config.boardHeight;
9
- const horizontalVectors = generateVectors({ getNthVector, vectorsCount });
10
- const horizontalPatterns = horizontalVectors.flatMap((cells) => {
11
- return generatePattern({ board, config, PatternModel: HorizontalPattern, cells });
12
- });
13
-
14
- return horizontalPatterns;
15
- };
@@ -1,33 +0,0 @@
1
- import { type Board, type Cell, type Config, type Pattern } from '@scrabble-solver/types';
2
-
3
- import { generateEndIndices } from './generateEndIndices';
4
- import { generateStartIndices } from './generateStartIndices';
5
-
6
- export const generatePattern = <P extends Pattern>({
7
- board,
8
- cells,
9
- config,
10
- PatternModel,
11
- }: {
12
- board: Board;
13
- cells: Cell[];
14
- config: Config;
15
- PatternModel: new (board: Board, cells: Cell[]) => P;
16
- }): P[] => {
17
- const startIndices = generateStartIndices(cells);
18
-
19
- return startIndices.flatMap((startIndex) => {
20
- const endIndices = generateEndIndices(cells, startIndex);
21
- const patterns: P[] = [];
22
-
23
- for (const endIndex of endIndices) {
24
- const pattern = new PatternModel(board, cells.slice(startIndex, endIndex + 1));
25
-
26
- if (pattern.canBePlaced(config)) {
27
- patterns.push(pattern);
28
- }
29
- }
30
-
31
- return patterns;
32
- });
33
- };
@@ -1,13 +0,0 @@
1
- import { getConfig } from '@scrabble-solver/configs';
2
- import { Board, Game, Locale } from '@scrabble-solver/types';
3
-
4
- import { generatePatterns } from './generatePatterns';
5
-
6
- describe('generatePatterns', () => {
7
- it('Generates all patterns for an empty board', () => {
8
- const config = getConfig(Game.Scrabble, Locale.EN_US);
9
- const board = Board.create(config.boardWidth, config.boardHeight);
10
-
11
- expect(generatePatterns(config, board).length).toEqual(54);
12
- });
13
- });
@@ -1,11 +0,0 @@
1
- import { type Board, type Config, type Pattern } from '@scrabble-solver/types';
2
-
3
- import { generateHorizontalPatterns } from './generateHorizontalPatterns';
4
- import { generateVerticalPatterns } from './generateVerticalPatterns';
5
-
6
- export const generatePatterns = (config: Config, board: Board): Pattern[] => {
7
- const horizontalPatterns = generateHorizontalPatterns(config, board);
8
- const verticalPatterns = generateVerticalPatterns(config, board);
9
-
10
- return horizontalPatterns.concat(verticalPatterns);
11
- };
@@ -1,19 +0,0 @@
1
- import { type Cell } from '@scrabble-solver/types';
2
-
3
- import { generateStartIndices } from './generateStartIndices';
4
-
5
- describe('generateStartIndices', () => {
6
- const emptyCell: Cell = { hasTile: () => false } as Cell;
7
- const filledCell: Cell = { hasTile: () => true } as Cell;
8
-
9
- it('returns empty array when no cells given', () => {
10
- const cells: Cell[] = [];
11
- expect(generateStartIndices(cells).length).toBe(0);
12
- });
13
-
14
- it('finds indices where a new word can start', () => {
15
- const cells = [filledCell, filledCell, emptyCell, emptyCell, emptyCell, filledCell];
16
- const startIndices = generateStartIndices(cells);
17
- expect(startIndices).toEqual([0, 3, 4]);
18
- });
19
- });
@@ -1,17 +0,0 @@
1
- import { type Cell } from '@scrabble-solver/types';
2
-
3
- export const generateStartIndices = (cells: Cell[]): number[] => {
4
- if (cells.length === 0) {
5
- return [];
6
- }
7
-
8
- const startIndices: number[] = [0];
9
-
10
- for (let startIndex = 1; startIndex < cells.length - 1; ++startIndex) {
11
- if (!cells[startIndex - 1].hasTile()) {
12
- startIndices.push(startIndex);
13
- }
14
- }
15
-
16
- return startIndices;
17
- };
@@ -1,12 +0,0 @@
1
- import { generateVectors } from './generateVectors';
2
-
3
- describe('generateVectors', () => {
4
- it('generates given number of vectors', () => {
5
- const vectors = generateVectors({
6
- getNthVector: () => [],
7
- vectorsCount: 3,
8
- });
9
- expect(vectors.length).toBe(3);
10
- expect(vectors).toEqual([[], [], []]);
11
- });
12
- });
@@ -1,10 +0,0 @@
1
- import { type Cell } from '@scrabble-solver/types';
2
-
3
- interface Parameters {
4
- getNthVector: (index: number) => Cell[];
5
- vectorsCount: number;
6
- }
7
-
8
- export const generateVectors = ({ getNthVector, vectorsCount }: Parameters): Cell[][] => {
9
- return Array.from({ length: vectorsCount }, (_, index) => getNthVector(index));
10
- };
@@ -1,32 +0,0 @@
1
- import { EMPTY_CELL } from '@scrabble-solver/constants';
2
- import { Board, type Config } from '@scrabble-solver/types';
3
-
4
- import { generateVerticalPatterns } from './generateVerticalPatterns';
5
-
6
- const board = Board.fromStringArray([' t ', 'do ', ' ']);
7
-
8
- const config = {
9
- boardHeight: 3,
10
- boardWidth: 3,
11
- rackSize: 7,
12
- } as Config;
13
-
14
- describe('generateVerticalPatterns', () => {
15
- it('generates some vertical patterns', () => {
16
- expect(generateVerticalPatterns(config, board).length).toBeGreaterThan(0);
17
- });
18
-
19
- it('generates proper vertical patterns', () => {
20
- const vertical = generateVerticalPatterns(config, board);
21
-
22
- expect(vertical.map(({ cells }) => cells.map(String))).toEqual([
23
- [EMPTY_CELL, 'd'],
24
- [EMPTY_CELL, 'd', EMPTY_CELL],
25
- ['d', EMPTY_CELL],
26
- ['t', 'o', EMPTY_CELL],
27
- [EMPTY_CELL, EMPTY_CELL],
28
- [EMPTY_CELL, EMPTY_CELL, EMPTY_CELL],
29
- [EMPTY_CELL, EMPTY_CELL],
30
- ]);
31
- });
32
- });
@@ -1,15 +0,0 @@
1
- import { type Board, type Config, type Pattern, VerticalPattern } from '@scrabble-solver/types';
2
-
3
- import { generatePattern } from './generatePattern';
4
- import { generateVectors } from './generateVectors';
5
-
6
- export const generateVerticalPatterns = (config: Config, board: Board): Pattern[] => {
7
- const getNthVector = (index: number) => board.getColumn(index);
8
- const vectorsCount = config.boardWidth;
9
- const verticalVectors = generateVectors({ getNthVector, vectorsCount });
10
- const verticalPatterns = verticalVectors.flatMap((cells) => {
11
- return generatePattern({ board, config, PatternModel: VerticalPattern, cells });
12
- });
13
-
14
- return verticalPatterns;
15
- };
@@ -1,21 +0,0 @@
1
- import { NO_BONUS } from '@scrabble-solver/constants';
2
- import { type Cell, type Config } from '@scrabble-solver/types';
3
-
4
- export const getCellsScore = (config: Config, cells: Cell[]): number => {
5
- const total = cells.reduce(
6
- ({ multiplier, score }, cell: Cell): { multiplier: number; score: number } => {
7
- const bonus = config.getCellBonus(cell);
8
- const { characterMultiplier, wordMultiplier } = bonus && bonus.canApply(config, cell) ? bonus.value : NO_BONUS;
9
- const characterScore = config.pointsMap[cell.tile.character] || 0;
10
- const tileScore = cell.tile.isBlank ? config.blankScore : characterScore;
11
-
12
- return {
13
- multiplier: multiplier * wordMultiplier,
14
- score: score + tileScore * characterMultiplier,
15
- };
16
- },
17
- { multiplier: 1, score: 0 },
18
- );
19
-
20
- return total.score * total.multiplier;
21
- };
@@ -1,17 +0,0 @@
1
- import { Board, Cell, Pattern, Tile } from '@scrabble-solver/types';
2
-
3
- import { getPatternHash } from './getPatternHash';
4
-
5
- describe('getPatternHash', () => {
6
- const board = Board.fromStringArray([' t ', 'do ', ' ']);
7
-
8
- it('hashes blanks', () => {
9
- const pattern = new Pattern(board, [
10
- new Cell({ x: 0, y: 0, tile: new Tile({ character: 'a', isBlank: false }) }),
11
- new Cell({ x: 0, y: 1, tile: new Tile({ character: 'b', isBlank: true }) }),
12
- new Cell({ x: 0, y: 2, tile: new Tile({ character: 'c', isBlank: false }) }),
13
- ]);
14
-
15
- expect(getPatternHash(pattern)).toBe('0,0,a-0,1,b!-0,2,c');
16
- });
17
- });
@@ -1,12 +0,0 @@
1
- import { type Pattern } from '@scrabble-solver/types';
2
-
3
- export const getPatternHash = (pattern: Pattern): string => {
4
- return pattern.cells
5
- .filter((cell) => cell.isEmpty)
6
- .map((cell) => {
7
- const blank = cell.tile.isBlank ? '!' : '';
8
- const tile = cell.tile.character + blank;
9
- return [cell.x, cell.y, tile].join(',');
10
- })
11
- .join('-');
12
- };