Skip to content

Commit 93988fb

Browse files
committed
wordsearch prototype
1 parent e5190b4 commit 93988fb

4 files changed

Lines changed: 38 additions & 9 deletions

File tree

experiments/wordsearch/src/fill/filler.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ export function* fillGridSteps(grid, model, config = {}) {
5151
rng = Math.random,
5252
lattice = 'square',
5353
includeBackwards = true,
54+
reverseModel = null,
5455
} = config;
5556
const alphabet = [...model.alphabet];
5657
let cell;
@@ -63,7 +64,11 @@ export function* fillGridSteps(grid, model, config = {}) {
6364
for (const d of dirs) {
6465
const ctx = readContext(grid, x, y, d, model.order, lattice);
6566
if (ctx) {
66-
const dist = model.predict(ctx);
67+
// Backward-oriented vectors are best predicted by a model trained on
68+
// the reversed stream; their context must be reversed to match.
69+
const useReverse = d.forward === false && reverseModel;
70+
const queryCtx = useReverse ? [...ctx].reverse().join('') : ctx;
71+
const dist = (useReverse ? reverseModel : model).predict(queryCtx);
6772
if (dist.size) {
6873
dists.push(dist);
6974
contexts.push({ dir: d.name, ctx });
@@ -95,6 +100,7 @@ export function fillGrid(grid, model, config = {}) {
95100
rng = Math.random,
96101
lattice = 'square',
97102
includeBackwards = true,
103+
reverseModel = null,
98104
} = config;
99105
const alphabet = [...model.alphabet];
100106

@@ -107,7 +113,10 @@ export function fillGrid(grid, model, config = {}) {
107113
for (const d of dirs) {
108114
const ctx = readContext(grid, x, y, d, model.order, lattice);
109115
if (ctx) {
110-
const dist = model.predict(ctx);
116+
// Use the reverse-trained model for backward-oriented vectors.
117+
const useReverse = d.forward === false && reverseModel;
118+
const queryCtx = useReverse ? [...ctx].reverse().join('') : ctx;
119+
const dist = (useReverse ? reverseModel : model).predict(queryCtx);
111120
if (dist.size) dists.push(dist);
112121
}
113122
}

experiments/wordsearch/src/generator.js

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,28 @@ export function generatePuzzle(opts) {
3030
lattice = 'square',
3131
includeBackwards = true,
3232
model: providedModel,
33+
reverseModel: providedReverseModel,
3334
} = opts;
3435

3536
const model = providedModel || new MarkovModel(order).train(referenceText, order);
37+
// Reverse model only matters when backward-oriented vectors participate.
38+
const reverseModel = includeBackwards
39+
? providedReverseModel || new MarkovModel(order).train(referenceText, order, { reverse: true })
40+
: null;
3641

3742
const grid = new Grid(width, height);
3843
const placement = placeWords(grid, words, rng, { lattice, includeBackwards });
39-
fillGrid(grid, model, { combiner, sampling, rng, lattice, includeBackwards });
44+
fillGrid(grid, model, {
45+
combiner,
46+
sampling,
47+
rng,
48+
lattice,
49+
includeBackwards,
50+
reverseModel,
51+
});
4052
grid.lattice = lattice;
4153

42-
return { grid, placement, model };
54+
return { grid, placement, model, reverseModel };
4355
}
4456
/**
4557
* Build the puzzle scaffold (grid + placed words + trained model) but
@@ -57,9 +69,13 @@ export function preparePuzzle(opts) {
5769
lattice = 'square',
5870
includeBackwards = true,
5971
model: providedModel,
72+
reverseModel: providedReverseModel,
6073
} = opts;
6174
const model = providedModel || new MarkovModel(order).train(referenceText, order);
75+
const reverseModel = includeBackwards
76+
? providedReverseModel || new MarkovModel(order).train(referenceText, order, { reverse: true })
77+
: null;
6278
const grid = new Grid(width, height);
6379
const placement = placeWords(grid, words, rng, { lattice, includeBackwards });
64-
return { grid, placement, model };
80+
return { grid, placement, model, reverseModel };
6581
}

experiments/wordsearch/src/markov/MarkovModel.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,14 @@ export class MarkovModel {
3232
* from 0 (unigram) up to `order`.
3333
* @param {string} text
3434
* @param {number} [order]
35+
* @param {object} [opts]
36+
* @param {boolean} [opts.reverse] train on the reversed character stream
3537
*/
36-
train(text, order = this.order) {
38+
train(text, order = this.order, opts = {}) {
39+
const { reverse = false } = opts;
3740
this.order = order;
38-
const clean = normaliseText(text);
41+
let clean = normaliseText(text);
42+
if (reverse) clean = [...clean].reverse().join('');
3943
for (const ch of clean) this.alphabet.add(ch);
4044

4145
for (let i = 0; i < clean.length; i++) {

experiments/wordsearch/src/ui/watchMode.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,10 @@ function doStep(root) {
5959
export function initWatch(root, cfg) {
6060
clearTimer();
6161
stepCount = 0;
62-
const { grid, model } = preparePuzzle(cfg);
62+
const { grid, model, reverseModel } = preparePuzzle(cfg);
6363
stepGrid = grid;
6464
stepLattice = cfg.lattice || 'square';
65-
stepGen = fillGridSteps(grid, model, cfg);
65+
stepGen = fillGridSteps(grid, model, { ...cfg, reverseModel });
6666
renderState(root, null);
6767
}
6868

0 commit comments

Comments
 (0)