scrabble-solver 2.10.0 → 2.10.2

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 (185) hide show
  1. package/README.md +2 -2
  2. package/lerna.json +1 -1
  3. package/package.json +19 -19
  4. package/packages/configs/package-lock.json +45 -0
  5. package/packages/configs/package.json +3 -3
  6. package/packages/constants/build/index.js +1 -0
  7. package/packages/constants/package-lock.json +13 -0
  8. package/packages/constants/package.json +1 -1
  9. package/packages/constants/src/index.ts +1 -0
  10. package/packages/dictionaries/build/lib/createAsyncProxy.d.ts +1 -1
  11. package/packages/dictionaries/package-lock.json +2 -2
  12. package/packages/dictionaries/package.json +4 -4
  13. package/packages/logger/package-lock.json +8 -8
  14. package/packages/logger/package.json +1 -1
  15. package/packages/scrabble-solver/.next/BUILD_ID +1 -1
  16. package/packages/scrabble-solver/.next/build-manifest.json +19 -31
  17. package/packages/scrabble-solver/.next/cache/.tsbuildinfo +1 -1
  18. package/packages/scrabble-solver/.next/cache/eslint/.cache_8dgz12 +1 -1
  19. package/packages/scrabble-solver/.next/cache/next-server.js.nft.json +1 -1
  20. package/packages/scrabble-solver/.next/cache/webpack/client-development/0.pack +0 -0
  21. package/packages/scrabble-solver/.next/cache/webpack/client-development/1.pack +0 -0
  22. package/packages/scrabble-solver/.next/cache/webpack/client-development/2.pack +0 -0
  23. package/packages/scrabble-solver/.next/cache/webpack/client-development/3.pack +0 -0
  24. package/packages/scrabble-solver/.next/cache/webpack/client-development/4.pack +0 -0
  25. package/packages/scrabble-solver/.next/cache/webpack/client-development/index.pack +0 -0
  26. package/packages/scrabble-solver/.next/cache/webpack/client-development/index.pack.old +0 -0
  27. package/packages/scrabble-solver/.next/cache/webpack/client-production/0.pack +0 -0
  28. package/packages/scrabble-solver/.next/cache/webpack/client-production/index.pack +0 -0
  29. package/packages/scrabble-solver/.next/cache/webpack/edge-server-production/0.pack +0 -0
  30. package/packages/scrabble-solver/.next/cache/webpack/edge-server-production/index.pack +0 -0
  31. package/packages/scrabble-solver/.next/cache/webpack/server-development/0.pack +0 -0
  32. package/packages/scrabble-solver/.next/cache/webpack/server-development/10.pack_ +0 -0
  33. package/packages/scrabble-solver/.next/cache/webpack/server-development/5.pack_ +0 -0
  34. package/packages/scrabble-solver/.next/cache/webpack/server-development/8.pack_ +0 -0
  35. package/packages/scrabble-solver/.next/cache/webpack/server-development/index.pack +0 -0
  36. package/packages/scrabble-solver/.next/cache/webpack/server-production/0.pack +0 -0
  37. package/packages/scrabble-solver/.next/cache/webpack/server-production/index.pack +0 -0
  38. package/packages/scrabble-solver/.next/images-manifest.json +1 -1
  39. package/packages/scrabble-solver/.next/next-server.js.nft.json +1 -1
  40. package/packages/scrabble-solver/.next/prerender-manifest.json +1 -1
  41. package/packages/scrabble-solver/.next/required-server-files.json +1 -1
  42. package/packages/scrabble-solver/.next/routes-manifest.json +1 -1
  43. package/packages/scrabble-solver/.next/server/chunks/131.js +1399 -117
  44. package/packages/scrabble-solver/.next/server/chunks/{515.js → 176.js} +850 -732
  45. package/packages/scrabble-solver/.next/server/chunks/210.js +122 -0
  46. package/packages/scrabble-solver/.next/server/chunks/{939.js → 290.js} +4 -3
  47. package/packages/scrabble-solver/.next/server/chunks/44.js +33 -33
  48. package/packages/scrabble-solver/.next/server/chunks/50.js +5 -9
  49. package/packages/scrabble-solver/.next/server/chunks/{413.js → 579.js} +184 -117
  50. package/packages/scrabble-solver/.next/server/chunks/664.js +537 -350
  51. package/packages/scrabble-solver/.next/server/chunks/859.js +56 -23
  52. package/packages/scrabble-solver/.next/server/chunks/865.js +1 -1
  53. package/packages/scrabble-solver/.next/server/middleware-build-manifest.js +1 -1
  54. package/packages/scrabble-solver/.next/server/middleware-react-loadable-manifest.js +1 -1
  55. package/packages/scrabble-solver/.next/server/pages/404.html +2 -2
  56. package/packages/scrabble-solver/.next/server/pages/404.js.nft.json +1 -1
  57. package/packages/scrabble-solver/.next/server/pages/500.html +2 -2
  58. package/packages/scrabble-solver/.next/server/pages/_app.js +23 -5
  59. package/packages/scrabble-solver/.next/server/pages/_app.js.nft.json +1 -1
  60. package/packages/scrabble-solver/.next/server/pages/_document.js +2 -2
  61. package/packages/scrabble-solver/.next/server/pages/_error.js +206 -25
  62. package/packages/scrabble-solver/.next/server/pages/_error.js.nft.json +1 -1
  63. package/packages/scrabble-solver/.next/server/pages/api/dictionary/[locale]/[word].js +11 -11
  64. package/packages/scrabble-solver/.next/server/pages/api/dictionary/[locale]/[word].js.nft.json +1 -1
  65. package/packages/scrabble-solver/.next/server/pages/api/dictionary/[locale].js +10 -10
  66. package/packages/scrabble-solver/.next/server/pages/api/dictionary/[locale].js.nft.json +1 -1
  67. package/packages/scrabble-solver/.next/server/pages/api/solve.js +34 -36
  68. package/packages/scrabble-solver/.next/server/pages/api/solve.js.nft.json +1 -1
  69. package/packages/scrabble-solver/.next/server/pages/api/verify.js +10 -10
  70. package/packages/scrabble-solver/.next/server/pages/api/verify.js.nft.json +1 -1
  71. package/packages/scrabble-solver/.next/server/pages/api/visit.js +3 -3
  72. package/packages/scrabble-solver/.next/server/pages/api/visit.js.nft.json +1 -1
  73. package/packages/scrabble-solver/.next/server/pages/index.html +2 -2
  74. package/packages/scrabble-solver/.next/server/pages/index.js +44 -128
  75. package/packages/scrabble-solver/.next/server/pages/index.js.nft.json +1 -1
  76. package/packages/scrabble-solver/.next/server/pages/index.json +1 -1
  77. package/packages/scrabble-solver/.next/server/pages-manifest.json +4 -4
  78. package/packages/scrabble-solver/.next/static/FjrbXpI5fkt4lmko-vL_7/_buildManifest.js +1 -0
  79. package/packages/scrabble-solver/.next/static/{vscqn7BEtAxJteWSwNnas → FjrbXpI5fkt4lmko-vL_7}/_ssgManifest.js +0 -0
  80. package/packages/scrabble-solver/.next/static/chunks/361-d16f336a9752a55a.js +1 -0
  81. package/packages/scrabble-solver/.next/static/chunks/724-eb48df4d1ba3df8b.js +5 -0
  82. package/packages/scrabble-solver/.next/static/chunks/amp.js +720 -0
  83. package/packages/scrabble-solver/.next/static/chunks/framework-2c79e2a64abdb08b.js +33 -0
  84. package/packages/scrabble-solver/.next/static/chunks/main-f11614d8aa7ee555.js +1 -0
  85. package/packages/scrabble-solver/.next/static/chunks/main.js +1076 -0
  86. package/packages/scrabble-solver/.next/static/chunks/pages/404-24f9617eeb8d6dc1.js +1 -0
  87. package/packages/scrabble-solver/.next/static/chunks/pages/_app-959e495f0f221247.js +24 -0
  88. package/packages/scrabble-solver/.next/static/chunks/pages/_app.js +2121 -0
  89. package/packages/scrabble-solver/.next/static/chunks/pages/_error-8353112a01355ec2.js +1 -0
  90. package/packages/scrabble-solver/.next/static/chunks/pages/_error.js +28 -0
  91. package/packages/scrabble-solver/.next/static/chunks/pages/index-1e30dafa41bddb80.js +1 -0
  92. package/packages/scrabble-solver/.next/static/chunks/pages/index.js +5314 -0
  93. package/packages/scrabble-solver/.next/static/chunks/react-refresh.js +62 -0
  94. package/packages/scrabble-solver/.next/static/chunks/webpack-59c5c889f52620d6.js +1 -0
  95. package/packages/scrabble-solver/.next/static/chunks/webpack.js +1237 -0
  96. package/packages/scrabble-solver/.next/static/css/aafd07997120f1e4.css +1 -0
  97. package/packages/scrabble-solver/.next/static/css/c8d26240c04079b9.css +1 -0
  98. package/packages/scrabble-solver/.next/static/css/eb9d57f7103525ab.css +1 -0
  99. package/packages/scrabble-solver/.next/static/development/_buildManifest.js +1 -0
  100. package/packages/scrabble-solver/.next/static/development/_ssgManifest.js +1 -0
  101. package/packages/scrabble-solver/.next/static/webpack/fb4b50d5e70ee127.webpack.hot-update.json +1 -0
  102. package/packages/scrabble-solver/.next/static/webpack/pages/index.fb4b50d5e70ee127.hot-update.js +171 -0
  103. package/packages/scrabble-solver/.next/static/webpack/webpack.fb4b50d5e70ee127.hot-update.js +18 -0
  104. package/packages/scrabble-solver/.next/trace +52 -52
  105. package/packages/scrabble-solver/package-lock.json +1533 -1363
  106. package/packages/scrabble-solver/package.json +20 -20
  107. package/packages/scrabble-solver/public/og.png +0 -0
  108. package/packages/scrabble-solver/src/components/Board/Board.module.scss +1 -2
  109. package/packages/scrabble-solver/src/components/Board/BoardPure.tsx +2 -0
  110. package/packages/scrabble-solver/src/components/Board/components/Cell/Cell.module.scss +65 -55
  111. package/packages/scrabble-solver/src/components/Board/components/Cell/Cell.tsx +9 -0
  112. package/packages/scrabble-solver/src/components/Board/components/Cell/CellPure.tsx +11 -2
  113. package/packages/scrabble-solver/src/components/Board/hooks/useGrid.ts +6 -6
  114. package/packages/scrabble-solver/src/components/NavButtons/NavButtons.tsx +11 -1
  115. package/packages/scrabble-solver/src/components/Rack/Rack.tsx +16 -4
  116. package/packages/scrabble-solver/src/components/Rack/RackTile.tsx +10 -1
  117. package/packages/scrabble-solver/src/components/RemainingTiles/Character.module.scss +0 -1
  118. package/packages/scrabble-solver/src/components/RemainingTiles/Character.tsx +1 -0
  119. package/packages/scrabble-solver/src/components/Results/Results.tsx +2 -2
  120. package/packages/scrabble-solver/src/components/Settings/components/AutoGroupTilesSetting/AutoGroupTilesSetting.tsx +2 -2
  121. package/packages/scrabble-solver/src/components/Settings/components/LocaleSetting/options.ts +9 -1
  122. package/packages/scrabble-solver/src/components/Solver/Solver.module.scss +85 -0
  123. package/packages/scrabble-solver/src/components/Solver/Solver.tsx +75 -0
  124. package/packages/scrabble-solver/src/components/Solver/index.ts +1 -0
  125. package/packages/scrabble-solver/src/components/Tile/Tile.module.scss +51 -7
  126. package/packages/scrabble-solver/src/components/Tile/Tile.tsx +3 -0
  127. package/packages/scrabble-solver/src/components/Tile/TilePure.tsx +8 -1
  128. package/packages/scrabble-solver/src/components/index.ts +1 -0
  129. package/packages/scrabble-solver/src/hooks/index.ts +1 -0
  130. package/packages/scrabble-solver/src/hooks/useIsTouchDevice.ts +7 -0
  131. package/packages/scrabble-solver/src/i18n/fr.json +1 -1
  132. package/packages/scrabble-solver/src/icons/ExclamationSquareFill.svg +4 -0
  133. package/packages/scrabble-solver/src/icons/index.ts +1 -0
  134. package/packages/scrabble-solver/src/lib/getRemainingTilesGroups.ts +24 -26
  135. package/packages/scrabble-solver/src/pages/index.module.scss +1 -75
  136. package/packages/scrabble-solver/src/pages/index.tsx +11 -73
  137. package/packages/scrabble-solver/src/parameters/index.ts +2 -0
  138. package/packages/scrabble-solver/src/sdk/findWordDefinitions.ts +1 -1
  139. package/packages/scrabble-solver/src/service-worker/average.ts +9 -0
  140. package/packages/scrabble-solver/src/service-worker/routeSolveRequests.ts +46 -7
  141. package/packages/scrabble-solver/src/state/sagas.ts +19 -5
  142. package/packages/scrabble-solver/src/state/selectors.ts +30 -2
  143. package/packages/scrabble-solver/src/state/slices/boardInitialState.ts +27 -0
  144. package/packages/scrabble-solver/src/styles/mixins.scss +6 -1
  145. package/packages/scrabble-solver/src/styles/variables.scss +6 -3
  146. package/packages/solver/package-lock.json +2 -2
  147. package/packages/solver/package.json +5 -5
  148. package/packages/solver/src/generatePattern.ts +1 -0
  149. package/packages/types/build/Board.js +5 -5
  150. package/packages/types/build/BoardJson.d.ts +1 -1
  151. package/packages/types/build/Cell.js +7 -7
  152. package/packages/types/build/Collision.d.ts +1 -1
  153. package/packages/types/build/CollisionJson.d.ts +1 -1
  154. package/packages/types/build/Config.js +3 -3
  155. package/packages/types/build/Result.d.ts +1 -1
  156. package/packages/types/build/Result.js +8 -8
  157. package/packages/types/build/Tile.js +4 -4
  158. package/packages/types/build/WordDefinition.js +6 -6
  159. package/packages/types/package-lock.json +28 -0
  160. package/packages/types/package.json +2 -2
  161. package/packages/word-definitions/build/parse/parseEnglish.js +1 -1
  162. package/packages/word-definitions/package-lock.json +2 -2
  163. package/packages/word-definitions/package.json +2 -2
  164. package/packages/word-definitions/src/parse/__tests__/input/en-US.awe.html +2170 -323
  165. package/packages/word-definitions/src/parse/__tests__/input/en-US.pawn.html +2405 -349
  166. package/packages/word-definitions/src/parse/__tests__/input/en-US.pawnee.html +1326 -222
  167. package/packages/word-definitions/src/parse/__tests__/input/en-US.pean.html +1490 -201
  168. package/packages/word-definitions/src/parse/__tests__/input/en-US.wiz.html +1526 -272
  169. package/packages/word-definitions/src/parse/parseEnglish.ts +2 -1
  170. package/packages/word-lists/package-lock.json +23 -20
  171. package/packages/word-lists/package.json +2 -2
  172. package/packages/scrabble-solver/.next/InjectManifest.js.nft.json +0 -1
  173. package/packages/scrabble-solver/.next/static/chunks/368-d423e70be6c0c473.js +0 -1
  174. package/packages/scrabble-solver/.next/static/chunks/546-447e243fc9de2c59.js +0 -1
  175. package/packages/scrabble-solver/.next/static/chunks/framework-4556c45dd113b893.js +0 -1
  176. package/packages/scrabble-solver/.next/static/chunks/main-a75cf611e061d8f8.js +0 -1
  177. package/packages/scrabble-solver/.next/static/chunks/pages/404-932294135c3206dd.js +0 -1
  178. package/packages/scrabble-solver/.next/static/chunks/pages/_app-3f5508a5f544d9eb.js +0 -1
  179. package/packages/scrabble-solver/.next/static/chunks/pages/_error-a4ba2246ff8fb532.js +0 -1
  180. package/packages/scrabble-solver/.next/static/chunks/pages/index-8af7a9d7a2cd98a7.js +0 -1
  181. package/packages/scrabble-solver/.next/static/chunks/webpack-5752944655d749a0.js +0 -1
  182. package/packages/scrabble-solver/.next/static/css/6b1833fd19d3a74a.css +0 -1
  183. package/packages/scrabble-solver/.next/static/css/a6154e4ca046ca13.css +0 -1
  184. package/packages/scrabble-solver/.next/static/css/bad53af6f8616677.css +0 -1
  185. package/packages/scrabble-solver/.next/static/vscqn7BEtAxJteWSwNnas/_buildManifest.js +0 -1
