scrabble-solver 2.12.2 → 2.12.4

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 (250) hide show
  1. package/README.md +40 -13
  2. package/lerna.json +1 -1
  3. package/package.json +3 -2
  4. package/packages/configs/build/games/index.d.ts +3 -0
  5. package/packages/configs/build/games/index.js +12 -0
  6. package/packages/configs/build/games/literaki.d.ts +25 -0
  7. package/packages/configs/build/games/literaki.js +110 -0
  8. package/packages/configs/build/games/scrabble.d.ts +18 -0
  9. package/packages/configs/build/games/scrabble.js +78 -0
  10. package/packages/configs/build/games/superScrabble.d.ts +18 -0
  11. package/packages/configs/build/games/superScrabble.js +141 -0
  12. package/packages/configs/build/getConfig.d.ts +2 -6
  13. package/packages/configs/build/getConfig.js +29 -10
  14. package/packages/configs/build/hasConfig.d.ts +3 -0
  15. package/packages/configs/build/hasConfig.js +31 -0
  16. package/packages/configs/build/index.d.ts +7 -4
  17. package/packages/configs/build/index.js +32 -9
  18. package/packages/configs/build/locales/deDe.d.ts +3 -0
  19. package/packages/configs/build/locales/deDe.js +42 -0
  20. package/packages/configs/build/locales/enGb.d.ts +3 -0
  21. package/packages/configs/build/locales/enGb.js +104 -0
  22. package/packages/configs/build/locales/enUs.d.ts +3 -0
  23. package/packages/configs/build/locales/enUs.js +104 -0
  24. package/packages/configs/build/locales/esEs.d.ts +3 -0
  25. package/packages/configs/build/locales/esEs.js +41 -0
  26. package/packages/configs/build/locales/faIr.d.ts +3 -0
  27. package/packages/configs/build/locales/faIr.js +45 -0
  28. package/packages/configs/build/locales/frFr.d.ts +3 -0
  29. package/packages/configs/build/locales/frFr.js +39 -0
  30. package/packages/configs/build/locales/index.d.ts +7 -0
  31. package/packages/configs/build/locales/index.js +20 -0
  32. package/packages/configs/build/locales/plPl.d.ts +3 -0
  33. package/packages/configs/build/locales/plPl.js +83 -0
  34. package/packages/configs/package.json +3 -3
  35. package/packages/configs/src/games/index.ts +3 -0
  36. package/packages/configs/src/games/literaki.ts +110 -0
  37. package/packages/configs/src/games/scrabble.ts +78 -0
  38. package/packages/configs/src/games/superScrabble.ts +141 -0
  39. package/packages/configs/src/getConfig.ts +8 -15
  40. package/packages/configs/src/hasConfig.ts +10 -0
  41. package/packages/configs/src/index.ts +7 -4
  42. package/packages/configs/src/locales/deDe.ts +43 -0
  43. package/packages/configs/src/locales/enGb.ts +105 -0
  44. package/packages/configs/src/locales/enUs.ts +105 -0
  45. package/packages/configs/src/locales/esEs.ts +42 -0
  46. package/packages/configs/src/locales/faIr.ts +46 -0
  47. package/packages/configs/src/locales/frFr.ts +40 -0
  48. package/packages/configs/src/locales/index.ts +7 -0
  49. package/packages/configs/src/locales/plPl.ts +84 -0
  50. package/packages/constants/package.json +1 -1
  51. package/packages/dictionaries/package-lock.json +3 -10
  52. package/packages/dictionaries/package.json +4 -4
  53. package/packages/logger/package-lock.json +3 -224
  54. package/packages/logger/package.json +1 -1
  55. package/packages/scrabble-solver/.next/BUILD_ID +1 -1
  56. package/packages/scrabble-solver/.next/build-manifest.json +6 -6
  57. package/packages/scrabble-solver/.next/cache/.tsbuildinfo +1 -1
  58. package/packages/scrabble-solver/.next/cache/eslint/.cache_8dgz12 +1 -1
  59. package/packages/scrabble-solver/.next/cache/next-server.js.nft.json +1 -1
  60. package/packages/scrabble-solver/.next/cache/webpack/client-production/0.pack +0 -0
  61. package/packages/scrabble-solver/.next/cache/webpack/client-production/index.pack +0 -0
  62. package/packages/scrabble-solver/.next/cache/webpack/edge-server-production/0.pack +0 -0
  63. package/packages/scrabble-solver/.next/cache/webpack/edge-server-production/index.pack +0 -0
  64. package/packages/scrabble-solver/.next/cache/webpack/server-production/0.pack +0 -0
  65. package/packages/scrabble-solver/.next/cache/webpack/server-production/index.pack +0 -0
  66. package/packages/scrabble-solver/.next/next-server.js.nft.json +1 -1
  67. package/packages/scrabble-solver/.next/prerender-manifest.json +1 -1
  68. package/packages/scrabble-solver/.next/routes-manifest.json +1 -1
  69. package/packages/scrabble-solver/.next/server/chunks/131.js +478 -106
  70. package/packages/scrabble-solver/.next/server/chunks/277.js +1132 -976
  71. package/packages/scrabble-solver/.next/server/chunks/44.js +37 -9
  72. package/packages/scrabble-solver/.next/server/chunks/865.js +597 -169
  73. package/packages/scrabble-solver/.next/server/chunks/911.js +894 -773
  74. package/packages/scrabble-solver/.next/server/middleware-build-manifest.js +1 -1
  75. package/packages/scrabble-solver/.next/server/pages/404.html +1 -1
  76. package/packages/scrabble-solver/.next/server/pages/404.js.nft.json +1 -1
  77. package/packages/scrabble-solver/.next/server/pages/500.html +1 -1
  78. package/packages/scrabble-solver/.next/server/pages/_app.js +3 -1
  79. package/packages/scrabble-solver/.next/server/pages/_app.js.nft.json +1 -1
  80. package/packages/scrabble-solver/.next/server/pages/_document.js.nft.json +1 -1
  81. package/packages/scrabble-solver/.next/server/pages/api/dictionary/[locale]/[word].js +4 -2
  82. package/packages/scrabble-solver/.next/server/pages/api/solve.js +23 -19
  83. package/packages/scrabble-solver/.next/server/pages/api/verify.js +8 -5
  84. package/packages/scrabble-solver/.next/server/pages/index.html +1 -1
  85. package/packages/scrabble-solver/.next/server/pages/index.js +42 -55
  86. package/packages/scrabble-solver/.next/server/pages/index.js.nft.json +1 -1
  87. package/packages/scrabble-solver/.next/server/pages/index.json +1 -1
  88. package/packages/scrabble-solver/.next/server/pages-manifest.json +2 -2
  89. package/packages/scrabble-solver/.next/static/{9dmPfnTc_AQTHBPvL7xQe → 8oRk1nUMQYFWmhu4SExQI}/_buildManifest.js +1 -1
  90. package/packages/scrabble-solver/.next/static/chunks/pages/_app-e7f3d1c9c09c8f91.js +32 -0
  91. package/packages/scrabble-solver/.next/static/chunks/pages/index-82b2939158c7729f.js +1 -0
  92. package/packages/scrabble-solver/.next/static/css/4e8b47fe382a8a8f.css +2 -0
  93. package/packages/scrabble-solver/.next/static/css/cfae5256f1689f57.css +1 -0
  94. package/packages/scrabble-solver/.next/trace +51 -52
  95. package/packages/scrabble-solver/package-lock.json +158 -4898
  96. package/packages/scrabble-solver/package.json +8 -8
  97. package/packages/scrabble-solver/src/components/Board/components/Cell/Cell.module.scss +4 -12
  98. package/packages/scrabble-solver/src/components/Board/components/Cell/Cell.tsx +4 -0
  99. package/packages/scrabble-solver/src/components/Board/hooks/useBackgroundImage.tsx +23 -0
  100. package/packages/scrabble-solver/src/components/PlainTiles/lib/createPlainTile.ts +4 -4
  101. package/packages/scrabble-solver/src/components/Radio/Radio.module.scss +4 -0
  102. package/packages/scrabble-solver/src/components/Radio/Radio.tsx +1 -0
  103. package/packages/scrabble-solver/src/components/SeoMessage/SeoMessage.tsx +3 -3
  104. package/packages/scrabble-solver/src/hooks/useAppLayout.ts +1 -2
  105. package/packages/scrabble-solver/src/hooks/useLocalStorage.ts +5 -5
  106. package/packages/scrabble-solver/src/i18n/constants.ts +31 -61
  107. package/packages/scrabble-solver/src/lib/extractCharacters.test.ts +3 -3
  108. package/packages/scrabble-solver/src/lib/extractCharactersByCase.test.ts +3 -3
  109. package/packages/scrabble-solver/src/lib/getCellSize.ts +2 -2
  110. package/packages/scrabble-solver/src/modals/MenuModal/MenuModal.module.scss +0 -1
  111. package/packages/scrabble-solver/src/modals/MenuModal/MenuModal.tsx +3 -3
  112. package/packages/scrabble-solver/src/modals/SettingsModal/components/ConfigSetting/ConfigSetting.tsx +16 -7
  113. package/packages/scrabble-solver/src/modals/SettingsModal/components/LocaleSetting/LocaleSetting.module.scss +1 -4
  114. package/packages/scrabble-solver/src/modals/SettingsModal/components/LocaleSetting/LocaleSetting.tsx +8 -8
  115. package/packages/scrabble-solver/src/pages/_app.tsx +3 -1
  116. package/packages/scrabble-solver/src/pages/api/dictionary/[locale]/[word].ts +6 -3
  117. package/packages/scrabble-solver/src/pages/api/solve.ts +11 -7
  118. package/packages/scrabble-solver/src/pages/api/verify.ts +11 -7
  119. package/packages/scrabble-solver/src/pages/index.module.scss +0 -1
  120. package/packages/scrabble-solver/src/parameters/index.ts +4 -6
  121. package/packages/scrabble-solver/src/sdk/solve.ts +3 -3
  122. package/packages/scrabble-solver/src/sdk/verify.ts +3 -3
  123. package/packages/scrabble-solver/src/service-worker/routeSolveRequests.ts +3 -3
  124. package/packages/scrabble-solver/src/state/localStorage.ts +6 -6
  125. package/packages/scrabble-solver/src/state/sagas.ts +18 -7
  126. package/packages/scrabble-solver/src/state/selectors.ts +3 -3
  127. package/packages/scrabble-solver/src/state/slices/boardInitialState.ts +3 -3
  128. package/packages/scrabble-solver/src/state/slices/boardSlice.ts +20 -6
  129. package/packages/scrabble-solver/src/state/slices/settingsInitialState.ts +3 -4
  130. package/packages/scrabble-solver/src/state/slices/settingsSlice.ts +5 -5
  131. package/packages/scrabble-solver/src/styles/variables.scss +0 -9
  132. package/packages/solver/build/getPatternHash.js +2 -2
  133. package/packages/solver/build/solve.js +3 -1
  134. package/packages/solver/package-lock.json +3 -10
  135. package/packages/solver/package.json +5 -5
  136. package/packages/solver/src/fillPattern.test.ts +3 -3
  137. package/packages/solver/src/generatePatterns.test.ts +13 -0
  138. package/packages/solver/src/getPatternHash.ts +2 -2
  139. package/packages/solver/src/getPatternScore.test.ts +4 -3
  140. package/packages/solver/src/solve.test.ts +68 -6
  141. package/packages/solver/src/solve.ts +4 -1
  142. package/packages/types/build/Config.d.ts +2 -0
  143. package/packages/types/build/Config.js +3 -0
  144. package/packages/types/build/ConfigJson.d.ts +2 -1
  145. package/packages/types/build/Dictionary.d.ts +7 -0
  146. package/packages/types/build/Dictionary.js +2 -0
  147. package/packages/types/build/Game.d.ts +7 -0
  148. package/packages/types/build/Game.js +13 -0
  149. package/packages/types/build/Locale.d.ts +5 -0
  150. package/packages/types/build/Locale.js +5 -1
  151. package/packages/types/build/index.d.ts +4 -2
  152. package/packages/types/build/index.js +8 -5
  153. package/packages/types/package.json +2 -2
  154. package/packages/types/src/Config.ts +5 -0
  155. package/packages/types/src/ConfigJson.ts +2 -1
  156. package/packages/types/src/Dictionary.ts +9 -0
  157. package/packages/types/src/Game.ts +11 -0
  158. package/packages/types/src/Locale.ts +5 -1
  159. package/packages/types/src/index.ts +4 -2
  160. package/packages/word-definitions/build/lib/normalizeDefinition.js +3 -1
  161. package/packages/word-definitions/package-lock.json +13 -163
  162. package/packages/word-definitions/package.json +2 -2
  163. package/packages/word-definitions/src/lib/normalizeDefinition.ts +3 -1
  164. package/packages/word-lists/build/getFrFrWordList.js +1 -3
  165. package/packages/word-lists/package-lock.json +9 -401
  166. package/packages/word-lists/package.json +2 -2
  167. package/packages/word-lists/src/getFrFrWordList.ts +1 -3
  168. package/packages/configs/build/getLocaleConfig.d.ts +0 -3
  169. package/packages/configs/build/getLocaleConfig.js +0 -10
  170. package/packages/configs/build/isConfigId.d.ts +0 -2
  171. package/packages/configs/build/isConfigId.js +0 -12
  172. package/packages/configs/build/literaki/bonuses.d.ts +0 -14
  173. package/packages/configs/build/literaki/bonuses.js +0 -99
  174. package/packages/configs/build/literaki/index.d.ts +0 -1
  175. package/packages/configs/build/literaki/index.js +0 -8
  176. package/packages/configs/build/literaki/literaki.d.ts +0 -13
  177. package/packages/configs/build/literaki/literaki.js +0 -31
  178. package/packages/configs/build/literaki/tiles/index.d.ts +0 -6
  179. package/packages/configs/build/literaki/tiles/index.js +0 -18
  180. package/packages/configs/build/literaki/tiles/tilesDe.d.ts +0 -6
  181. package/packages/configs/build/literaki/tiles/tilesDe.js +0 -34
  182. package/packages/configs/build/literaki/tiles/tilesEn.d.ts +0 -6
  183. package/packages/configs/build/literaki/tiles/tilesEn.js +0 -31
  184. package/packages/configs/build/literaki/tiles/tilesEs.d.ts +0 -6
  185. package/packages/configs/build/literaki/tiles/tilesEs.js +0 -33
  186. package/packages/configs/build/literaki/tiles/tilesFa.d.ts +0 -6
  187. package/packages/configs/build/literaki/tiles/tilesFa.js +0 -37
  188. package/packages/configs/build/literaki/tiles/tilesFr.d.ts +0 -6
  189. package/packages/configs/build/literaki/tiles/tilesFr.js +0 -31
  190. package/packages/configs/build/literaki/tiles/tilesPl.d.ts +0 -6
  191. package/packages/configs/build/literaki/tiles/tilesPl.js +0 -37
  192. package/packages/configs/build/scrabble/bonuses.d.ts +0 -7
  193. package/packages/configs/build/scrabble/bonuses.js +0 -67
  194. package/packages/configs/build/scrabble/index.d.ts +0 -1
  195. package/packages/configs/build/scrabble/index.js +0 -8
  196. package/packages/configs/build/scrabble/scrabble.d.ts +0 -13
  197. package/packages/configs/build/scrabble/scrabble.js +0 -31
  198. package/packages/configs/build/scrabble/tiles/index.d.ts +0 -6
  199. package/packages/configs/build/scrabble/tiles/index.js +0 -18
  200. package/packages/configs/build/scrabble/tiles/tilesDe.d.ts +0 -6
  201. package/packages/configs/build/scrabble/tiles/tilesDe.js +0 -34
  202. package/packages/configs/build/scrabble/tiles/tilesEn.d.ts +0 -6
  203. package/packages/configs/build/scrabble/tiles/tilesEn.js +0 -31
  204. package/packages/configs/build/scrabble/tiles/tilesEs.d.ts +0 -6
  205. package/packages/configs/build/scrabble/tiles/tilesEs.js +0 -33
  206. package/packages/configs/build/scrabble/tiles/tilesFa.d.ts +0 -6
  207. package/packages/configs/build/scrabble/tiles/tilesFa.js +0 -37
  208. package/packages/configs/build/scrabble/tiles/tilesFr.d.ts +0 -6
  209. package/packages/configs/build/scrabble/tiles/tilesFr.js +0 -31
  210. package/packages/configs/build/scrabble/tiles/tilesPl.d.ts +0 -6
  211. package/packages/configs/build/scrabble/tiles/tilesPl.js +0 -37
  212. package/packages/configs/src/getLocaleConfig.ts +0 -9
  213. package/packages/configs/src/isConfigId.ts +0 -10
  214. package/packages/configs/src/literaki/bonuses.ts +0 -99
  215. package/packages/configs/src/literaki/index.ts +0 -1
  216. package/packages/configs/src/literaki/literaki.ts +0 -30
  217. package/packages/configs/src/literaki/tiles/index.ts +0 -6
  218. package/packages/configs/src/literaki/tiles/tilesDe.ts +0 -33
  219. package/packages/configs/src/literaki/tiles/tilesEn.ts +0 -30
  220. package/packages/configs/src/literaki/tiles/tilesEs.ts +0 -32
  221. package/packages/configs/src/literaki/tiles/tilesFa.ts +0 -36
  222. package/packages/configs/src/literaki/tiles/tilesFr.ts +0 -30
  223. package/packages/configs/src/literaki/tiles/tilesPl.ts +0 -36
  224. package/packages/configs/src/scrabble/bonuses.ts +0 -67
  225. package/packages/configs/src/scrabble/index.ts +0 -1
  226. package/packages/configs/src/scrabble/scrabble.ts +0 -30
  227. package/packages/configs/src/scrabble/tiles/index.ts +0 -6
  228. package/packages/configs/src/scrabble/tiles/tilesDe.ts +0 -33
  229. package/packages/configs/src/scrabble/tiles/tilesEn.ts +0 -30
  230. package/packages/configs/src/scrabble/tiles/tilesEs.ts +0 -32
  231. package/packages/configs/src/scrabble/tiles/tilesFa.ts +0 -36
  232. package/packages/configs/src/scrabble/tiles/tilesFr.ts +0 -30
  233. package/packages/configs/src/scrabble/tiles/tilesPl.ts +0 -36
  234. package/packages/dictionaries/.scrabble-solver/dictionaries/de-DE.txt +0 -1
  235. package/packages/dictionaries/.scrabble-solver/dictionaries/en-GB.txt +0 -1
  236. package/packages/dictionaries/.scrabble-solver/dictionaries/en-US.txt +0 -1
  237. package/packages/dictionaries/.scrabble-solver/dictionaries/es-ES.txt +0 -1
  238. package/packages/dictionaries/.scrabble-solver/dictionaries/fa-IR.txt +0 -1
  239. package/packages/dictionaries/.scrabble-solver/dictionaries/fr-FR.txt +0 -1
  240. package/packages/dictionaries/.scrabble-solver/dictionaries/pl-PL.txt +0 -1
  241. package/packages/scrabble-solver/.next/static/chunks/pages/_app-02851b06b95b19cb.js +0 -32
  242. package/packages/scrabble-solver/.next/static/chunks/pages/index-0ba5607d1aad8a09.js +0 -1
  243. package/packages/scrabble-solver/.next/static/css/09dfdea53eba31a9.css +0 -2
  244. package/packages/scrabble-solver/.next/static/css/60e8258da7362a1a.css +0 -1
  245. package/packages/scrabble-solver/src/i18n/i18n.module.scss +0 -27
  246. package/packages/scrabble-solver/src/modals/SettingsModal/components/ConfigSetting/options.ts +0 -19
  247. package/packages/scrabble-solver/src/modals/SettingsModal/components/ConfigSetting/types.ts +0 -9
  248. package/packages/scrabble-solver/src/modals/SettingsModal/components/InputModeSetting/types.ts +0 -7
  249. package/packages/scrabble-solver/src/modals/SettingsModal/components/LocaleSetting/types.ts +0 -9
  250. /package/packages/scrabble-solver/.next/static/{9dmPfnTc_AQTHBPvL7xQe → 8oRk1nUMQYFWmhu4SExQI}/_ssgManifest.js +0 -0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scrabble-solver/scrabble-solver",
