lettras 0.0.0-stage → 0.2.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.
- package/LICENSE +25 -0
- package/README.md +57 -2
- package/bin/lettras.js +81 -0
- package/engine/LICENSE +19 -0
- package/engine/index.d.ts +1 -0
- package/engine/index.js +7 -0
- package/engine/lettras_engine.d.ts +93 -0
- package/engine/lettras_engine.js +321 -0
- package/package.json +49 -4
- package/src/index.d.ts +21 -0
- package/src/index.js +46 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Artificialss
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
|
6
|
+
software and associated documentation files (the "Software"), to deal in the Software
|
|
7
|
+
without restriction, including without limitation the rights to use, copy, modify, merge,
|
|
8
|
+
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
|
9
|
+
to whom the Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be included in all copies or
|
|
12
|
+
substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
EXCEPTION: This license does NOT cover the compiled Lettras engine in `npm/engine/`.
|
|
15
|
+
That directory is proprietary and is governed solely by `engine/LICENSE`.
|
|
16
|
+
|
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
18
|
+
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
|
19
|
+
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
|
20
|
+
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
21
|
+
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
22
|
+
DEALINGS IN THE SOFTWARE.
|
|
23
|
+
|
|
24
|
+
----------------------------------------------------------------------------------------
|
|
25
|
+
The compiled engine in `engine/` is NOT MIT. See `engine/LICENSE`.
|
package/README.md
CHANGED
|
@@ -1,3 +1,58 @@
|
|
|
1
|
-
#
|
|
1
|
+
# lettras
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Word-search generator for **Spanish, English, Portuguese, French, German and Italian**, with native accented letters
|
|
4
|
+
kept as one cell each. Runs locally (WebAssembly): no network, no API key. Library and CLI.
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
npm install lettras
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
```js
|
|
11
|
+
import { generate, render } from 'lettras';
|
|
12
|
+
|
|
13
|
+
const puzzle = generate({ words: ['gato', 'perro', 'piña'], rows: 9, cols: 12, position: 'mixed', seed: 8 });
|
|
14
|
+
console.log(render(puzzle));
|
|
15
|
+
puzzle.grid; // string[][], one letter per cell, '-' for empty cells
|
|
16
|
+
puzzle.placements; // where each word is hidden: start (r, c), step (dr, dc), length
|
|
17
|
+
puzzle.unplaced; // words that did not fit
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
```js
|
|
21
|
+
import { generate, fill, render } from 'lettras';
|
|
22
|
+
|
|
23
|
+
const puzzle = generate({ words: ['gato', 'perro', 'piña'], rows: 9, cols: 12, position: 'mixed', seed: 8 });
|
|
24
|
+
const done = fill(puzzle, { lang: 'es', accents: true }); // random letters in the empty cells
|
|
25
|
+
console.log(done.grid.map((row) => row.join(' ')).join('\n'));
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npx lettras --words gato,perro,piña --rows 9 --cols 12 --position mixed --random --accents on
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Options
|
|
33
|
+
|
|
34
|
+
| Option | Values |
|
|
35
|
+
| --- | --- |
|
|
36
|
+
| `words`, `rows`, `cols` | Word list and grid size (rectangular grids are fine). |
|
|
37
|
+
| `position` | `horizontal`, `vertical` or `mixed` (all 8 directions). |
|
|
38
|
+
| `difficulty` | 1–4, used when `position` is not set. |
|
|
39
|
+
| `clustering` | 0 words apart · 1 words crossing · default 0.5. |
|
|
40
|
+
| `seed` | Same input and seed give the same grid. |
|
|
41
|
+
| `lang` | `es` (default) `en` `pt` `fr` `de` `it`. |
|
|
42
|
+
| `classicMode` | Strip accents in the grid. |
|
|
43
|
+
| `fill` | Empty-cell character, default `-`. |
|
|
44
|
+
|
|
45
|
+
`generate` leaves empty cells as `-`. **`fill(puzzleOrGrid, { lang, accents, seed })`** completes them: letters follow the
|
|
46
|
+
language's letter frequency, `accents: false` limits them to A-Z, and without a `seed` every call is different. Passing the
|
|
47
|
+
puzzle (instead of a bare matrix) also protects its words from accidental extra copies. CLI: `--random` and `--accents on|off`.
|
|
48
|
+
|
|
49
|
+
CLI flags mirror these: `--words a,b,c --rows N --cols N --position P --difficulty N --clustering N --seed N --lang xx
|
|
50
|
+
--classic --fill C`, plus `--json`, `--solution` and `--stdin`.
|
|
51
|
+
|
|
52
|
+
`generate` throws on invalid input (for example zero rows). Words that cannot be placed are listed in `unplaced`;
|
|
53
|
+
words that are refused (spaces, digits, duplicates) are listed in `rejected` with a reason.
|
|
54
|
+
|
|
55
|
+
## License
|
|
56
|
+
|
|
57
|
+
Wrapper, CLI and types: MIT. The compiled engine in `engine/` is proprietary: use it unmodified through this package;
|
|
58
|
+
see `engine/LICENSE`. Source and issues: <https://github.com/Artificialss/lettras-sdk>.
|
package/bin/lettras.js
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
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 -] [--random] [--accents on|off]
|
|
4
|
+
// [--json] [--solution]
|
|
5
|
+
// or: echo '{"words":["sol"],"rows":6,"cols":6}' | lettras --stdin
|
|
6
|
+
import { readFileSync } from 'node:fs';
|
|
7
|
+
import { generate, renderPuzzle } from '../engine/index.js';
|
|
8
|
+
import { fill } from '../src/index.js';
|
|
9
|
+
|
|
10
|
+
const HELP = `lettras: word-search generator
|
|
11
|
+
|
|
12
|
+
lettras --words sol,luna,mar --rows 8 --cols 8 [options]
|
|
13
|
+
|
|
14
|
+
--words a,b,c word bank (comma separated)
|
|
15
|
+
--rows N --cols N grid size (rectangular allowed)
|
|
16
|
+
--position P horizontal | vertical | mixed (mixed = all 8 directions)
|
|
17
|
+
--difficulty 1-4 directions when --position is not set
|
|
18
|
+
--clustering 0-1 0 = words apart, 1 = words crossing (default 0.5)
|
|
19
|
+
--seed N same seed, same grid
|
|
20
|
+
--lang xx es en pt fr de it
|
|
21
|
+
--classic strip accents in the grid
|
|
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)
|
|
25
|
+
--json print the JSON result
|
|
26
|
+
--solution show only the hidden words
|
|
27
|
+
--stdin read the JSON input from stdin`;
|
|
28
|
+
|
|
29
|
+
function parse(argv) {
|
|
30
|
+
const flags = new Set(['classic', 'json', 'solution', 'stdin', 'help', 'random']);
|
|
31
|
+
const opts = {};
|
|
32
|
+
for (let i = 0; i < argv.length; i++) {
|
|
33
|
+
const a = argv[i];
|
|
34
|
+
if (!a.startsWith('--')) throw new Error(`unexpected argument: ${a}`);
|
|
35
|
+
const key = a.slice(2);
|
|
36
|
+
if (flags.has(key)) opts[key] = true;
|
|
37
|
+
else if (i + 1 < argv.length) opts[key] = argv[++i];
|
|
38
|
+
else throw new Error(`missing value for --${key}`);
|
|
39
|
+
}
|
|
40
|
+
return opts;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function main() {
|
|
44
|
+
const o = parse(process.argv.slice(2));
|
|
45
|
+
if (o.help) return console.log(HELP);
|
|
46
|
+
let input;
|
|
47
|
+
if (o.stdin) {
|
|
48
|
+
input = JSON.parse(readFileSync(0, 'utf8'));
|
|
49
|
+
} else {
|
|
50
|
+
if (!o.words || !o.rows) { console.log(HELP); process.exit(o.words || o.rows ? 2 : 0); }
|
|
51
|
+
input = {
|
|
52
|
+
words: o.words.split(',').map((w) => w.trim()).filter(Boolean),
|
|
53
|
+
rows: Number(o.rows),
|
|
54
|
+
cols: Number(o.cols ?? o.rows),
|
|
55
|
+
};
|
|
56
|
+
if (o.position) input.position = o.position;
|
|
57
|
+
if (o.difficulty) input.difficulty = Number(o.difficulty);
|
|
58
|
+
if (o.clustering) input.clustering = Number(o.clustering);
|
|
59
|
+
if (o.seed) input.seed = Number(o.seed);
|
|
60
|
+
if (o.lang) input.lang = o.lang;
|
|
61
|
+
if (o.classic) input.classicMode = true;
|
|
62
|
+
if (o.fill) input.fill = o.fill;
|
|
63
|
+
}
|
|
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
|
+
}
|
|
73
|
+
if (o.json) return console.log(outJson);
|
|
74
|
+
if (o.solution) {
|
|
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}`)));
|
|
76
|
+
return console.log(out.grid.map((row, r) => row.map((ch, c) => (hidden.has(`${r},${c}`) ? ch : '·')).join(' ')).join('\n'));
|
|
77
|
+
}
|
|
78
|
+
console.log(renderPuzzle(outJson));
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
try { main(); } catch (e) { console.error(`lettras: ${e.message ?? e}`); process.exit(1); }
|
package/engine/LICENSE
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Lettras compiled engine: proprietary license
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Artificialss. All rights reserved.
|
|
4
|
+
|
|
5
|
+
This directory contains the compiled Lettras word-search engine (WebAssembly and the
|
|
6
|
+
generated loader code). It is NOT covered by the MIT license that applies to the rest of
|
|
7
|
+
this repository.
|
|
8
|
+
|
|
9
|
+
You may use this engine, unmodified and only as distributed in the `lettras` npm package
|
|
10
|
+
or this repository, to generate puzzles in your own applications, including commercial
|
|
11
|
+
ones, free of charge.
|
|
12
|
+
|
|
13
|
+
You may not, without written permission from Artificialss:
|
|
14
|
+
- copy, extract or redistribute the engine separately from the `lettras` package;
|
|
15
|
+
- modify it, or create derivative works of it;
|
|
16
|
+
- decompile, disassemble or otherwise attempt to derive its source code or algorithm;
|
|
17
|
+
- use it to build a competing puzzle-generation service or library.
|
|
18
|
+
|
|
19
|
+
THE ENGINE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './lettras_engine.js';
|