@@ -1,5 +1,7 @@
1
1
  export const GITHUB_PROJECT_URL = 'https://github.com/kamilmielnik/scrabble-solver';
2
2
 
3
+ export const INITIALIZATION_DURATION = 100;
4
+
3
5
  export const TRANSITION_DURATION = 100;
4
6
  export const TRANSITION_DURATION_LONG = 250;
5
7
 
@@ -3,7 +3,7 @@ import { Locale, WordDefinition, WordDefinitionJson } from '@scrabble-solver/typ
3
3
  import fetchJson from './fetchJson';
4
4
 
5
5
  const findWordDefinitions = async (locale: Locale, word: string): Promise<WordDefinition[]> => {
6
- const json = await fetchJson<WordDefinitionJson[]>(`/api/dictionary/${locale}/${word}`);
6
+ const json = await fetchJson<WordDefinitionJson[]>(`/api/dictionary/${locale}/${encodeURIComponent(word)}`);
7
7
  return json.map(WordDefinition.fromJson);
8
8
  };
9
9
 
@@ -0,0 +1,9 @@
1
+ const average = (numbers: number[]): number => {
2
+ if (numbers.length === 0) {
3
+ return 0;
4
+ }
5
+
6
+ return numbers.reduce((sum, value) => sum + value, 0) / numbers.length;
7
+ };
8
+
9
+ export default average;
@@ -1,9 +1,11 @@
1
+ import { Trie } from '@kamilmielnik/trie';
1
2
  import { getConfig } from '@scrabble-solver/configs';