3
- "version": "2.12.2",
3
+ "version": "2.12.4",
4
4
  "description": "Scrabble Solver 2 - App",
5
5
  "engines": {
6
6
  "node": ">=16"
@@ -31,13 +31,13 @@
31
31
  "@floating-ui/react": "^0.22.3",
32
32
  "@kamilmielnik/trie": "^2.0.1",
33
33
  "@reduxjs/toolkit": "^1.9.3",
34
- "@scrabble-solver/configs": "^2.12.2",
35
- "@scrabble-solver/constants": "^2.12.2",
36
- "@scrabble-solver/dictionaries": "^2.12.2",
37
- "@scrabble-solver/logger": "^2.12.2",
38
- "@scrabble-solver/solver": "^2.12.2",
39
- "@scrabble-solver/types": "^2.12.2",
40
- "@scrabble-solver/word-definitions": "^2.12.2",
34
+ "@scrabble-solver/configs": "^2.12.4",
35
+ "@scrabble-solver/constants": "^2.12.4",
36
+ "@scrabble-solver/dictionaries": "^2.12.4",
37
+ "@scrabble-solver/logger": "^2.12.4",
38
+ "@scrabble-solver/solver": "^2.12.4",
39
+ "@scrabble-solver/types": "^2.12.4",
40
+ "@scrabble-solver/word-definitions": "^2.12.4",
41
41
  "classnames": "^2.3.2",
42
42
  "include-media": "^2.0.0",
43
43
  "include-media-query-builder": "^1.1.0",
@@ -17,18 +17,14 @@
17
17
  }
