lettras 0.1.0 → 0.2.1
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.
- package/README.md +66 -1
- package/bin/lettras.js +15 -4
- package/engine/index.js +3 -3
- package/engine/lettras_engine.d.ts +21 -0
- package/engine/lettras_engine.js +32 -0
- package/package.json +1 -1
- package/src/index.d.ts +14 -2
- package/src/index.js +28 -2
package/README.md
CHANGED
|
@@ -7,6 +7,8 @@ kept as one cell each. Runs locally (WebAssembly): no network, no API key. Libra
|
|
|
7
7
|
npm install lettras
|
|
8
8
|
```
|
|
9
9
|
|
|
10
|
+
[npm package](https://www.npmjs.com/package/lettras) · [source and docs](https://github.com/Artificialss/lettras-sdk)
|
|
11
|
+
|
|
10
12
|
```js
|
|
11
13
|
import { generate, render } from 'lettras';
|
|
12
14
|
|
|
@@ -17,8 +19,16 @@ puzzle.placements; // where each word is hidden: start (r, c), step (dr, dc), l
|
|
|
17
19
|
puzzle.unplaced; // words that did not fit
|
|
18
20
|
```
|
|
19
21
|
|
|
22
|
+
```js
|
|
23
|
+
import { generate, fill, render } from 'lettras';
|
|
24
|
+
|
|
25
|
+
const puzzle = generate({ words: ['gato', 'perro', 'piña'], rows: 9, cols: 12, position: 'mixed', seed: 8 });
|
|
26
|
+
const done = fill(puzzle, { lang: 'es', accents: true }); // random letters in the empty cells
|
|
27
|
+
console.log(done.grid.map((row) => row.join(' ')).join('\n'));
|
|
28
|
+
```
|
|
29
|
+
|
|
20
30
|
```bash
|
|
21
|
-
npx lettras --words gato,perro,piña --rows 9 --cols 12 --position mixed
|
|
31
|
+
npx lettras --words gato,perro,piña --rows 9 --cols 12 --position mixed --random --accents on
|
|
22
32
|
```
|
|
23
33
|
|
|
24
34
|
## Options
|
|
@@ -34,12 +44,67 @@ npx lettras --words gato,perro,piña --rows 9 --cols 12 --position mixed
|
|
|
34
44
|
| `classicMode` | Strip accents in the grid. |
|
|
35
45
|
| `fill` | Empty-cell character, default `-`. |
|
|
36
46
|
|
|
47
|
+
`generate` leaves empty cells as `-`. **`fill(puzzleOrGrid, { lang, accents, seed })`** completes them: letters follow the
|
|
48
|
+
language's letter frequency, `accents: false` limits them to A-Z, and without a `seed` every call is different. Passing the
|
|
49
|
+
puzzle (instead of a bare matrix) also protects its words from accidental extra copies. CLI: `--random` and `--accents on|off`.
|
|
50
|
+
|
|
51
|
+
**Example.** The same puzzle before and after `fill` (Spanish, seed 5):
|
|
52
|
+
|
|
53
|
+
```js
|
|
54
|
+
const puzzle = generate({ words: ['gato', 'perro', 'piña', 'mono', 'cebra'], rows: 8, cols: 10, position: 'mixed', seed: 8 });
|
|
55
|
+
const done = fill(puzzle, { lang: 'es', accents: true, seed: 5 });
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
`puzzle.grid` has `-` in every empty cell; `done.grid` replaces them (58 cells here):
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
C E B R A - O - - -
|
|
62
|
+
- - - - - - - T O -
|
|
63
|
+
- - - - M - - R A -
|
|
64
|
+
- - - O - - R - - G
|
|
65
|
+
- - N - - E - - - -
|
|
66
|
+
- O - - P - - - - -
|
|
67
|
+
- - - - - - - - - -
|
|
68
|
+
- - - - - - A Ñ I P
|
|
69
|
+
```
|
|
70
|
+
```
|
|
71
|
+
C E B R A R O G G J
|
|
72
|
+
D R A E E R C T O D
|
|
73
|
+
B Ó E E M Í M R A Ñ
|
|
74
|
+
T S C O N R R A E G
|
|
75
|
+
T R N E A E R O E M
|
|
76
|
+
I O O E P S N P A O
|
|
77
|
+
O C O O A P P A U A
|
|
78
|
+
I R E A A S A Ñ I P
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
With `accents: false` the filler uses plain A-Z only (the one `Ñ` left is the hidden word *piña*, which keeps its spelling):
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
C E B R A R O G G I
|
|
85
|
+
D Q A E E P C T O D
|
|
86
|
+
B Y E E M X M R A N
|
|
87
|
+
S R C O N R R A E G
|
|
88
|
+
S R N E A E R O E M
|
|
89
|
+
I O O E P S N O A O
|
|
90
|
+
O B O O A P O A T A
|
|
91
|
+
H R E A A S A Ñ I P
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Same grid, language, accents and `seed` always give the same filler on every platform. Without a `seed` the wrappers
|
|
95
|
+
pick a random one, so every call gives different letters.
|
|
96
|
+
|
|
37
97
|
CLI flags mirror these: `--words a,b,c --rows N --cols N --position P --difficulty N --clustering N --seed N --lang xx
|
|
38
98
|
--classic --fill C`, plus `--json`, `--solution` and `--stdin`.
|
|
39
99
|
|
|
40
100
|
`generate` throws on invalid input (for example zero rows). Words that cannot be placed are listed in `unplaced`;
|
|
41
101
|
words that are refused (spaces, digits, duplicates) are listed in `rejected` with a reason.
|
|
42
102
|
|
|
103
|
+
## Module format
|
|
104
|
+
|
|
105
|
+
The package is ESM only: use `import { generate, fill } from 'lettras'`. From CommonJS use `const { generate } = await import('lettras')`.
|
|
106
|
+
It needs Node 20 or newer (or any modern browser bundler) and ships its own TypeScript types.
|
|
107
|
+
|
|
43
108
|
## License
|
|
44
109
|
|
|
45
110
|
Wrapper, CLI and types: MIT. The compiled engine in `engine/` is proprietary: use it unmodified through this package;
|
package/bin/lettras.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// lettras --words sol,luna,mar --rows 8 --cols 8 [--position horizontal|vertical|mixed] [--seed 7]
|
|
3
|
-
// [--difficulty 1-4] [--clustering 0-1] [--lang es] [--classic] [--fill -] [--
|
|
3
|
+
// [--difficulty 1-4] [--clustering 0-1] [--lang es] [--classic] [--fill -] [--random] [--accents on|off]
|
|
4
|
+
// [--json] [--solution]
|
|
4
5
|
// or: echo '{"words":["sol"],"rows":6,"cols":6}' | lettras --stdin
|
|
5
6
|
import { readFileSync } from 'node:fs';
|
|
6
7
|
import { generate, renderPuzzle } from '../engine/index.js';
|
|
8
|
+
import { fill } from '../src/index.js';
|
|
7
9
|
|
|
8
10
|
const HELP = `lettras: word-search generator
|
|
9
11
|
|
|
@@ -18,12 +20,14 @@ const HELP = `lettras: word-search generator
|
|
|
18
20
|
--lang xx es en pt fr de it
|
|
19
21
|
--classic strip accents in the grid
|
|
20
22
|
--fill C empty-cell character (default -)
|
|
23
|
+
--random fill the empty cells with random letters
|
|
24
|
+
--accents on|off with --random: use the language's accented letters (default on; off with --classic)
|
|
21
25
|
--json print the JSON result
|
|
22
26
|
--solution show only the hidden words
|
|
23
27
|
--stdin read the JSON input from stdin`;
|
|
24
28
|
|
|
25
29
|
function parse(argv) {
|
|
26
|
-
const flags = new Set(['classic', 'json', 'solution', 'stdin', 'help']);
|
|
30
|
+
const flags = new Set(['classic', 'json', 'solution', 'stdin', 'help', 'random']);
|
|
27
31
|
const opts = {};
|
|
28
32
|
for (let i = 0; i < argv.length; i++) {
|
|
29
33
|
const a = argv[i];
|
|
@@ -57,9 +61,16 @@ function main() {
|
|
|
57
61
|
if (o.classic) input.classicMode = true;
|
|
58
62
|
if (o.fill) input.fill = o.fill;
|
|
59
63
|
}
|
|
60
|
-
|
|
64
|
+
let outJson = generate(JSON.stringify(input));
|
|
65
|
+
let out = JSON.parse(outJson);
|
|
66
|
+
if (o.random) {
|
|
67
|
+
if (o.accents !== undefined && !['on', 'off'].includes(o.accents)) throw new Error('--accents must be on or off');
|
|
68
|
+
const accents = o.accents ? o.accents === 'on' : !input.classicMode;
|
|
69
|
+
const filled = fill(out, { lang: input.lang, accents, seed: input.seed });
|
|
70
|
+
out = { ...out, grid: filled.grid };
|
|
71
|
+
outJson = JSON.stringify(out);
|
|
72
|
+
}
|
|
61
73
|
if (o.json) return console.log(outJson);
|
|
62
|
-
const out = JSON.parse(outJson);
|
|
63
74
|
if (o.solution) {
|
|
64
75
|
const hidden = new Set(out.placements.flatMap((p) => Array.from({ length: p.length }, (_, i) => `${p.r + p.dr * i},${p.c + p.dc * i}`)));
|
|
65
76
|
return console.log(out.grid.map((row, r) => row.map((ch, c) => (hidden.has(`${r},${c}`) ? ch : '·')).join(' ')).join('\n'));
|