2
3
  import { BLANK } from '@scrabble-solver/constants';
3
4
  import { solve } from '@scrabble-solver/solver';
4
5
  import { Board, Locale, Tile } from '@scrabble-solver/types';
5
6
  import { registerRoute } from 'workbox-routing';
6
7
 
8
+ import average from './average';
7
9
  import { revalidateDictionary } from './dictionaries';
8
10
  import getTrie from './getTrie';
9
11
 
@@ -11,24 +13,61 @@ const headers = {
11
13
  'Content-Type': 'application/json; charset=utf-8',
12
14
  };
13
15
 
16
+ const MIN_MEASUREMENTS = 5;
17
+ const localDurations: number[] = [];
18
+ const serverDurations: number[] = [];
19
+
20
+ const isSlowDevice = (): boolean | undefined => {
21
+ if (localDurations.length < MIN_MEASUREMENTS || serverDurations.length < MIN_MEASUREMENTS) {
22
+ return undefined;
23
+ }
24
+
25
+ const count = Math.min(localDurations.length, serverDurations.length);
26
+ return average(localDurations.slice(0, count)) > average(serverDurations.slice(0, count));
27
+ };
28
+
14
29
  const routeSolveRequests = () => {
15
30
  registerRoute(
16
31
  ({ url }) => url.origin === location.origin && url.pathname === '/api/solve',
17
32
  async ({ request }) => {
18
33
  const { board, characters, configId, locale } = await request.clone().json();
34
+
35
+ const solveLocal = async (trie: Trie) => {
36
+ const config = getConfig(configId)[locale as Locale];
37
+ const tiles = characters.map((character: string) => new Tile({ character, isBlank: character === BLANK }));
38
+ const resultsJson = solve(trie, config, Board.fromJson(board), tiles);
39
+ const json = JSON.stringify(resultsJson);
40
+ return new Response(json, { headers });
41
+ };
42
+
43
+ const solveServer = () => fetch(request);
44
+
19
45
  const trie = await getTrie(locale);
20
46
 
21
- if (!trie) {
22
- const response = await fetch(request);
47
+ if (trie && typeof isSlowDevice() === 'undefined') {
48
+ const response = await Promise.race([
49
+ (async () => {
50
+ const start = Date.now();
51
+ const result = await solveLocal(trie);
52
+ localDurations.push(Date.now() - start);
53
+ return result;
54
+ })(),
55
+ (async () => {
56
+ const start = Date.now();
57
+ const result = await solveServer();
58
+ serverDurations.push(Date.now() - start);
59
+ return result;
60
+ })(),
61
+ ]);
62
+
23
63
  revalidateDictionary(locale);
24
64
  return response;
25
65
  }
26
66
 
27
- const config = getConfig(configId)[locale as Locale];
28
- const tiles = characters.map((character: string) => new Tile({ character, isBlank: character === BLANK }));
29
- const resultsJson = solve(trie, config, Board.fromJson(board), tiles);
30
- const json = JSON.stringify(resultsJson);
31
- return new Response(json, { headers });
67
+ const handleSolve = trie && !isSlowDevice() ? () => solveLocal(trie) : () => solveServer();
68
+ const response = await handleSolve();
69
+ revalidateDictionary(locale);
70
+ return response;
32
71
  },
33
72
  'POST',
34
73
  );
@@ -7,13 +7,13 @@ import { findWordDefinitions, solve, verify, visit } from 'sdk';
7
7
 
8
8
  import { initialize, reset } from './actions';
9
9
  import {
10
- selectAutoGroupTiles,
11
10
  selectBoard,
12
11
  selectCellIsFiltered,
13
12
  selectCharacters,
14
13
  selectConfig,
15
14
  selectDictionary,
16
15
  selectLocale,
16
+ selectLocaleAutoGroupTiles,
17
17
  } from './selectors';
18
18
  import {
19
19
  boardSlice,
@@ -65,7 +65,7 @@ function* onRackValueChange(): AnyGenerator {
65
65
  }
66
66
 
67
67
  function* onApplyResult({ payload: result }: PayloadAction<Result>): AnyGenerator {
68
- const autoGroupTiles = yield select(selectAutoGroupTiles);
68
+ const autoGroupTiles = yield select(selectLocaleAutoGroupTiles);
69
69
  yield put(boardSlice.actions.applyResult(result));
70
70
  yield put(cellFilterSlice.actions.reset());
71
71
  yield put(rackSlice.actions.removeTiles(result.tiles));
@@ -74,8 +74,15 @@ function* onApplyResult({ payload: result }: PayloadAction<Result>): AnyGenerato
74
74
  }
75
75
 
76
76
  function* onConfigIdChange(): AnyGenerator {
77
+ const characters = yield select(selectCharacters);
78
+
79
+ if (characters.length > 0) {
80
+ yield put(solveSlice.actions.submit());
81
+ } else {
82
+ yield put(resultsSlice.actions.reset());
83
+ }
84
+
77
85
  yield put(resultsSlice.actions.reset());
78
- yield put(solveSlice.actions.submit());
79
86
  yield put(verifySlice.actions.submit());
80
87
  yield* ensureProperTilesCount();
81
88
  }
@@ -112,9 +119,16 @@ function* onReset(): AnyGenerator {
112
119
  }
113
120
 
114
121
  function* onLocaleChange(): AnyGenerator {
122
+ const characters = yield select(selectCharacters);
123
+
124
+ if (characters.length > 0) {
125
+ yield put(solveSlice.actions.submit());
126
+ } else {
127
+ yield put(resultsSlice.actions.reset());
128
+ }
129
+
115
130
  yield put(dictionarySlice.actions.reset());
116
131
  yield put(resultsSlice.actions.changeResultCandidate(null));
117
- yield put(solveSlice.actions.submit());
118
132
  yield put(verifySlice.actions.submit());
119
133
  }
120
134
 
@@ -181,7 +195,7 @@ function* ensureProperTilesCount(): AnyGenerator {
181
195
  } else if (config.maximumCharactersCount < characters.length) {
182
196
  const nonNulls = characters.filter(Boolean).slice(0, config.maximumCharactersCount);
183
197
  const differenceCount = Math.abs(config.maximumCharactersCount - nonNulls.length);
184
- const autoGroupTiles = yield select(selectAutoGroupTiles);
198
+ const autoGroupTiles = yield select(selectLocaleAutoGroupTiles);
185
199
  yield put(rackSlice.actions.init([...nonNulls, ...Array(differenceCount).fill(null)]));
186
200
  yield put(rackSlice.actions.groupTiles(autoGroupTiles));
187
201
  }
@@ -1,8 +1,9 @@
1
1
  import { createSelector } from '@reduxjs/toolkit';
2
2
  import { getLocaleConfig } from '@scrabble-solver/configs';
3
+ import { BLANK } from '@scrabble-solver/constants';
3
4
  import { Cell, Config, isError, Result, Tile } from '@scrabble-solver/types';
4
5
 
5
- import i18n from 'i18n';
6
+ import i18n, { LOCALE_FEATURES } from 'i18n';
6
7
  import { findCell, getRemainingTiles, getRemainingTilesGroups, sortResults, unorderedArraysEqual } from 'lib';
7
8
  import { Translations } from 'types';
8
9
 
@@ -38,9 +39,17 @@ export const selectDictionaryError = createSelector([selectDictionaryRoot], (dic
38
39
  return isError(dictionary.error) ? dictionary.error : undefined;
39
40
  });
40
41
 
42
+ export const selectLocale = createSelector([selectSettingsRoot], (settings) => settings.locale);
43
+
41
44
  export const selectAutoGroupTiles = createSelector([selectSettingsRoot], (settings) => settings.autoGroupTiles);
42
45
 
43
- export const selectLocale = createSelector([selectSettingsRoot], (settings) => settings.locale);
46
+ export const selectLocaleAutoGroupTiles = createSelector([selectLocale, selectSettingsRoot], (locale, settings) => {
47
+ if (LOCALE_FEATURES[locale].direction === 'ltr' || settings.autoGroupTiles === null) {
48
+ return settings.autoGroupTiles;
49
+ }
50
+
51
+ return settings.autoGroupTiles === 'left' ? 'right' : 'left';
52
+ });
44
53
 
45
54
  export const selectBoard = selectBoardRoot;
46
55
 
@@ -54,6 +63,14 @@ export const selectCellIsFiltered = createSelector([selectCellFilter, selectPoin
54
63
  return cellFilter.some((cell) => cell.x === x && cell.y === y);
55
64
  });
56
65
 
66
+ export const selectCellIsValid = createSelector([selectConfig, selectCell], (config, cell) => {
67
+ if (!cell.hasTile()) {
68
+ return true;
69
+ }
70
+
71
+ return config.tiles.some((tile) => tile.character === cell.tile.character);
72
+ });
73
+
57
74
  export const selectResults = createSelector([selectResultsRoot], (results) => results.results);
58
75
 
59
76
  export const selectResultsQuery = createSelector([selectResultsRoot], (results) => results.query);
@@ -132,6 +149,17 @@ export const selectCharacterPoints = createSelector(
132
149
  },
133
150
  );
134
151
 
152
+ export const selectCharacterIsValid = createSelector(
153
+ [selectConfig, selectCharacter],
154
+ (config: Config, character: string | null) => {
155
+ if (character === null || character === BLANK) {
156
+ return true;
157
+ }
158
+
159
+ return config.tiles.some((tile) => tile.character === character);
160
+ },
161
+ );
162
+
135
163
  export const selectTilePoints = createSelector([selectConfig, selectTile], (config: Config, tile: Tile | null) => {
136
164
  return config.getTilePoints(tile);
137
165
  });
@@ -7,4 +7,31 @@ const { configId, locale } = settingsInitialState;
7
7
  const { boardHeight, boardWidth } = getLocaleConfig(configId, locale);
8
8
  const boardInitialState: Board = Board.create(boardWidth, boardHeight);
9
9
 
10
+ // const createOxyphenbutazone = () => {
11
+ // // Tiles: oypbaze
12
+
13
+ // const board = Board.fromStringArray([
14
+ // ' x hen ut on ',
15
+ // 'puer or amas j',
16
+ // 'a led a er a',
17
+ // 'c ki i elf c',
18
+ // 'i snot n is u',
19
+ // 'f t o w do l',
20
+ // 'y e moa er a',
21
+ // 'i r solar t',
22
+ // 'n v h t i',
23
+ // 'g i i bitten',
24
+ // ' e n v g',
25
+ // ' w g e ',
26
+ // ' e ',
27
+ // ' d ',
28
+ // ' ',
29
+ // ]);
30
+
31
+ // board.rows[4][3].tile.isBlank = true;
32
+ // board.rows[9][11].tile.isBlank = true;
33
+
34
+ // return board;
35
+ // };
36
+
10
37
  export default boardInitialState;
@@ -1,4 +1,4 @@
1
- @mixin tablet() {
1
+ @mixin tablet {
2
2
  @media (max-width: 1024px) {
3
3
  @content;
4
4
  }
@@ -73,3 +73,8 @@
73
73
  font-size: var(--font--size--s);
74
74
  font-family: var(--font--family);
75
75
  }
76
+
77
+ @mixin text-stroke($color, $size: 1px) {
78
+ text-shadow: $size 0 $color, (-$size) 0 $color, 0 $size $color, 0 (-$size) $color, (-$size) (-$size) $color,
79
+ (-$size) $size $color, $size (-$size) $color, $size $size $color;
80
+ }
@@ -2,6 +2,7 @@ $easeOutSine: cubic-bezier(0.61, 1, 0.88, 1);
2
2
 
3
3
  :root {
4
4
  --border--color: #cdcdcd;
5
+ --border--color--light: #d9d9d9;
5
6
  --border--radius: 5px;
6
7
  --border--width: 1px;
7
8
  --border: var(--border--width) solid var(--border--color);
@@ -41,13 +42,15 @@ $easeOutSine: cubic-bezier(0.61, 1, 0.88, 1);
41
42
  --color--blue: #c7d8f9;
42
43
  --color--blue--light: #dde4f6;
43
44
  --color--light-blue: #7bb5e5;
44
- --color--light-blue--light: #{rgba(#7bb5e5, 0.5)};
45
+ --color--light-blue--light: #b8d5ed;
45
46
  --color--dark-blue: #1868ad;
46
- --color--dark-blue--light: #{rgba(#1868ad, 0.5)};
47
+ --color--dark-blue--light: #86aed1;
47
48
  --color--red: #f7c2aa;
48
49
  --color--red--light: #fbe0d4;
49
50
  --color--violet: #78387f;
50
- --color--violet--light: #{rgba(#78387f, 0.5)};
51
+ --color--violet--light: #b284b8;
52
+ --color--orange: #fbc997;
53
+ --color--pink: #f19393;
51
54
 
52
55
  --font--family: 'Open Sans', sans-serif;
53
56
  --font--family--title: 'Lato', sans-serif;
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@scrabble-solver/solver",
3
- "version": "2.10.0",
3
+ "version": "2.10.2",
4
4
  "lockfileVersion": 2,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@scrabble-solver/solver",
9
- "version": "2.10.0",
9
+ "version": "2.10.2",
10
10
  "license": "CC-BY-NC-ND-4.0",
11
11
  "dependencies": {
12
12
  "@kamilmielnik/trie": "^2.0.1"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scrabble-solver/solver",
3
- "version": "2.10.0",
3
+ "version": "2.10.2",
4
4
  "description": "Scrabble Solver 2 - Solver",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -25,12 +25,12 @@
25
25
  },
26
26
  "dependencies": {
27
27
  "@kamilmielnik/trie": "^2.0.1",
28
- "@scrabble-solver/types": "^2.10.0"
28
+ "@scrabble-solver/types": "^2.10.2"
29
29
  },
30
30
  "devDependencies": {
31
- "@scrabble-solver/configs": "^2.10.0",
32
- "@scrabble-solver/constants": "^2.10.0",
33
- "@scrabble-solver/dictionaries": "^2.10.0"
31
+ "@scrabble-solver/configs": "^2.10.2",
32
+ "@scrabble-solver/constants": "^2.10.2",
33
+ "@scrabble-solver/dictionaries": "^2.10.2"
34
34
  },
35
35
  "gitHead": "1e2d1ad49a288d4a44196d8e3336740da132c637"
36
36
  }
@@ -12,6 +12,7 @@ const generatePattern = <P extends Pattern>({
12
12
  board: Board;
13
13
  cells: Cell[];
14
14
  config: Config;
15
+ // eslint-disable-next-line @typescript-eslint/no-shadow
15
16
  PatternModel: new (board: Board, cells: Cell[]) => P;
16
17
  }): P[] => {
17
18
  const startIndices = generateStartIndices(cells);
@@ -7,11 +7,6 @@ const constants_1 = require("@scrabble-solver/constants");
7
7
  const Cell_1 = __importDefault(require("./Cell"));
8
8
  const Tile_1 = __importDefault(require("./Tile"));
9
9
  class Board {
10
- constructor({ rows }) {
11
- this.rows = rows;
12
- this.columnsCount = rows[0].length;
13
- this.rowsCount = rows.length;
14
- }
15
10
  static create(width, height) {
16
11
  return Board.fromStringArray(Array(height).fill(Array(width).fill(' ').join('')));
17
12
  }
@@ -30,6 +25,11 @@ class Board {
30
25
  }))),
31
26
  });