18
18
 
19
19
  [dir='ltr'] & {
20
- &:nth-child(15n + 1),
21
- &:nth-child(15n + 2),
22
- &:nth-child(15n + 3) {
20
+ &.first3 {
23
21
  input {
24
22
  left: 0;
25
23
  clip-path: polygon(0 (100% / 3), (100% / 3) (100% / 3), (100% / 3) (200% / 3), 0 (200% / 3));
26
24
  }
27
25
  }
28
26
 
29
- &:nth-last-child(15n + 1),
30
- &:nth-last-child(15n + 2),
31
- &:nth-last-child(15n + 3) {
27
+ &.last3 {
32
28
  input {
33
29
  left: -200%;
34
30
  clip-path: polygon((200% / 3) (100% / 3), 100% (100% / 3), 100% (200% / 3), (200% / 3) (200% / 3));
@@ -37,9 +33,7 @@
37
33
  }
38
34
 
39
35
  [dir='rtl'] & {
40
- &:nth-child(15n + 1),
41
- &:nth-child(15n + 2),
42
- &:nth-child(15n + 3) {
36
+ &.first3 {
43
37
  input {
44
38
  left: -200%;
45
39
  right: 0;
@@ -47,9 +41,7 @@
47
41
  }
48
42
  }
49
43
 
50
- &:nth-last-child(15n + 1),
51
- &:nth-last-child(15n + 2),
52
- &:nth-last-child(15n + 3) {
44
+ &.last3 {
53
45
  input {
54
46
  left: 0;
55
47
  right: -200%;
@@ -13,6 +13,7 @@ import {
13
13
 
14
14
  import {
15
15
  selectCellIsValid,
16
+ selectConfig,
16
17
  selectInputMode,
17
18
  selectLocale,
18
19
  selectTilePoints,
@@ -52,6 +53,7 @@ const Cell: FunctionComponent<Props> = ({
52
53
  const { tile, x, y } = cell;
53
54
  const translate = useTranslate();
54
55
  const locale = useTypedSelector(selectLocale);
56
+ const config = useTypedSelector(selectConfig);
55
57
  const inputMode = useTypedSelector(selectInputMode);
56
58
  const points = useTypedSelector((state) => selectTilePoints(state, cell.tile));
57
59
  const isValid = useTypedSelector((state) => selectCellIsValid(state, cell));
@@ -98,6 +100,8 @@ const Cell: FunctionComponent<Props> = ({
98
100
  y: (y + 1).toLocaleString(locale),
99
101
  })}
100
102
  className={classNames(styles.tile, className, {
103
+ [styles.first3]: x < 3,
104
+ [styles.last3]: config.boardWidth - x - 1 < 3,
101
105
  [styles.sharpTopLeft]: cellTop?.hasTile() || cellLeft?.hasTile(),
102
106
  [styles.sharpTopRight]: cellTop?.hasTile() || cellRight?.hasTile(),
103
107
  [styles.sharpBottomLeft]: cellBottom?.hasTile() || cellLeft?.hasTile(),
@@ -21,6 +21,7 @@ const VERTICAL_LINE = 'v';
21
21
  const BONUS = 'b';
22
22
  const BONUS_WORD_2 = 'b2';
23
23
  const BONUS_WORD_3 = 'b3';
24
+ const BONUS_WORD_4 = 'b4';
24
25
  const CELL_FILTER = 'c';
25
26
 
26
27
  const useBackgroundImage = () => {
@@ -41,6 +42,7 @@ const useBackgroundImage = () => {
41
42
  const characterBonuses = config.bonuses.filter((bonus) => bonus.type === BONUS_CHARACTER);
42
43
  const word2Bonuses = config.bonuses.filter((bonus) => bonus.type === BONUS_WORD && bonus.multiplier === 2);
43
44
  const word3Bonuses = config.bonuses.filter((bonus) => bonus.type === BONUS_WORD && bonus.multiplier === 3);
45
+ const word4Bonuses = config.bonuses.filter((bonus) => bonus.type === BONUS_WORD && bonus.multiplier === 4);
44
46
 
45
47
  const getX = (point: Point): number => point.x * (cellSize + BORDER_WIDTH);
46
48
 
@@ -101,6 +103,23 @@ const useBackgroundImage = () => {
101
103
  </text>
102
104
  </symbol>
103
105
 
106
+ <symbol id={BONUS_WORD_4}>
107
+ <rect height={bonusSize} rx={borderRadius} width={bonusSize} x={bonusOffset} y={bonusOffset} />
108
+
109
+ <text
110
+ dominantBaseline="central"
111
+ fill="white"
112
+ fontFamily="system-ui, sans-serif"
113
+ fontSize={fontSize}
114
+ fontWeight="bold"
115
+ textAnchor="middle"
116
+ x={fontOffset}
117
+ y={fontOffset}
118
+ >
119
+ x4
120
+ </text>
121
+ </symbol>
122
+
104
123
  <symbol id={CELL_FILTER}>
105
124
  <rect
106
125
  fill={COLOR_FILTERED}
@@ -137,6 +156,10 @@ const useBackgroundImage = () => {
137
156
  <use fill={getBonusColor(bonus)} key={index} href={`#${BONUS_WORD_3}`} x={getX(bonus)} y={getY(bonus)} />
138
157
  ))}
139
158
 
159
+ {word4Bonuses.map((bonus, index) => (
160
+ <use fill={getBonusColor(bonus)} key={index} href={`#${BONUS_WORD_4}`} x={getX(bonus)} y={getY(bonus)} />
161
+ ))}
162
+
140
163
  <rect
141
164
  fill={COLOR_BONUS_START}
142
165
  height={bonusSize}
@@ -1,11 +1,11 @@
1
- import { literaki } from '@scrabble-solver/configs';
2
- import { Locale } from '@scrabble-solver/types';
1
+ import { getConfig } from '@scrabble-solver/configs';
2
+ import { Game, Locale } from '@scrabble-solver/types';
3
3
 
4
4
  import {
5
5
  PLAIN_TILES_COLOR_DEFAULT,
6
6
  PLAIN_TILES_POINTS_COLORS,
7
- PLAIN_TILES_TILE_MAX_SCATTER,
8
7
  PLAIN_TILES_TILE_MAX_ROTATE,
8
+ PLAIN_TILES_TILE_MAX_SCATTER,
9
9
  PLAIN_TILES_TILE_SIZE,
10
10
  } from 'parameters';
11
11
 
@@ -16,7 +16,7 @@ import getY from './getY';
16
16
  import randomize from './randomize';
17
17
 
18
18
  const createPlainTile = ({ cellIndex, character, color, rowIndex, showPoints }: CreatePlainTileOptions): PlainTile => {
19
- const configPoints = literaki[Locale.EN_US].getCharacterPoints(character.toLowerCase());
19
+ const configPoints = getConfig(Game.Literaki, Locale.EN_US).getCharacterPoints(character.toLowerCase());
20
20
  const points = showPoints ? configPoints : undefined;
21
21
  const defaultColor =
22
22
  typeof configPoints === 'number' ? PLAIN_TILES_POINTS_COLORS[configPoints] : PLAIN_TILES_COLOR_DEFAULT;
@@ -22,6 +22,10 @@ $radio-box-size: $radio-size + 2 * $radio-inner-border;
22
22
  }
23
23
  }
24
24
  }
25
+
26
+ &.disabled {
27
+ opacity: var(--opacity--disabled);
28
+ }
25
29
  }
26
30
 
27
31
  .input {
@@ -17,6 +17,7 @@ const Radio: FunctionComponent<Props> = ({ checked, children, className, disable
17
17
  <label
18
18
  className={classNames(styles.radio, className, {
19
19
  [styles.checked]: checked,
20
+ [styles.disabled]: disabled,
20
21
  })}
21
22
  >
22
23
  <input
@@ -10,9 +10,9 @@ const INVISIBLE_STYLE: CSSProperties = {
10
10
 
11
11
  const SeoMessage: FunctionComponent = () => (
12
12
  <p style={INVISIBLE_STYLE}>
13
- Scrabble Solver 2 is a free and open-source analysis tool for Scrabble and Literaki. Quickly find top scoring words
14
- using given letters and board state. Available in English, French, German, Polish & Spanish. Source code is
15
- available on GitHub - contributions are welcome!
13
+ Scrabble Solver 2 is a free and open-source analysis tool for Scrabble, Super Scrabble &amp; Literaki. Quickly find
14
+ top scoring words using given letters and board state. Available in English, French, German, Polish & Spanish.
15
+ Source code is available on GitHub - contributions are welcome!
16
16
  </p>
17
17
  );
18
18
 
@@ -2,7 +2,6 @@
2
2
 
3
3
  import {
4
4
  BOARD_TILE_SIZE_MAX,
5
- BOARD_TILE_SIZE_MIN,
6
5
  BORDER_WIDTH,
7
6
  BUTTON_HEIGHT,
8
7
  COMPONENTS_SPACING,
@@ -47,7 +46,7 @@ const useAppLayout = () => {
47
46
  : Math.max(solverHeight - bottomContainerHeight, 0);
48
47
  const cellWidth = (maxBoardWidth - (config.boardWidth + 1) * BORDER_WIDTH) / config.boardWidth;
49
48
  const cellHeight = (maxBoardHeight - (config.boardHeight + 1) * BORDER_WIDTH) / config.boardHeight;
50
- const cellSize = Math.min(Math.max(Math.min(cellWidth, cellHeight), BOARD_TILE_SIZE_MIN), BOARD_TILE_SIZE_MAX);
49
+ const cellSize = Math.min(Math.min(cellWidth, cellHeight), BOARD_TILE_SIZE_MAX);
51
50
  const boardSize = (cellSize + BORDER_WIDTH) * config.boardWidth + BORDER_WIDTH;
52
51
  const maxControlsWidth = tileSize * config.maximumCharactersCount + 2 * BORDER_WIDTH;
53
52
  const showResultsInModal = isLessThanL;
@@ -4,7 +4,7 @@ import {
4
4
  localStorage,
5
5
  selectAutoGroupTiles,
6
6
  selectBoard,
7
- selectConfigId,
7
+ selectGame,
8
8
  selectInputMode,
9
9
  selectLocale,
10
10
  selectRack,
@@ -14,7 +14,7 @@ import {
14
14
  const useLocalStorage = () => {
15
15
  const autoGroupTiles = useTypedSelector(selectAutoGroupTiles);
16
16
  const board = useTypedSelector(selectBoard);
17
- const configId = useTypedSelector(selectConfigId);
17
+ const game = useTypedSelector(selectGame);
18
18
  const inputMode = useTypedSelector(selectInputMode);
19
19
  const locale = useTypedSelector(selectLocale);
20
20
  const rack = useTypedSelector(selectRack);
@@ -32,10 +32,10 @@ const useLocalStorage = () => {
32
32
  }, [board]);
33
33
 
34
34
  useEffect(() => {
35
- if (configId) {
36
- localStorage.setConfigId(configId);
35
+ if (game) {
36
+ localStorage.setGame(game);
37
37
  }
38
- }, [configId]);
38
+ }, [game]);
39
39
 
40
40
  useEffect(() => {
41
41
  if (inputMode) {
@@ -4,12 +4,14 @@ import { FunctionComponent, SVGAttributes } from 'react';
4
4
 
5
5
  import { FlagDe, FlagEs, FlagFa, FlagFr, FlagGb, FlagPl, FlagUs } from 'icons';
6
6
 
7
- import styles from './i18n.module.scss';
8
-
9
7
  interface LocaleFeatures {
10
8
  comma: string;
11
9
  consonants: boolean;
12
10
  direction: 'ltr' | 'rtl';
11
+ Icon: FunctionComponent<SVGAttributes<SVGElement>>;
12
+ label: string;
13
+ locale: Locale;
14
+ name: string;
13
15
  separator: string;
14
16
  vowels: boolean;
15
17
  }
@@ -19,6 +21,10 @@ export const LOCALE_FEATURES: Record<Locale, LocaleFeatures> = {
19
21
  comma: COMMA_LATIN,
20
22
  consonants: true,
21
23
  direction: 'ltr',
24
+ Icon: FlagDe,
25
+ label: 'Deutsch',
26
+ locale: Locale.DE_DE,
27
+ name: 'German',
22
28
  separator: `${COMMA_LATIN} `,
23
29
  vowels: true,
24
30
  },
@@ -26,6 +32,10 @@ export const LOCALE_FEATURES: Record<Locale, LocaleFeatures> = {
26
32
  comma: COMMA_LATIN,
27
33
  consonants: true,
28
34
  direction: 'ltr',
35
+ Icon: FlagGb,
36
+ label: 'English (GB)',
37
+ locale: Locale.EN_GB,
38
+ name: 'English (GB)',
29
39
  separator: `${COMMA_LATIN} `,
30
40
  vowels: true,
31
41
  },
@@ -33,6 +43,10 @@ export const LOCALE_FEATURES: Record<Locale, LocaleFeatures> = {
33
43
  comma: COMMA_LATIN,
34
44
  consonants: true,
35
45
  direction: 'ltr',
46
+ Icon: FlagUs,
47
+ label: 'English (US)',
48
+ locale: Locale.EN_US,
49
+ name: 'English (US)',
36
50
  separator: `${COMMA_LATIN} `,
37
51
  vowels: true,
38
52
  },
@@ -40,6 +54,10 @@ export const LOCALE_FEATURES: Record<Locale, LocaleFeatures> = {
40
54
  comma: COMMA_LATIN,
41
55
  consonants: true,
42
56
  direction: 'ltr',
57
+ Icon: FlagEs,
58
+ label: 'Español',
59
+ locale: Locale.ES_ES,
60
+ name: 'Spanish',
43
61
  separator: `${COMMA_LATIN} `,
44
62
  vowels: true,
45
63
  },
@@ -47,6 +65,10 @@ export const LOCALE_FEATURES: Record<Locale, LocaleFeatures> = {
47
65
  comma: COMMA_ARABIC,
48
66
  consonants: false,
49
67
  direction: 'rtl',
68
+ Icon: FlagFa,
69
+ label: 'فارسی',
70
+ locale: Locale.FA_IR,
71
+ name: 'Persian',
50
72
  separator: `${COMMA_ARABIC} `,
51
73
  vowels: false,
52
74
  },
@@ -54,6 +76,10 @@ export const LOCALE_FEATURES: Record<Locale, LocaleFeatures> = {
54
76
  comma: COMMA_LATIN,
55
77
  consonants: true,
56
78
  direction: 'ltr',
79
+ Icon: FlagFr,
80
+ label: 'Français',
81
+ locale: Locale.FR_FR,
82
+ name: 'French',
57
83
  separator: `${COMMA_LATIN} `,
58
84
  vowels: true,
59
85
  },
@@ -61,67 +87,11 @@ export const LOCALE_FEATURES: Record<Locale, LocaleFeatures> = {
61
87
  comma: COMMA_LATIN,
62
88
  consonants: true,
63
89
  direction: 'ltr',
64
- separator: `${COMMA_LATIN} `,
65
- vowels: true,
66
- },
67
- };
68
-
69
- interface Flag {
70
- className: string;
71
- Icon: FunctionComponent<SVGAttributes<SVGElement>>;
72
- label: string;
73
- name: string;
74
- value: Locale;
75
- }
76
-
77
- export const LOCALE_FLAGS: Record<Locale, Flag> = {
78
- [Locale.DE_DE]: {
79
- className: styles.de,
80
- Icon: FlagDe,
81
- label: 'Deutsch',
82
- name: 'German',
83
- value: Locale.DE_DE,
84
- },
85
- [Locale.EN_GB]: {
86
- className: styles.gb,
87
- Icon: FlagGb,
88
- label: 'English (GB)',
89
- name: 'English (GB)',
90
- value: Locale.EN_GB,
91
- },
92
- [Locale.EN_US]: {
93
- className: styles.us,
94
- Icon: FlagUs,
95
- label: 'English (US)',
96
- name: 'English (US)',
97
- value: Locale.EN_US,
98
- },
99
- [Locale.ES_ES]: {
100
- className: styles.es,
101
- Icon: FlagEs,
102
- label: 'Español',
103
- name: 'Spanish',
104
- value: Locale.ES_ES,
105
- },
106
- [Locale.FA_IR]: {
107
- className: styles.fa,
108
- Icon: FlagFa,
109
- label: 'فارسی',
110
- name: 'Persian',
111
- value: Locale.FA_IR,
112
- },
113
- [Locale.FR_FR]: {
114
- className: styles.fr,
115
- Icon: FlagFr,
116
- label: 'Français',
117
- name: 'French',
118
- value: Locale.FR_FR,
119
- },
120
- [Locale.PL_PL]: {
121
- className: styles.pl,
122
90
  Icon: FlagPl,
123
91
  label: 'Polski',
92
+ locale: Locale.PL_PL,
124
93
  name: 'Polish',
125
- value: Locale.PL_PL,
94
+ separator: `${COMMA_LATIN} `,
95
+ vowels: true,
126
96
  },
127
97
  };
@@ -1,6 +1,6 @@
1
- import { scrabble } from '@scrabble-solver/configs';
1
+ import { getConfig } from '@scrabble-solver/configs';
2
2
  import { BLANK } from '@scrabble-solver/constants';
3
- import { Locale } from '@scrabble-solver/types';
3
+ import { Game, Locale } from '@scrabble-solver/types';
4
4
 
5
5
  import extractCharacters from './extractCharacters';
6
6
 
@@ -16,7 +16,7 @@ const tests = [
16
16
 
17
17
  describe('extractCharacters', () => {
18
18
  const locale = Locale.ES_ES;
19
- const config = scrabble[locale];
19
+ const config = getConfig(Game.Scrabble, locale);
20
20
 
21
21
  for (const { input, expected } of tests) {
22
22
  it(`[${locale}] "${input}"`, () => {
@@ -1,6 +1,6 @@
1
- import { scrabble } from '@scrabble-solver/configs';
1
+ import { getConfig } from '@scrabble-solver/configs';
2
2
  import { BLANK } from '@scrabble-solver/constants';
3
- import { Locale } from '@scrabble-solver/types';
3
+ import { Game, Locale } from '@scrabble-solver/types';
4
4
 
5
5
  import extractCharactersByCase from './extractCharactersByCase';
6
6
 
@@ -21,7 +21,7 @@ const tests = [
21
21
 
22
22
  describe('extractCharactersByCase', () => {
23
23
  const locale = Locale.ES_ES;
24
- const config = scrabble[locale];
24
+ const config = getConfig(Game.Scrabble, locale);
25
25
 
26
26
  for (const { input, expected } of tests) {
27
27
  it(`[${locale}] "${input}"`, () => {
@@ -1,12 +1,12 @@
1
1
  import { Config } from '@scrabble-solver/types';
2
2
 
3
- import { BOARD_CELL_BORDER_WIDTH, BOARD_TILE_SIZE_MAX, BOARD_TILE_SIZE_MIN } from 'parameters';
3
+ import { BOARD_CELL_BORDER_WIDTH, BOARD_TILE_SIZE_MAX } from 'parameters';
4
4
 
5
5
  const getCellSize = (config: Config, width: number, height: number): number => {
6
6
  const maxWidth = (width - BOARD_CELL_BORDER_WIDTH) / config.boardWidth - BOARD_CELL_BORDER_WIDTH;
7
7
  const maxHeight = (height - BOARD_CELL_BORDER_WIDTH) / config.boardHeight - BOARD_CELL_BORDER_WIDTH;
8
8
  const cellSize = Math.min(maxWidth, maxHeight);
9
- return Math.floor(Math.min(Math.max(cellSize, BOARD_TILE_SIZE_MIN), BOARD_TILE_SIZE_MAX));
9
+ return Math.floor(Math.min(cellSize, BOARD_TILE_SIZE_MAX));
10
10
  };
11
11
 
12
12
  export default getCellSize;
@@ -42,7 +42,6 @@
42
42
 
43
43
  .flag {
44
44
  position: fixed;
45
- width: calc(var(--button--icon--size) * var(--aspect-ratio));
46
45
  height: var(--button--icon--size);
47
46
  border-radius: var(--border--radius);
48
47
  box-shadow: 0 0 0 1px var(--box-shadow--color);
@@ -1,7 +1,7 @@
1
1
  import { FunctionComponent, memo } from 'react';
2
2
 
3
3
  import { Button, Modal } from 'components';
4
- import { LOCALE_FLAGS } from 'i18n';
4
+ import { LOCALE_FEATURES } from 'i18n';
5
5
  import { BookHalf, CardChecklist, Cog, Github, Sack } from 'icons';
6
6
  import { GITHUB_PROJECT_URL } from 'parameters';
7
7
  import { selectLocale, useTranslate, useTypedSelector } from 'state';
@@ -29,7 +29,7 @@ const MenuModal: FunctionComponent<Props> = ({
29
29
  }) => {
30
30
  const translate = useTranslate();
31
31
  const locale = useTypedSelector(selectLocale);
32
- const Flag = LOCALE_FLAGS[locale];
32
+ const { Icon } = LOCALE_FEATURES[locale];
33
33
 
34
34
  return (
35
35
  <Modal className={className} isOpen={isOpen} title={translate('menu')} onClose={onClose}>
@@ -64,7 +64,7 @@ const MenuModal: FunctionComponent<Props> = ({
64
64
  <Button aria-label={translate('settings')} className={styles.button} Icon={Cog} onClick={onShowSettings}>
65
65
  <div className={styles.settings}>
66
66
  <div className={styles.settingsLabel}>{translate('settings')}</div>
67
- <Flag.Icon className={styles.flag} />
67
+ <Icon className={styles.flag} />
68
68
  </div>
69
69
  </Button>
70
70
  </Modal>
@@ -1,11 +1,12 @@
1
+ import { games, hasConfig } from '@scrabble-solver/configs';
2
+ import { isGame } from '@scrabble-solver/types';
1
3
  import { ChangeEvent, FunctionComponent } from 'react';
2
4
  import { useDispatch } from 'react-redux';
3
5
 
4
6
  import { Radio } from 'components';
5
- import { selectConfigId, settingsSlice, useTypedSelector } from 'state';
7
+ import { selectGame, selectLocale, settingsSlice, useTypedSelector } from 'state';
6
8
 
7
9
  import styles from './ConfigSetting.module.scss';
8
- import options from './options';
9
10
 
10
11
  interface Props {
11
12
  className?: string;
@@ -14,21 +15,29 @@ interface Props {
14
15
 
15
16
  const ConfigSetting: FunctionComponent<Props> = ({ className, disabled }) => {
16
17
  const dispatch = useDispatch();
17
- const configId = useTypedSelector(selectConfigId);
18
+ const game = useTypedSelector(selectGame);
19
+ const locale = useTypedSelector(selectLocale);
20
+ const options = Object.values(games).map((gameConfig) => ({
21
+ disabled: !hasConfig(gameConfig.game, locale),
22
+ label: gameConfig.name,
23
+ value: gameConfig.game,
24
+ }));
18
25
 
19
26
  const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
20
- dispatch(settingsSlice.actions.changeConfigId(event.target.value));
27
+ if (isGame(event.target.value)) {
28
+ dispatch(settingsSlice.actions.changeGame(event.target.value));
29
+ }
21
30
  };
22
31
 
23
32
  return (
24
33
  <div className={className}>
25
34
  {options.map((option) => (
26
35
  <Radio
27
- checked={configId === option.value}
36
+ checked={game === option.value}
28
37
  className={styles.option}
29
- disabled={disabled}
38
+ disabled={disabled || option.disabled}
30
39
  key={option.value}
31
- name="configId"
40
+ name="game"
32
41
  value={option.value}
33
42
  onChange={handleChange}
34
43
  >
@@ -13,10 +13,7 @@
13
13
  }
14
14
 
15
15
  .flag {
16
- --height: 32px;
17
-
18
- width: calc(var(--height) * var(--aspect-ratio));
19
- height: var(--height);
16
+ height: 32px;
20
17
  border-radius: var(--border--radius);
21
18
  box-shadow: var(--box-shadow);
22
19
  transition: var(--transition);
@@ -4,7 +4,7 @@ import { ChangeEvent, FunctionComponent } from 'react';
4
4
  import { useDispatch } from 'react-redux';
5
5
 
6
6
  import { Radio } from 'components';
7
- import { LOCALE_FLAGS } from 'i18n';
7
+ import { LOCALE_FEATURES } from 'i18n';
8
8
  import { selectLocale, settingsSlice, useTypedSelector } from 'state';
9
9
 
10
10
  import styles from './LocaleSetting.module.scss';
@@ -14,7 +14,7 @@ interface Props {
14
14
  disabled: boolean;
15
15
  }
16
16
 
17
- const OPTIONS = Object.values(LOCALE_FLAGS).sort((a, b) => a.name.localeCompare(b.name));
17
+ const OPTIONS = Object.values(LOCALE_FEATURES).sort((a, b) => a.name.localeCompare(b.name));
18
18
 
19
19
  const LocaleSetting: FunctionComponent<Props> = ({ className, disabled }) => {
20
20
  const dispatch = useDispatch();
@@ -29,18 +29,18 @@ const LocaleSetting: FunctionComponent<Props> = ({ className, disabled }) => {
29
29
  <div className={className}>
30
30
  {OPTIONS.map(({ Icon, ...option }) => (
31
31
  <Radio
32
- checked={locale === option.value}
32
+ checked={locale === option.locale}
33
33
  className={classNames(styles.option, className, {
34
- [styles.checked]: locale === option.value,
34
+ [styles.checked]: locale === option.locale,
35
35
  })}
36
36
  disabled={disabled}
37
- key={option.value}
37
+ key={option.locale}
38
38
  name="locale"
39
- value={option.value}
39
+ value={option.locale}
40
40
  onChange={handleChange}
41
41
  >
42
- <span className={classNames(styles.label, option.className)}>
43
- <Icon className={classNames(styles.flag, option.className)} />
42
+ <span className={styles.label}>
43
+ <Icon className={styles.flag} />
44
44
 
45
45
  <span>{option.label}</span>
46
46
  </span>
@@ -10,12 +10,14 @@ import 'styles/global.scss';
10
10
 
11
11
  const DESCRIPTION =
12
12
  // eslint-disable-next-line max-len
13
- 'Scrabble Solver 2 - Free and open-source analysis tool for Scrabble and Literaki. Quickly find top scoring words using given letters and board state. Available in English, French, German, Polish & Spanish.';
13
+ 'Scrabble Solver 2 - Free and open-source analysis tool for Scrabble, Super Scrabble & Literaki. Quickly find top scoring words using given letters and board state. Available in English, French, German, Polish & Spanish.';
14
14
 
15
15
  const KEYWORDS = [
16
16
  'Scrabble Solver',
17
17
  'Scrabble',
18
18
  'Solver',
19
+ 'Super Scrabble',
20
+ 'Super Scrabble Solver',
19
21
  'Board',
20
22
  'Open-source',
21
23
  'Open',
@@ -1,8 +1,8 @@
1
- import { scrabble } from '@scrabble-solver/configs';
1
+ import { games } from '@scrabble-solver/configs';
2
2
  import { COMMA_ARABIC, COMMA_LATIN } from '@scrabble-solver/constants';
3
3
  import { dictionaries } from '@scrabble-solver/dictionaries';
4
4
  import logger from '@scrabble-solver/logger';
5
- import { isLocale, Locale } from '@scrabble-solver/types';
5
+ import { Locale, isLocale } from '@scrabble-solver/types';
6
6
  import { getWordDefinition } from '@scrabble-solver/word-definitions';
7
7
  import { NextApiRequest, NextApiResponse } from 'next';
8
8
 
@@ -13,7 +13,10 @@ interface RequestData {
13
13
  words: string[];
14
14
  }
15
15
 
16
- const MAXIMUM_COLLISIONS_COUNT = scrabble['en-US'].maximumCharactersCount;
16
+ const MAXIMUM_COLLISIONS_COUNT = Object.values(games).reduce(
17
+ (result, game) => Math.max(result, game.maximumCharactersCount),
18
+ 0,
19
+ );
17
20
  const MAXIMUM_WORDS_COUNT = MAXIMUM_COLLISIONS_COUNT + 1;
18
21
 
19
22
  const dictionary = async (request: NextApiRequest, response: NextApiResponse): Promise<void> => {