32
27
  }
28
+ constructor({ rows }) {
29
+ this.rows = rows;
30
+ this.columnsCount = rows[0].length;
31
+ this.rowsCount = rows.length;
32
+ }
33
33
  get center() {
34
34
  const x = Math.floor(this.columnsCount / 2);
35
35
  const y = Math.floor(this.rowsCount / 2);
@@ -1,4 +1,4 @@
1
1
  import CellJson from './CellJson';
2
- declare type BoardJson = CellJson[][];
2
+ type BoardJson = CellJson[][];
3
3
  export declare const isBoardJson: (value: unknown) => value is BoardJson;
4
4
  export default BoardJson;
@@ -5,13 +5,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const Tile_1 = __importDefault(require("./Tile"));
7
7
  class Cell {
8
- // eslint-disable-next-line no-undef
9
- constructor({ isEmpty = true, tile = Tile_1.default.Null, x, y }) {
10
- this.isEmpty = isEmpty;
11
- this.tile = tile;
12
- this.x = x;
13
- this.y = y;
14
- }
15
8
  static fromJson(json) {
16
9
  return new Cell({
17
10
  isEmpty: json.isEmpty,
@@ -20,6 +13,13 @@ class Cell {
20
13
  y: json.y,
21
14
  });
22
15
  }
16
+ // eslint-disable-next-line no-undef
17
+ constructor({ isEmpty = true, tile = Tile_1.default.Null, x, y }) {
18
+ this.isEmpty = isEmpty;
19
+ this.tile = tile;
20
+ this.x = x;
21
+ this.y = y;
22
+ }
23
23
  clone() {
24
24
  return new Cell({
25
25
  isEmpty: this.isEmpty,
@@ -1,3 +1,3 @@
1
1
  import Cell from './Cell';
2
- declare type Collision = Cell[];
2
+ type Collision = Cell[];
3
3
  export default Collision;
@@ -1,3 +1,3 @@
1
1
  import CellJson from './CellJson';
2
- declare type CollisionJson = CellJson[];
2
+ type CollisionJson = CellJson[];
3
3
  export default CollisionJson;
@@ -7,14 +7,14 @@ const constants_1 = require("@scrabble-solver/constants");
7
7
  const CharacterBonus_1 = __importDefault(require("./CharacterBonus"));
8
8
  const WordBonus_1 = __importDefault(require("./WordBonus"));
9
9
  class Config {
10
+ static fromJson(json) {
11
+ return new Config(json);
12
+ }
10
13
  constructor(config) {
11
14
  this.bonuses = getBonuses(config);
12
15
  this.config = config;
13
16
  this.pointsMap = getPointsMap(this.config);
14
17
  }
15
- static fromJson(json) {
16
- return new Config(json);
17
- }
18
18
  get allTilesBonusScore() {
19
19
  return this.config.allTilesBonusScore;
20
20
  }
@@ -1,7 +1,7 @@
1
1
  import Cell from './Cell';
2
2
  import ResultJson from './ResultJson';
3
3
  import Tile from './Tile';
4
- declare type Collision = Cell[];
4
+ type Collision = Cell[];
5
5
  declare class Result {
6
6
  static fromJson(json: ResultJson): Result;
7
7
  readonly blanksCount: number;
@@ -6,6 +6,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const constants_1 = require("@scrabble-solver/constants");
7
7
  const Cell_1 = __importDefault(require("./Cell"));
8
8
  class Result {
9
+ static fromJson(json) {
10
+ return new Result({
11
+ id: json.id,
12
+ cells: json.cells.map(Cell_1.default.fromJson),
13
+ collisions: json.collisions.map((collision) => collision.map(Cell_1.default.fromJson)),
14
+ points: json.points,
15
+ });
16
+ }
9
17
  constructor({ cells, id, collisions, points, }) {
10
18
  const tiles = getTiles(cells);
11
19
  this.blanksCount = getBlanks(tiles).length;
@@ -23,14 +31,6 @@ class Result {
23
31
  this.words = getWords(cells, collisions);
24
32
  this.wordsCount = 1 + this.collisions.length;
25
33
  }
26
- static fromJson(json) {
27
- return new Result({
28
- id: json.id,
29
- cells: json.cells.map(Cell_1.default.fromJson),
30
- collisions: json.collisions.map((collision) => collision.map(Cell_1.default.fromJson)),
31
- points: json.points,
32
- });
33
- }
34
34
  toJson() {
35
35
  return {
36
36
  cells: this.cells.map((cell) => cell.toJson()),
@@ -2,10 +2,6 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const constants_1 = require("@scrabble-solver/constants");
4
4
  class Tile {
5
- constructor({ character, isBlank = false }) {
6
- this.character = character;
7
- this.isBlank = isBlank;
8
- }
9
5
  static fromJson(json) {
10
6
  if (!json) {
11
7
  return Tile.Null;
@@ -15,6 +11,10 @@ class Tile {
15
11
  isBlank: json.isBlank,
16
12
  });
17
13
  }
14
+ constructor({ character, isBlank = false }) {
15
+ this.character = character;
16
+ this.isBlank = isBlank;
17
+ }
18
18
  clone() {
19
19
  return new Tile({
20
20
  character: this.character,
@@ -1,12 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  class WordDefinition {
4
- constructor({ definitions, exists, isAllowed, word }) {
5
- this.definitions = definitions;
6
- this.exists = exists;
7
- this.isAllowed = isAllowed;
8
- this.word = word;
9
- }
10
4
  static fromJson(json) {
11
5
  if (!json) {
12
6
  return WordDefinition.Null;
@@ -18,6 +12,12 @@ class WordDefinition {
18
12
  word: json.word,
19
13
  });
20
14
  }
15
+ constructor({ definitions, exists, isAllowed, word }) {
16
+ this.definitions = definitions;
17
+ this.exists = exists;
18
+ this.isAllowed = isAllowed;
19
+ this.word = word;
20
+ }
21
21
  toJson() {
22
22
  return {
23
23
  definitions: this.definitions,
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "@scrabble-solver/types",
3
+ "version": "2.10.2",
4
+ "lockfileVersion": 2,
5
+ "requires": true,
6
+ "packages": {
7
+ "": {
8
+ "name": "@scrabble-solver/types",
9
+ "version": "2.10.2",
10
+ "license": "CC-BY-NC-ND-4.0",
11
+ "dependencies": {
12
+ "@scrabble-solver/constants": "^2.10.2"
13
+ }
14
+ },
15
+ "node_modules/@scrabble-solver/constants": {
16
+ "version": "2.10.1",
17
+ "resolved": "https://registry.npmjs.org/@scrabble-solver/constants/-/constants-2.10.1.tgz",
18
+ "integrity": "sha512-XrLcJQREt1OHHA1VY+/8mS9avJCcS0jaXKmUABxQCPpBOZMD39G4E/0ebgwp4uNjxogIYZccRQXG2olYSZukwA=="
19
+ }
20
+ },
21
+ "dependencies": {
22
+ "@scrabble-solver/constants": {
23
+ "version": "2.10.1",
24
+ "resolved": "https://registry.npmjs.org/@scrabble-solver/constants/-/constants-2.10.1.tgz",
25
+ "integrity": "sha512-XrLcJQREt1OHHA1VY+/8mS9avJCcS0jaXKmUABxQCPpBOZMD39G4E/0ebgwp4uNjxogIYZccRQXG2olYSZukwA=="
26
+ }
27
+ }
28
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scrabble-solver/types",
3
- "version": "2.10.0",
3
+ "version": "2.10.2",
4
4
  "description": "Scrabble Solver 2 - Types",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -24,7 +24,7 @@
24
24
  "clean:force": "npm run clean && rimraf package-lock.json"
25
25
  },
26
26
  "dependencies": {
27
- "@scrabble-solver/constants": "^2.10.0"
27
+ "@scrabble-solver/constants": "^2.10.2"
28
28
  },
29
29
  "gitHead": "1e2d1ad49a288d4a44196d8e3336740da132c637"
30
30
  }
@@ -8,7 +8,7 @@ const parseEnglish = (html) => {
8
8
  const $ = (0, cheerio_1.load)(html);
9
9
  $('strong.mw_t_bc').replaceWith(', ');
10
10
  $('.text-lowercase').remove();
11
- $('[id^=dictionary-entry]').find('.dtText > *:not(a)').remove();
11
+ $('.sub-content-thread').remove();
12
12
  const $definitions = $('[id^=dictionary-entry]').find('.dtText, .cxl-ref');
13
13
  return {
14
14
  definitions: Array.from($definitions).map((definition) => $(definition).text().replace(/\n/g, '')),
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@scrabble-solver/word-definitions",
3
- "version": "2.10.0",
3
+ "version": "2.10.2",
4
4
  "lockfileVersion": 2,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@scrabble-solver/word-definitions",
9
- "version": "2.10.0",
9
+ "version": "2.10.2",
10
10
  "license": "CC-BY-NC-ND-4.0",
11
11
  "dependencies": {
12
12
  "cheerio": "^1.0.0-rc.12",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scrabble-solver/word-definitions",
3
- "version": "2.10.0",
3
+ "version": "2.10.2",
4
4
  "description": "Scrabble Solver 2 - Word definitions",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -23,7 +23,7 @@
23
23
  "clean": "rimraf build/ node_modules/ package-lock.json"
24
24
  },
25
25
  "dependencies": {
26
- "@scrabble-solver/types": "^2.10.0",
26
+ "@scrabble-solver/types": "^2.10.2",
27
27
  "cheerio": "^1.0.0-rc.12",
28
28
  "follow-redirects": "^1.15.2",
29
29
  "striptags": "^3.2.0"