From c334a9d7b770cee5165a26b3249f8e39aea78ab0 Mon Sep 17 00:00:00 2001 From: Ilia Denisov Date: Mon, 6 Jul 2026 01:35:11 +0200 Subject: [PATCH] feat(offline): port DAWG cursor + move generator to TS (parity-pinned) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit First engine-first step of PWA offline mode (Phase A): the client-side move generator — the "robot brain" a local vs_ai game will run on-device — with no runtime wiring yet (Phase B). - dawg.ts: add the step-by-step cursor (root/final/next/arcs), a faithful port of dafsa traverse.go over the reader's existing bitstream. - generate.ts: the Appel-Jacobson generator (leftPart/extendRight + cross-sets + counts-rack + board transpose + moveKey ranking), reusing the cursor and validate.ts evaluate/connected. A cross-set LetterSet is a Uint8Array, so the 33-letter Russian alphabet (index 32) is exact under JS bit ops. - validate.ts: export connected for the generator's connectivity filter. - backend/cmd/movegen: dev tool building small sample dictionaries and emitting golden move-generation fixtures from the real Go solver (EN + RU). - tests: dawg.cursor.test.ts (enumeration bijection vs indexOf) and generate.parity.test.ts (7/7 vs the Go solver: empty board, mid-game, blank, single-word rule, Russian index-32 cross-set). The committed EN sample also unblocks the existing skipped dawg.parity.test.ts once wired with DICT_* in CI. Pure additive library code; no runtime behavior change. --- backend/cmd/movegen/main.go | 295 + ui/src/lib/dict/dawg.cursor.test.ts | 68 + ui/src/lib/dict/dawg.ts | 79 + ui/src/lib/dict/generate.parity.test.ts | 99 + ui/src/lib/dict/generate.ts | 418 + ui/src/lib/dict/testdata/sample_en.dawg | Bin 0 -> 61 bytes ui/src/lib/dict/testdata/sample_en.gen.json | 9802 +++++++++++++++++ ui/src/lib/dict/testdata/sample_en.words.json | 122 + ui/src/lib/dict/testdata/sample_ru.dawg | Bin 0 -> 37 bytes ui/src/lib/dict/testdata/sample_ru.gen.json | 1271 +++ ui/src/lib/dict/testdata/sample_ru.words.json | 38 + ui/src/lib/dict/validate.ts | 5 +- 12 files changed, 12195 insertions(+), 2 deletions(-) create mode 100644 backend/cmd/movegen/main.go create mode 100644 ui/src/lib/dict/dawg.cursor.test.ts create mode 100644 ui/src/lib/dict/generate.parity.test.ts create mode 100644 ui/src/lib/dict/generate.ts create mode 100644 ui/src/lib/dict/testdata/sample_en.dawg create mode 100644 ui/src/lib/dict/testdata/sample_en.gen.json create mode 100644 ui/src/lib/dict/testdata/sample_en.words.json create mode 100644 ui/src/lib/dict/testdata/sample_ru.dawg create mode 100644 ui/src/lib/dict/testdata/sample_ru.gen.json create mode 100644 ui/src/lib/dict/testdata/sample_ru.words.json diff --git a/backend/cmd/movegen/main.go b/backend/cmd/movegen/main.go new file mode 100644 index 0000000..f7003cb --- /dev/null +++ b/backend/cmd/movegen/main.go @@ -0,0 +1,295 @@ +// Command movegen emits golden conformance fixtures for the client-side move +// generator port (ui/src/lib/dict). It is a dev tool, run by hand; its output is +// committed so the TypeScript parity tests run without a Go toolchain. +// +// For each small sample dictionary (English and Russian — the latter reaches +// alphabet index 32, exercising the 33-letter cross-set boundary) it writes: +// +// - sample_.dawg the serialized dictionary (the reader/cursor fixture) +// - sample_.words.json the stored words + their alphabet indexes +// - sample_.gen.json ranked move-generation results from the real solver, +// for a handful of positions, plus the ruleset the TS +// side rebuilds to score identically +// +// Positions are built with only the solver's public API: an empty board, and +// two-ply positions reached by applying the solver's own top move (so no internal +// encoding is needed). Regenerate with: +// +// go run ./backend/cmd/movegen -out ui/src/lib/dict/testdata +package main + +import ( + "encoding/json" + "flag" + "log" + "os" + "path/filepath" + + "gitea.iliadenisov.ru/developer/scrabble-solver/board" + "gitea.iliadenisov.ru/developer/scrabble-solver/rack" + "gitea.iliadenisov.ru/developer/scrabble-solver/rules" + "gitea.iliadenisov.ru/developer/scrabble-solver/scrabble" + dawg "github.com/iliadenisov/dafsa" +) + +// sampleWordsEN is the English sample dictionary, in strictly increasing +// alphabet-index order (the builder requires it). Shared prefixes (car/care/cars), +// shared suffixes (cats/dogs), internal-final nodes (do, an) and a one-letter word. +var sampleWordsEN = []string{ + "a", "an", "and", "ant", + "car", "care", "cared", "cares", "cars", "cat", "cats", + "do", "doe", "does", "dog", "dogs", "done", "dot", +} + +// sampleWordsRU is the Russian sample dictionary, in strictly increasing index +// order. It deliberately includes words starting with я (index 32) so the ported +// cross-set handles alphabet indexes past JS's 31-bit shift boundary. +var sampleWordsRU = []string{"ад", "ар", "оса", "я", "яд", "яр"} + +// sampleFixture is the JSON committed with the .dawg so the TypeScript cursor test +// knows the exact word set (as alphabet indexes) to expect from enumeration. +type sampleFixture struct { + Alphabet string `json:"alphabet"` + NumAdded int `json:"numAdded"` + Words []string `json:"words"` + Indexes [][]int `json:"indexes"` +} + +// genFixture is the move-generation golden set for one sample dictionary. +type genFixture struct { + Ruleset genRuleset `json:"ruleset"` + Cases []genCase `json:"cases"` +} + +// genRuleset is the scoring data the TS side rebuilds so evaluate() matches the Go +// solver: letter values, premium multipliers per square, the centre, rack size and bonus. +type genRuleset struct { + Size int `json:"size"` + Cols int `json:"cols"` + Center int `json:"center"` + RackSize int `json:"rackSize"` + Bingo int `json:"bingo"` + Values []int `json:"values"` + LetterMult [][]int `json:"letterMult"` + WordMult [][]int `json:"wordMult"` +} + +// genTile is one placed tile (a board tile or a move placement). +type genTile struct { + Row int `json:"row"` + Col int `json:"col"` + Letter int `json:"letter"` + Blank bool `json:"blank"` +} + +// genRack is a rack as a multiset of letter indexes plus a blank count. +type genRack struct { + Letters []int `json:"letters"` + Blanks int `json:"blanks"` +} + +// genMove is one ranked generated play: its orientation, placed tiles and total score. +type genMove struct { + Dir int `json:"dir"` + Tiles []genTile `json:"tiles"` + Score int `json:"score"` +} + +// genCase is one generation position: the tiles already on the board (empty when +// none), the rack, the mode/rule and the ranked moves the solver returns. +type genCase struct { + Name string `json:"name"` + Placed []genTile `json:"placed"` + Rack genRack `json:"rack"` + Mode int `json:"mode"` + IgnoreCrossWords bool `json:"ignoreCrossWords"` + Moves []genMove `json:"moves"` +} + +func main() { + out := flag.String("out", "ui/src/lib/dict/testdata", "output directory for fixtures") + flag.Parse() + + if err := os.MkdirAll(*out, 0o755); err != nil { + log.Fatalf("movegen: mkdir %s: %v", *out, err) + } + + buildSample(*out, "en", rules.English(), sampleWordsEN, []genCase{ + emptyCase("empty-cared", englishRack("caredts", 0), scrabble.Both, false), + emptyCase("empty-dogs", englishRack("dogsent", 0), scrabble.Both, false), + emptyCase("empty-blank", englishRack("caret", 1), scrabble.Both, false), + emptyCase("empty-single-word", englishRack("caredts", 0), scrabble.Both, true), + }) + + buildSample(*out, "ru", rules.RussianScrabble(), sampleWordsRU, []genCase{ + emptyCase("empty-yad", russianRack("ядрасо", 0), scrabble.Both, false), + }) +} + +// buildSample writes the dawg, the word fixture and the generation golden set for +// one sample dictionary. Two-ply cases are appended: the solver's own top move from +// the first non-empty result is applied, then generation runs again on the new rack. +func buildSample(out, tag string, rs *rules.Ruleset, words []string, cases []genCase) { + idx := rs.Alphabet + b := dawg.New(idx) + indexes := make([][]int, 0, len(words)) + for _, w := range words { + if err := b.Add(w); err != nil { + log.Fatalf("movegen[%s]: add %q: %v", tag, w, err) + } + enc, err := idx.Encode(w) + if err != nil { + log.Fatalf("movegen[%s]: encode %q: %v", tag, w, err) + } + ints := make([]int, len(enc)) + for i, x := range enc { + ints[i] = int(x) + } + indexes = append(indexes, ints) + } + finder := b.Finish() + + writeJSON(filepath.Join(out, "sample_"+tag+".words.json"), sampleFixture{ + Alphabet: tag, NumAdded: finder.NumAdded(), Words: words, Indexes: indexes, + }) + dawgPath := filepath.Join(out, "sample_"+tag+".dawg") + if _, err := finder.Save(dawgPath); err != nil { + log.Fatalf("movegen[%s]: save %s: %v", tag, dawgPath, err) + } + + s := scrabble.NewSolver(rs, finder) + for i := range cases { + runCase(s, rs, &cases[i], nil) + } + // A two-ply position from the first standard case that produced a move. + if two := twoPly(s, rs, cases); two != nil { + cases = append(cases, *two) + } + + writeJSON(filepath.Join(out, "sample_"+tag+".gen.json"), genFixture{ + Ruleset: rulesetOf(rs), Cases: cases, + }) + log.Printf("movegen[%s]: %d words, %d cases", tag, finder.NumAdded(), len(cases)) +} + +// runCase fills a case's Moves by generating on a board holding the given placed +// tiles (nil = empty board). +func runCase(s *scrabble.Solver, rs *rules.Ruleset, c *genCase, placed []genTile) { + bd := board.New(rs.Rows, rs.Cols) + for _, t := range placed { + bd.Set(t.Row, t.Col, cellByte(t.Letter, t.Blank)) + } + c.Placed = placed + rk := toRack(rs.Size(), c.Rack) + moves := s.GenerateMovesOpts(bd, rk, scrabble.Mode(c.Mode), scrabble.PlayOptions{IgnoreCrossWords: c.IgnoreCrossWords}) + c.Moves = movesOf(moves) +} + +// twoPly reaches a mid-game position by applying the top move of the first standard +// case that generated one, then generates again with a fresh rack of the same tiles. +func twoPly(s *scrabble.Solver, rs *rules.Ruleset, cases []genCase) *genCase { + for _, c := range cases { + if c.IgnoreCrossWords || len(c.Moves) == 0 { + continue + } + placed := c.Moves[0].Tiles + next := genCase{Name: "two-ply", Rack: c.Rack, Mode: int(scrabble.Both)} + runCase(s, rs, &next, placed) + return &next + } + return nil +} + +// cellByte encodes a board cell the way internal/encoding.Cell does (bits 0-5 hold +// letter+1, bit 7 marks a blank). Duplicated here because that package is internal +// to the solver module and cannot be imported. +func cellByte(letter int, blank bool) byte { + v := byte(letter+1) & 0x3f + if blank { + v |= 0x80 + } + return v +} + +func toRack(size int, r genRack) rack.Rack { + rk := rack.New(size) + for _, l := range r.Letters { + rk.Add(byte(l)) + } + for i := 0; i < r.Blanks; i++ { + rk.AddBlank() + } + return rk +} + +func rulesetOf(rs *rules.Ruleset) genRuleset { + lm := make([][]int, rs.Rows) + wm := make([][]int, rs.Rows) + for r := 0; r < rs.Rows; r++ { + lm[r] = make([]int, rs.Cols) + wm[r] = make([]int, rs.Cols) + for c := 0; c < rs.Cols; c++ { + p := rs.Premium(r, c) + lm[r][c] = p.LetterMult() + wm[r][c] = p.WordMult() + } + } + return genRuleset{ + Size: rs.Size(), Cols: rs.Cols, Center: rs.Center, RackSize: rs.RackSize, + Bingo: rs.Bingo, Values: rs.Values, LetterMult: lm, WordMult: wm, + } +} + +func movesOf(ms []scrabble.Move) []genMove { + out := make([]genMove, len(ms)) + for i, m := range ms { + out[i] = genMove{Dir: int(m.Dir), Tiles: tilesOf(m.Tiles), Score: m.Score} + } + return out +} + +func tilesOf(ps []scrabble.Placement) []genTile { + out := make([]genTile, len(ps)) + for i, p := range ps { + out[i] = genTile{Row: p.Row, Col: p.Col, Letter: int(p.Letter), Blank: p.Blank} + } + return out +} + +// emptyCase builds an empty-board case (Moves filled later by runCase). +func emptyCase(name string, r genRack, mode scrabble.Mode, ignoreCross bool) genCase { + return genCase{Name: name, Rack: r, Mode: int(mode), IgnoreCrossWords: ignoreCross} +} + +// englishRack builds a rack from lowercase a-z letters (index = letter-'a'). +func englishRack(letters string, blanks int) genRack { + idx := make([]int, 0, len(letters)) + for _, ch := range letters { + idx = append(idx, int(ch-'a')) + } + return genRack{Letters: idx, Blanks: blanks} +} + +// russianRack builds a rack from the Russian sample letters used above. +func russianRack(letters string, blanks int) genRack { + m := map[rune]int{'а': 0, 'д': 4, 'о': 15, 'р': 17, 'с': 18, 'я': 32} + idx := make([]int, 0, len([]rune(letters))) + for _, ch := range letters { + i, ok := m[ch] + if !ok { + log.Fatalf("movegen: russianRack: no index for %q", string(ch)) + } + idx = append(idx, i) + } + return genRack{Letters: idx, Blanks: blanks} +} + +func writeJSON(path string, v any) { + data, err := json.MarshalIndent(v, "", " ") + if err != nil { + log.Fatalf("movegen: marshal %s: %v", path, err) + } + if err := os.WriteFile(path, append(data, '\n'), 0o644); err != nil { + log.Fatalf("movegen: write %s: %v", path, err) + } +} diff --git a/ui/src/lib/dict/dawg.cursor.test.ts b/ui/src/lib/dict/dawg.cursor.test.ts new file mode 100644 index 0000000..6f77b5e --- /dev/null +++ b/ui/src/lib/dict/dawg.cursor.test.ts @@ -0,0 +1,68 @@ +import { describe, it, expect } from 'vitest'; +import { readFileSync } from 'node:fs'; +import { Dawg } from './dawg'; + +// The step-by-step DAWG cursor (root/final/next/arcs) is the primitive the move +// generator walks. These fast unit tests pin it against a small committed sample +// dictionary (backend/cmd/movegen); the full parity vs the Go solver lands with +// the generator's conformance fixtures. +const bytes = new Uint8Array(readFileSync(new URL('./testdata/sample_en.dawg', import.meta.url))); +const fixture = JSON.parse( + readFileSync(new URL('./testdata/sample_en.words.json', import.meta.url), 'utf8'), +) as { numAdded: number; words: string[]; indexes: number[][] }; + +const key = (w: number[]): string => w.join(','); + +// enumerateWords walks the whole automaton depth-first, collecting the index path +// at every accepting node — i.e. every stored word. +function enumerateWords(d: Dawg): number[][] { + const out: number[][] = []; + const path: number[] = []; + const visit = (node: number): void => { + d.arcs(node, (label, dest, final) => { + path.push(label); + if (final) out.push(path.slice()); + visit(dest); + path.pop(); + return true; + }); + }; + if (d.final(d.root())) out.push([]); + visit(d.root()); + return out; +} + +describe('dawg cursor', () => { + it('parses the sample fixture', () => { + const d = new Dawg(bytes); + expect(d.numAdded).toBe(fixture.numAdded); + }); + + it('root is not an accepting state (the sample has no empty word)', () => { + const d = new Dawg(bytes); + expect(d.final(d.root())).toBe(false); + }); + + it('enumerates exactly the stored words', () => { + const d = new Dawg(bytes); + const got = enumerateWords(d).map(key).sort(); + const want = fixture.indexes.map(key).sort(); + expect(got).toEqual(want); + }); + + it('next walks a stored word to an accepting node and rejects a non-edge', () => { + const d = new Dawg(bytes); + let node = d.root(); + for (const ch of [2, 0, 17, 4, 3]) { + // "cared" + node = d.next(node, ch); + expect(node).toBeGreaterThanOrEqual(0); + } + expect(d.final(node)).toBe(true); + // "care" (index [2,0,17,4]) is an internal accepting node on the way to "cared". + const care = [2, 0, 17, 4].reduce((n, ch) => d.next(n, ch), d.root()); + expect(d.final(care)).toBe(true); + // No stored word starts with 'z' (index 25). + expect(d.next(d.root(), 25)).toBe(-1); + }); +}); diff --git a/ui/src/lib/dict/dawg.ts b/ui/src/lib/dict/dawg.ts index 0953c5f..24a6b0f 100644 --- a/ui/src/lib/dict/dawg.ts +++ b/ui/src/lib/dict/dawg.ts @@ -95,6 +95,85 @@ export class Dawg { return this.indexOf(word) >= 0; } + // --- Step-by-step traversal (the move generator's primitive) --------------- + // + // A `Node` is a bit offset into the graph; 0 denotes the root (which resolves + // to firstNodeOffset). These mirror dafsa's traverse.go Cursor (Root/Final/ + // Next/Arcs) over the same bitstream this reader already decodes, so the ported + // generator can drive the automaton one transition at a time. Single-threaded + // JS shares this reader's position across calls; every method re-seeks to its + // node on entry, and arcs brackets the callback with a save/restore, so nested + // use during a walk is safe. Mirrors dafsa (*Cursor). + + /** root returns the start state of the automaton. */ + root(): number { + return 0; + } + + /** final reports whether node is an accepting state (a stored word ends there). */ + final(node: number): boolean { + if (this.numEdges <= 0) { + return this.hasEmptyWord && node === 0; + } + this.p = node === 0 ? this.firstNodeOffset : node; + return this.readBits(1) === 1; + } + + /** + * next follows the edge labelled ch (an alphabet index) from node, returning the + * destination node, or -1 when no such edge exists. + */ + next(node: number, ch: number): number { + return this.getEdge(node, ch) ? this.eNode : -1; + } + + /** + * arcs calls fn for each out-edge of node in ascending label order, passing the + * edge's label, its destination node and whether that destination is accepting. + * It stops early if fn returns false. Mirrors dafsa (*Cursor).Arcs. + */ + arcs(node: number, fn: (label: number, dest: number, final: boolean) => boolean): void { + if (this.numEdges <= 0) { + return; + } + this.p = node === 0 ? this.firstNodeOffset : node; + this.readBits(1); // node final flag — not needed here + const fallthrough = this.readBits(1); + + if (fallthrough === 1) { + const label = this.readBits(this.cbits); + // The reader now sits at the destination node, whose first bit is its final flag. + const dest = this.p; + const final = this.readBits(1) === 1; + fn(label, dest, final); + return; + } + + const nskiplen = bitsLen(this.wbits); + let nskip = 0; + let numEdges = 1; + if (this.readBits(1) !== 1) { + // not a single edge + numEdges = this.readUnsigned(); + nskip = this.readBits(nskiplen); + } + + for (let i = 0; i < numEdges; i++) { + const label = this.readBits(this.cbits); + if (i > 0) { + this.readBits(nskip); // per-edge skip count, unused for traversal + } + const dest = this.readBits(this.abits); + const resume = this.p; + this.p = dest; + const final = this.readBits(1) === 1; + if (!fn(label, dest, final)) { + return; + } + this.p = resume; + } + } + // getEdge resolves the outgoing edge for ch from the node at the given bit // offset. On success it fills eNode/eCount/eFinal and returns true. Mirrors // dafsa (*dawg).getEdge. diff --git a/ui/src/lib/dict/generate.parity.test.ts b/ui/src/lib/dict/generate.parity.test.ts new file mode 100644 index 0000000..2112db0 --- /dev/null +++ b/ui/src/lib/dict/generate.parity.test.ts @@ -0,0 +1,99 @@ +import { describe, it, expect } from 'vitest'; +import { readFileSync } from 'node:fs'; +import { Dawg } from './dawg'; +import { generateMoves, GenRack, type GenBoard, type Mode } from './generate'; +import type { Ruleset } from './validate'; + +// Conformance gate for the ported move generator: for each committed position it must +// return exactly the ranked play list the real Go solver returns (backend/cmd/movegen). +// The Russian sample reaches alphabet index 32, exercising the 33-letter cross-set. + +interface Tile { + row: number; + col: number; + letter: number; + blank: boolean; +} +interface GenMove { + dir: number; + tiles: Tile[]; + score: number; +} +interface Fixture { + ruleset: { + size: number; + cols: number; + center: number; + rackSize: number; + bingo: number; + values: number[]; + letterMult: number[][]; + wordMult: number[][]; + }; + cases: { + name: string; + placed: Tile[] | null; + rack: { letters: number[]; blanks: number }; + mode: number; + ignoreCrossWords: boolean; + moves: GenMove[]; + }[]; +} + +function load(tag: string): { dawg: Dawg; fx: Fixture } { + const bytes = new Uint8Array(readFileSync(new URL(`./testdata/sample_${tag}.dawg`, import.meta.url))); + const fx = JSON.parse( + readFileSync(new URL(`./testdata/sample_${tag}.gen.json`, import.meta.url), 'utf8'), + ) as Fixture; + return { dawg: new Dawg(bytes), fx }; +} + +function buildBoard(placed: Tile[], cols: number): GenBoard { + const grid: ({ letter: number; blank: boolean } | null)[] = new Array(cols * cols).fill(null); + for (const t of placed) grid[t.row * cols + t.col] = { letter: t.letter, blank: t.blank }; + const inBounds = (r: number, c: number): boolean => r >= 0 && r < cols && c >= 0 && c < cols; + return { + rows: cols, + cols, + inBounds, + filled: (r, c) => inBounds(r, c) && grid[r * cols + c] !== null, + cellAt: (r, c) => grid[r * cols + c]!, + isEmpty: () => placed.length === 0, + }; +} + +function rulesetFor(fx: Fixture, ignoreCrossWords: boolean): Ruleset { + const r = fx.ruleset; + return { + cols: r.cols, + center: r.center, + rackSize: r.rackSize, + bingo: r.bingo, + values: r.values, + letterMult: (row, col) => r.letterMult[row][col], + wordMult: (row, col) => r.wordMult[row][col], + ignoreCrossWords, + }; +} + +// sig is an order-stable signature of a move: orientation, score and its placed tiles +// sorted by square — so two lists compare equal iff they rank the same plays the same way. +function sig(m: GenMove): string { + const ts = m.tiles.slice().sort((a, b) => (a.row !== b.row ? a.row - b.row : a.col - b.col)); + return `${m.dir}#${m.score}#` + ts.map((t) => `${t.row},${t.col},${t.letter}${t.blank ? '*' : ''}`).join(';'); +} + +for (const tag of ['en', 'ru']) { + describe(`move generator parity vs Go solver (${tag})`, () => { + const { dawg, fx } = load(tag); + for (const c of fx.cases) { + it(c.name, () => { + const board = buildBoard(c.placed ?? [], fx.ruleset.cols); + const rack = GenRack.from(fx.ruleset.size, c.rack.letters, c.rack.blanks); + const rs = rulesetFor(fx, c.ignoreCrossWords); + const got = generateMoves(dawg, board, rack, rs, c.mode as Mode); + expect(got.map(sig)).toEqual(c.moves.map(sig)); + }); + } + }); +} diff --git a/ui/src/lib/dict/generate.ts b/ui/src/lib/dict/generate.ts new file mode 100644 index 0000000..d7f90bd --- /dev/null +++ b/ui/src/lib/dict/generate.ts @@ -0,0 +1,418 @@ +// Local move generator: every legal play for a rack on a board, ranked by +// descending score. Ported from the scrabble-solver engine — the Appel-Jacobson +// two-phase algorithm (LeftPart then ExtendRight) over a plain left-to-right DAWG +// (scrabble/gen_dawg.go, gen.go, crossset.go, solver.go, key.go). It walks the DAWG +// with the cursor from dawg.ts and scores each play with evaluate() from validate.ts, +// so the whole robot brain runs on-device. Faithfulness to the Go solver is pinned by +// generate.parity.test.ts against golden fixtures (backend/cmd/movegen). +// +// Everything works in alphabet-index space, mirroring the Go engine. A letterSet is +// a per-square cross-set (the letters that form a legal perpendicular word there); +// it is a boolean membership array rather than a uint64, so alphabet indexes past +// JS's 31-bit shift boundary (Russian has 33 letters) are handled exactly. + +import { Dawg } from './dawg'; +import { + evaluate, + connected, + Horizontal, + Vertical, + type Board, + type Ruleset, + type Move, + type Placement, + type Direction, +} from './validate'; + +/** Both generates across plays (on the board) and down plays (on its transpose). */ +export const Both = 0; +/** OnlyHorizontal generates across plays only. */ +export const OnlyHorizontal = 1; +/** OnlyVertical generates down plays only (Эрудит plays a single orientation per turn). */ +export const OnlyVertical = 2; +export type Mode = typeof Both | typeof OnlyHorizontal | typeof OnlyVertical; + +function modeIncludes(mode: Mode, dir: Direction): boolean { + if (mode === Both) return true; + if (mode === OnlyHorizontal) return dir === Horizontal; + return dir === Vertical; +} + +/** + * GenBoard is the board view the generator needs: the validator's read view plus the + * dimensions it iterates over. The whole board is square, so a transposed view (below) + * satisfies the same shape. + */ +export interface GenBoard extends Board { + rows: number; + cols: number; +} + +/** + * GenRack is a rack as per-letter tile counts plus a blank slot, mirroring + * scrabble-solver/rack. The generator mutates a single rack in place — removing a + * tile, recursing, putting it back — so the operations are O(1) and allocation-free. + */ +export class GenRack { + private readonly counts: Int32Array; + + /** Construct an empty rack for an alphabet of the given size (a trailing blank slot). */ + constructor(size: number) { + this.counts = new Int32Array(size + 1); + } + + /** from builds a rack from a multiset of letter indexes plus a blank count. */ + static from(size: number, letters: readonly number[], blanks: number): GenRack { + const r = new GenRack(size); + for (const l of letters) r.counts[l]++; + r.counts[size] += blanks; + return r; + } + + /** has reports whether at least one tile of the letter index is on the rack. */ + has(letter: number): boolean { + return this.counts[letter] > 0; + } + /** blanks returns how many blank tiles are on the rack. */ + blanks(): number { + return this.counts[this.counts.length - 1]; + } + remove(letter: number): void { + this.counts[letter]--; + } + add(letter: number): void { + this.counts[letter]++; + } + removeBlank(): void { + this.counts[this.counts.length - 1]--; + } + addBlank(): void { + this.counts[this.counts.length - 1]++; + } + /** clone returns an independent copy. */ + clone(): GenRack { + const c = new GenRack(this.counts.length - 1); + c.counts.set(this.counts); + return c; + } +} + +// --- cross-sets ------------------------------------------------------------------ +// +// A LetterSet is membership over alphabet letter indexes. Mirrors scrabble.letterSet +// (a uint64) but as a Uint8Array so index 32 (Russian) is exact under JS bit ops. +type LetterSet = Uint8Array; + +function fullSet(size: number): LetterSet { + return new Uint8Array(size).fill(1); +} + +// walk follows word (alphabet indexes) left to right from the root; -1 if it derails. +function walk(dawg: Dawg, word: readonly number[]): number { + let n = dawg.root(); + for (const l of word) { + n = dawg.next(n, l); + if (n < 0) return -1; + } + return n; +} + +// completers returns the letters X (< size) whose arc from state leads directly to an +// accepting node — the deterministic cross-set primitive. Mirrors scrabble.completers. +function completers(dawg: Dawg, state: number, size: number): LetterSet { + const set = new Uint8Array(size); + dawg.arcs(state, (label, _dest, final) => { + if (final && label < size) set[label] = 1; + return true; + }); + return set; +} + +// dawgCrossSet returns the letters X for which above·X·below is a stored word. Mirrors +// scrabble.dawgCrossSet: a right extension (no tiles below) just completes the prefix +// above; a left extension (tiles below) probes each X. above/below are letter indexes. +function dawgCrossSet(dawg: Dawg, above: number[], below: number[], size: number): LetterSet { + if (above.length === 0 && below.length === 0) return fullSet(size); + if (below.length === 0) { + const node = walk(dawg, above); + if (node < 0) return new Uint8Array(size); + return completers(dawg, node, size); + } + let node = dawg.root(); + if (above.length > 0) { + node = walk(dawg, above); + if (node < 0) return new Uint8Array(size); + } + const set = new Uint8Array(size); + for (let x = 0; x < size; x++) { + let m = dawg.next(node, x); + if (m < 0) continue; + let ok = true; + for (const l of below) { + m = dawg.next(m, l); + if (m < 0) { + ok = false; + break; + } + } + if (ok && dawg.final(m)) set[x] = 1; + } + return set; +} + +// columnContext returns the contiguous run of filled cells immediately above and below +// the empty square (r, c), each top to bottom, as letter indexes — the tiles a +// perpendicular word through (r, c) would include. Mirrors scrabble.columnContext. +function columnContext(b: GenBoard, r: number, c: number): { above: number[]; below: number[] } { + const above: number[] = []; + let start = r; + while (start - 1 >= 0 && b.filled(start - 1, c)) start--; + for (let rr = start; rr < r; rr++) above.push(b.cellAt(rr, c).letter); + + const below: number[] = []; + let end = r; + while (end + 1 < b.rows && b.filled(end + 1, c)) end++; + for (let rr = r + 1; rr <= end; rr++) below.push(b.cellAt(rr, c).letter); + return { above, below }; +} + +// transpose returns a view of b with rows and columns swapped, so down-play generation +// runs as across generation. Mirrors board.Transpose (as a lazy view). +function transpose(b: GenBoard): GenBoard { + return { + rows: b.cols, + cols: b.rows, + inBounds: (r, c) => b.inBounds(c, r), + filled: (r, c) => b.filled(c, r), + cellAt: (r, c) => b.cellAt(c, r), + isEmpty: () => b.isEmpty(), + }; +} + +// A tentatively placed left-part tile; its column is fixed only at record time. +interface TileInfo { + letter: number; + blank: boolean; +} + +// AcrossGen carries one across-generation pass over a board. Mirrors scrabble.acrossGen. +class AcrossGen { + private row = 0; + private readonly left: TileInfo[] = []; + private readonly right: Placement[] = []; + + constructor( + private readonly dawg: Dawg, + private readonly bd: GenBoard, + private readonly rk: GenRack, + private readonly cross: (r: number, c: number) => LetterSet, + private readonly emit: (placements: Placement[]) => void, + ) {} + + generateRow(row: number, firstMove: boolean, centerRow: number, centerCol: number): void { + this.row = row; + let limit = 0; + for (let col = 0; col < this.bd.cols; col++) { + if (this.bd.filled(row, col)) { + limit = 0; + continue; + } + const anchor = firstMove ? row === centerRow && col === centerCol : this.hasFilledNeighbor(row, col); + if (!anchor) { + limit++; + continue; + } + this.left.length = 0; + this.right.length = 0; + if (col > 0 && this.bd.filled(row, col - 1)) { + const pre = this.walkPrefix(row, col); + if (pre.ok) this.extendRight(pre.node, col, col); + } else { + this.leftPart(this.dawg.root(), col, limit); + } + limit = 0; + } + } + + private hasFilledNeighbor(r: number, c: number): boolean { + return this.bd.filled(r - 1, c) || this.bd.filled(r + 1, c) || this.bd.filled(r, c - 1) || this.bd.filled(r, c + 1); + } + + // walkPrefix walks the DAWG through the filled run ending at col-1, returning the + // node reached and whether that prefix exists. Mirrors scrabble.acrossGen.walkPrefix. + private walkPrefix(row: number, col: number): { node: number; ok: boolean } { + let start = col - 1; + while (start - 1 >= 0 && this.bd.filled(row, start - 1)) start--; + let node = this.dawg.root(); + for (let c = start; c < col; c++) { + node = this.dawg.next(node, this.bd.cellAt(row, c).letter); + if (node < 0) return { node, ok: false }; + } + return { node, ok: true }; + } + + // leftPart places left-part tiles from the rack (up to limit), calling extendRight + // after each prefix. Mirrors scrabble.acrossGen.leftPart. + private leftPart(node: number, anchorCol: number, limit: number): void { + this.extendRight(node, anchorCol, anchorCol); + if (limit === 0) return; + this.dawg.arcs(node, (label, dest) => { + if (this.rk.has(label)) { + this.rk.remove(label); + this.left.push({ letter: label, blank: false }); + this.leftPart(dest, anchorCol, limit - 1); + this.left.pop(); + this.rk.add(label); + } + if (this.rk.blanks() > 0) { + this.rk.removeBlank(); + this.left.push({ letter: label, blank: true }); + this.leftPart(dest, anchorCol, limit - 1); + this.left.pop(); + this.rk.addBlank(); + } + return true; + }); + } + + // extendRight extends the word rightward from col, placing rack tiles on empty + // squares (constrained by cross-sets) and following board tiles. A word is recorded + // only past the anchor. Mirrors scrabble.acrossGen.extendRight. + private extendRight(node: number, col: number, anchorCol: number): void { + if (col >= this.bd.cols) { + if (col > anchorCol && this.dawg.final(node)) this.record(anchorCol); + return; + } + if (this.bd.filled(this.row, col)) { + const dest = this.dawg.next(node, this.bd.cellAt(this.row, col).letter); + if (dest >= 0) this.extendRight(dest, col + 1, anchorCol); + return; + } + + if (col > anchorCol && this.dawg.final(node)) this.record(anchorCol); + const cross = this.cross(this.row, col); + this.dawg.arcs(node, (label, dest) => { + if (cross[label] !== 1) return true; + if (this.rk.has(label)) { + this.rk.remove(label); + this.right.push({ row: this.row, col, letter: label, blank: false }); + this.extendRight(dest, col + 1, anchorCol); + this.right.pop(); + this.rk.add(label); + } + if (this.rk.blanks() > 0) { + this.rk.removeBlank(); + this.right.push({ row: this.row, col, letter: label, blank: true }); + this.extendRight(dest, col + 1, anchorCol); + this.right.pop(); + this.rk.addBlank(); + } + return true; + }); + } + + // record assembles the play (left part at fixed columns, then the right part) and + // reports it, skipping plays that lay no new tile. Mirrors scrabble.acrossGen.record. + private record(anchorCol: number): void { + if (this.left.length + this.right.length === 0) return; + const placements: Placement[] = []; + const leftStart = anchorCol - this.left.length; + for (let i = 0; i < this.left.length; i++) { + placements.push({ row: this.row, col: leftStart + i, letter: this.left[i].letter, blank: this.left[i].blank }); + } + for (const p of this.right) placements.push(p); + this.emit(placements); + } +} + +// runAcross generates all across plays on bd and reports each via emit in bd's +// coordinates. Cross-sets are computed lazily (vertical words on bd) and cached. +// Mirrors DAWGGenerator.runAcross. +function runAcross( + dawg: Dawg, + bd: GenBoard, + rk: GenRack, + size: number, + rs: Ruleset, + centerRow: number, + centerCol: number, + emit: (placements: Placement[]) => void, +): void { + let crossFn: (r: number, c: number) => LetterSet; + if (rs.ignoreCrossWords) { + const full = fullSet(size); + crossFn = () => full; + } else { + const cache = new Array(bd.rows * bd.cols); + crossFn = (r, c) => { + const i = r * bd.cols + c; + let s = cache[i]; + if (!s) { + const { above, below } = columnContext(bd, r, c); + s = dawgCrossSet(dawg, above, below, size); + cache[i] = s; + } + return s; + }; + } + + const ag = new AcrossGen(dawg, bd, rk, crossFn, emit); + const firstMove = bd.isEmpty(); + for (let row = 0; row < bd.rows; row++) { + ag.generateRow(row, firstMove, centerRow, centerCol); + } +} + +// moveKey is a canonical string identifying a play (direction plus its placed tiles), +// used to de-duplicate and rank generated moves. Mirrors scrabble.moveKey. +export function moveKey(dir: Direction, placements: readonly Placement[]): string { + const ps = placements.slice().sort((a, b) => (a.row !== b.row ? a.row - b.row : a.col - b.col)); + let s = String(dir); + for (const p of ps) s += `;${p.row},${p.col},${p.letter}${p.blank ? '*' : ''}`; + return s; +} + +/** + * generateMoves returns every legal play for rack on board in the mode's orientations, + * ranked by descending score (ties broken by the canonical move key). It walks the DAWG + * with the cursor and scores each play with evaluate(); the alphabet size is taken from + * the ruleset's value table. Mirrors (*Solver).GenerateMovesOpts (the ruleset carries + * ignoreCrossWords for the single-word rule). + */ +export function generateMoves(dawg: Dawg, board: GenBoard, rack: GenRack, rs: Ruleset, mode: Mode = Both): Move[] { + const size = rs.values.length; + const rk = rack.clone(); // generation mutates the rack in place and restores it + const centerRow = Math.floor(rs.center / rs.cols); + const centerCol = rs.center % rs.cols; + + const moves: Move[] = []; + const seen = new Set(); + const emit = (dir: Direction, placements: Placement[]): void => { + const key = moveKey(dir, placements); + if (seen.has(key)) return; + const res = evaluate(board, rs, dir, placements); + if (res.err || !res.move) return; + seen.add(key); + moves.push(res.move); + }; + + if (modeIncludes(mode, Horizontal)) { + runAcross(dawg, board, rk, size, rs, centerRow, centerCol, (p) => emit(Horizontal, p)); + } + if (modeIncludes(mode, Vertical)) { + const tb = transpose(board); + runAcross(dawg, tb, rk, size, rs, centerCol, centerRow, (p) => { + const rp = p.map((pl) => ({ row: pl.col, col: pl.row, letter: pl.letter, blank: pl.blank })); + emit(Vertical, rp); + }); + } + + const kept = moves.filter((m) => connected(board, rs, m)); + kept.sort((a, b) => { + if (a.score !== b.score) return b.score - a.score; + const ka = moveKey(a.dir, a.tiles); + const kb = moveKey(b.dir, b.tiles); + return ka < kb ? -1 : ka > kb ? 1 : 0; + }); + return kept; +} diff --git a/ui/src/lib/dict/testdata/sample_en.dawg b/ui/src/lib/dict/testdata/sample_en.dawg new file mode 100644 index 0000000000000000000000000000000000000000..2dc5d6ed4f200af33826752c0e187c239673444e GIT binary patch literal 61 zcmV-D0K)$O002D&2?Awq5)2jqbP6F6#x>w}z$7-T=BxlH027Q}cHsb-D3Xm>1cud= T)v{`?fQ**|JA-dtd8$a&EKU|> literal 0 HcmV?d00001 diff --git a/ui/src/lib/dict/testdata/sample_en.gen.json b/ui/src/lib/dict/testdata/sample_en.gen.json new file mode 100644 index 0000000..30199cb --- /dev/null +++ b/ui/src/lib/dict/testdata/sample_en.gen.json @@ -0,0 +1,9802 @@ +{ + "ruleset": { + "size": 26, + "cols": 15, + "center": 112, + "rackSize": 7, + "bingo": 50, + "values": [ + 1, + 3, + 3, + 2, + 1, + 4, + 2, + 4, + 1, + 8, + 5, + 1, + 3, + 1, + 1, + 3, + 10, + 1, + 1, + 1, + 1, + 4, + 4, + 8, + 4, + 10 + ], + "letterMult": [ + [ + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 3, + 1, + 1, + 1, + 3, + 1, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 1 + ], + [ + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 2 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ], + [ + 1, + 3, + 1, + 1, + 1, + 3, + 1, + 1, + 1, + 3, + 1, + 1, + 1, + 3, + 1 + ], + [ + 1, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 1 + ], + [ + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1 + ], + [ + 1, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 1 + ], + [ + 1, + 3, + 1, + 1, + 1, + 3, + 1, + 1, + 1, + 3, + 1, + 1, + 1, + 3, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ], + [ + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 2 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 3, + 1, + 1, + 1, + 3, + 1, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1 + ] + ], + "wordMult": [ + [ + 3, + 1, + 1, + 1, + 1, + 1, + 1, + 3, + 1, + 1, + 1, + 1, + 1, + 1, + 3 + ], + [ + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 1 + ], + [ + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 1 + ], + [ + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ], + [ + 3, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 3 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1 + ], + [ + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1 + ], + [ + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 1 + ], + [ + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 1 + ], + [ + 3, + 1, + 1, + 1, + 1, + 1, + 1, + 3, + 1, + 1, + 1, + 1, + 1, + 1, + 3 + ] + ] + }, + "cases": [ + { + "name": "empty-cared", + "placed": null, + "rack": { + "letters": [ + 2, + 0, + 17, + 4, + 3, + 19, + 18 + ], + "blanks": 0 + }, + "mode": 0, + "ignoreCrossWords": false, + "moves": [ + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 3, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 4, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 5, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 4, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 3, + "blank": false + } + ], + "score": 22 + }, + { + "dir": 1, + "tiles": [ + { + "row": 3, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 4, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 5, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 4, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 3, + "blank": false + } + ], + "score": 22 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 3, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 4, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 5, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 4, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 18, + "blank": false + } + ], + "score": 20 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 10, + "letter": 4, + "blank": false + }, + { + "row": 7, + "col": 11, + "letter": 3, + "blank": false + } + ], + "score": 20 + }, + { + "dir": 1, + "tiles": [ + { + "row": 3, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 4, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 5, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 4, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 18, + "blank": false + } + ], + "score": 20 + }, + { + "dir": 1, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 10, + "col": 7, + "letter": 4, + "blank": false + }, + { + "row": 11, + "col": 7, + "letter": 3, + "blank": false + } + ], + "score": 20 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 4, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 5, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 4, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 3, + "blank": false + } + ], + "score": 16 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 5, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 4, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 3, + "blank": false + } + ], + "score": 16 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 6, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 4, + "blank": false + }, + { + "row": 7, + "col": 10, + "letter": 3, + "blank": false + } + ], + "score": 16 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 10, + "letter": 4, + "blank": false + }, + { + "row": 7, + "col": 11, + "letter": 18, + "blank": false + } + ], + "score": 16 + }, + { + "dir": 1, + "tiles": [ + { + "row": 4, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 5, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 4, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 3, + "blank": false + } + ], + "score": 16 + }, + { + "dir": 1, + "tiles": [ + { + "row": 5, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 4, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 3, + "blank": false + } + ], + "score": 16 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 4, + "blank": false + }, + { + "row": 10, + "col": 7, + "letter": 3, + "blank": false + } + ], + "score": 16 + }, + { + "dir": 1, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 10, + "col": 7, + "letter": 4, + "blank": false + }, + { + "row": 11, + "col": 7, + "letter": 18, + "blank": false + } + ], + "score": 16 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 4, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 5, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 4, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 18, + "blank": false + } + ], + "score": 14 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 5, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 4, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 18, + "blank": false + } + ], + "score": 14 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 6, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 4, + "blank": false + }, + { + "row": 7, + "col": 10, + "letter": 18, + "blank": false + } + ], + "score": 14 + }, + { + "dir": 1, + "tiles": [ + { + "row": 4, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 5, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 4, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 18, + "blank": false + } + ], + "score": 14 + }, + { + "dir": 1, + "tiles": [ + { + "row": 5, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 4, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 18, + "blank": false + } + ], + "score": 14 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 4, + "blank": false + }, + { + "row": 10, + "col": 7, + "letter": 18, + "blank": false + } + ], + "score": 14 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 4, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 5, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 18, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 4, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 5, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 4, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 4, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 5, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 19, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 18, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 5, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 18, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 5, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 4, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 5, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 19, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 18, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 6, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 18, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 6, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 4, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 6, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 19, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 18, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 10, + "letter": 18, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 10, + "letter": 4, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 19, + "blank": false + }, + { + "row": 7, + "col": 10, + "letter": 18, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 1, + "tiles": [ + { + "row": 4, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 5, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 18, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 1, + "tiles": [ + { + "row": 4, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 5, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 4, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 1, + "tiles": [ + { + "row": 4, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 5, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 19, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 18, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 1, + "tiles": [ + { + "row": 5, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 18, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 1, + "tiles": [ + { + "row": 5, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 4, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 1, + "tiles": [ + { + "row": 5, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 19, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 18, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 18, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 4, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 19, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 18, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 1, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 10, + "col": 7, + "letter": 18, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 1, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 10, + "col": 7, + "letter": 4, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 1, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 19, + "blank": false + }, + { + "row": 10, + "col": 7, + "letter": 18, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 5, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 17, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 5, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 19, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 6, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 17, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 6, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 19, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 17, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 19, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 5, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 17, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 5, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 19, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 17, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 19, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 17, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 19, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + } + ], + "score": 2 + }, + { + "dir": 1, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + } + ], + "score": 2 + } + ] + }, + { + "name": "empty-dogs", + "placed": null, + "rack": { + "letters": [ + 3, + 14, + 6, + 18, + 4, + 13, + 19 + ], + "blanks": 0 + }, + "mode": 0, + "ignoreCrossWords": false, + "moves": [ + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 4, + "letter": 3, + "blank": false + }, + { + "row": 7, + "col": 5, + "letter": 14, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 6, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 18, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 5, + "letter": 3, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 14, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 6, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 18, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 6, + "letter": 3, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 14, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 6, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 18, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 3, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 14, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 6, + "blank": false + }, + { + "row": 7, + "col": 10, + "letter": 18, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 1, + "tiles": [ + { + "row": 4, + "col": 7, + "letter": 3, + "blank": false + }, + { + "row": 5, + "col": 7, + "letter": 14, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 6, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 18, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 1, + "tiles": [ + { + "row": 5, + "col": 7, + "letter": 3, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 14, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 6, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 18, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 7, + "letter": 3, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 14, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 6, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 18, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 1, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 3, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 14, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 6, + "blank": false + }, + { + "row": 10, + "col": 7, + "letter": 18, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 4, + "letter": 3, + "blank": false + }, + { + "row": 7, + "col": 5, + "letter": 14, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 13, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 4, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 4, + "letter": 3, + "blank": false + }, + { + "row": 7, + "col": 5, + "letter": 14, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 4, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 18, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 5, + "letter": 3, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 14, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 13, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 4, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 5, + "letter": 3, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 14, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 4, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 18, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 5, + "letter": 3, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 14, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 6, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 6, + "letter": 3, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 14, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 13, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 4, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 6, + "letter": 3, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 14, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 4, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 18, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 6, + "letter": 3, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 14, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 6, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 3, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 14, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 13, + "blank": false + }, + { + "row": 7, + "col": 10, + "letter": 4, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 3, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 14, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 4, + "blank": false + }, + { + "row": 7, + "col": 10, + "letter": 18, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 3, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 14, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 6, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 4, + "col": 7, + "letter": 3, + "blank": false + }, + { + "row": 5, + "col": 7, + "letter": 14, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 13, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 4, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 4, + "col": 7, + "letter": 3, + "blank": false + }, + { + "row": 5, + "col": 7, + "letter": 14, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 4, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 18, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 5, + "col": 7, + "letter": 3, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 14, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 13, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 4, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 5, + "col": 7, + "letter": 3, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 14, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 4, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 18, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 5, + "col": 7, + "letter": 3, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 14, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 6, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 7, + "letter": 3, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 14, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 13, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 4, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 7, + "letter": 3, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 14, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 4, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 18, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 7, + "letter": 3, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 14, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 6, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 3, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 14, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 13, + "blank": false + }, + { + "row": 10, + "col": 7, + "letter": 4, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 3, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 14, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 4, + "blank": false + }, + { + "row": 10, + "col": 7, + "letter": 18, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 3, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 14, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 6, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 5, + "letter": 3, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 14, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 19, + "blank": false + } + ], + "score": 8 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 5, + "letter": 3, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 14, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 4, + "blank": false + } + ], + "score": 8 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 6, + "letter": 3, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 14, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 19, + "blank": false + } + ], + "score": 8 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 6, + "letter": 3, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 14, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 4, + "blank": false + } + ], + "score": 8 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 3, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 14, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 19, + "blank": false + } + ], + "score": 8 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 3, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 14, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 4, + "blank": false + } + ], + "score": 8 + }, + { + "dir": 1, + "tiles": [ + { + "row": 5, + "col": 7, + "letter": 3, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 14, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 19, + "blank": false + } + ], + "score": 8 + }, + { + "dir": 1, + "tiles": [ + { + "row": 5, + "col": 7, + "letter": 3, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 14, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 4, + "blank": false + } + ], + "score": 8 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 7, + "letter": 3, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 14, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 19, + "blank": false + } + ], + "score": 8 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 7, + "letter": 3, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 14, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 4, + "blank": false + } + ], + "score": 8 + }, + { + "dir": 1, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 3, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 14, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 19, + "blank": false + } + ], + "score": 8 + }, + { + "dir": 1, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 3, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 14, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 4, + "blank": false + } + ], + "score": 8 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 6, + "letter": 3, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 14, + "blank": false + } + ], + "score": 6 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 3, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 14, + "blank": false + } + ], + "score": 6 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 7, + "letter": 3, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 14, + "blank": false + } + ], + "score": 6 + }, + { + "dir": 1, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 3, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 14, + "blank": false + } + ], + "score": 6 + } + ] + }, + { + "name": "empty-blank", + "placed": null, + "rack": { + "letters": [ + 2, + 0, + 17, + 4, + 19 + ], + "blanks": 1 + }, + "mode": 0, + "ignoreCrossWords": false, + "moves": [ + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 3, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 4, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 5, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 4, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 18, + "blank": true + } + ], + "score": 18 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 3, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 4, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 5, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 4, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 3, + "blank": true + } + ], + "score": 18 + }, + { + "dir": 1, + "tiles": [ + { + "row": 3, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 4, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 5, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 4, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 18, + "blank": true + } + ], + "score": 18 + }, + { + "dir": 1, + "tiles": [ + { + "row": 3, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 4, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 5, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 4, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 3, + "blank": true + } + ], + "score": 18 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 4, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 5, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 4, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 4, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 5, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 4, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 18, + "blank": true + } + ], + "score": 12 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 4, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 5, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 4, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 3, + "blank": true + } + ], + "score": 12 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 5, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 4, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 5, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 4, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 18, + "blank": true + } + ], + "score": 12 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 5, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 4, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 3, + "blank": true + } + ], + "score": 12 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 6, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 4, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 6, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 4, + "blank": false + }, + { + "row": 7, + "col": 10, + "letter": 18, + "blank": true + } + ], + "score": 12 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 6, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 4, + "blank": false + }, + { + "row": 7, + "col": 10, + "letter": 3, + "blank": true + } + ], + "score": 12 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 10, + "letter": 4, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 10, + "letter": 4, + "blank": false + }, + { + "row": 7, + "col": 11, + "letter": 18, + "blank": true + } + ], + "score": 12 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 10, + "letter": 4, + "blank": false + }, + { + "row": 7, + "col": 11, + "letter": 3, + "blank": true + } + ], + "score": 12 + }, + { + "dir": 1, + "tiles": [ + { + "row": 4, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 5, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 4, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 1, + "tiles": [ + { + "row": 4, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 5, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 4, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 18, + "blank": true + } + ], + "score": 12 + }, + { + "dir": 1, + "tiles": [ + { + "row": 4, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 5, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 4, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 3, + "blank": true + } + ], + "score": 12 + }, + { + "dir": 1, + "tiles": [ + { + "row": 5, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 4, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 1, + "tiles": [ + { + "row": 5, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 4, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 18, + "blank": true + } + ], + "score": 12 + }, + { + "dir": 1, + "tiles": [ + { + "row": 5, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 4, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 3, + "blank": true + } + ], + "score": 12 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 4, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 4, + "blank": false + }, + { + "row": 10, + "col": 7, + "letter": 18, + "blank": true + } + ], + "score": 12 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 4, + "blank": false + }, + { + "row": 10, + "col": 7, + "letter": 3, + "blank": true + } + ], + "score": 12 + }, + { + "dir": 1, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 10, + "col": 7, + "letter": 4, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 1, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 10, + "col": 7, + "letter": 4, + "blank": false + }, + { + "row": 11, + "col": 7, + "letter": 18, + "blank": true + } + ], + "score": 12 + }, + { + "dir": 1, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 10, + "col": 7, + "letter": 4, + "blank": false + }, + { + "row": 11, + "col": 7, + "letter": 3, + "blank": true + } + ], + "score": 12 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 4, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 5, + "letter": 0, + "blank": true + }, + { + "row": 7, + "col": 6, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 4, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 4, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 5, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 17, + "blank": true + }, + { + "row": 7, + "col": 7, + "letter": 4, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 4, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 5, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 18, + "blank": true + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 4, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 5, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 4, + "blank": true + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 4, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 5, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 19, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 18, + "blank": true + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 5, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 0, + "blank": true + }, + { + "row": 7, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 4, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 5, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 17, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 5, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 17, + "blank": true + }, + { + "row": 7, + "col": 8, + "letter": 4, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 5, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 18, + "blank": true + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 5, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 4, + "blank": true + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 5, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 19, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 5, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 19, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 18, + "blank": true + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 6, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": true + }, + { + "row": 7, + "col": 8, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 4, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 6, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 17, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 6, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 17, + "blank": true + }, + { + "row": 7, + "col": 9, + "letter": 4, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 6, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 18, + "blank": true + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 6, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 4, + "blank": true + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 6, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 19, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 6, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 19, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 18, + "blank": true + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 0, + "blank": true + }, + { + "row": 7, + "col": 9, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 10, + "letter": 4, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 17, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 17, + "blank": true + }, + { + "row": 7, + "col": 10, + "letter": 4, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 10, + "letter": 18, + "blank": true + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 10, + "letter": 4, + "blank": true + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 19, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 19, + "blank": false + }, + { + "row": 7, + "col": 10, + "letter": 18, + "blank": true + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 4, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 5, + "col": 7, + "letter": 0, + "blank": true + }, + { + "row": 6, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 4, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 4, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 5, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 17, + "blank": true + }, + { + "row": 7, + "col": 7, + "letter": 4, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 4, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 5, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 18, + "blank": true + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 4, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 5, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 4, + "blank": true + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 4, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 5, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 19, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 18, + "blank": true + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 5, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 0, + "blank": true + }, + { + "row": 7, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 4, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 5, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 17, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 5, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 17, + "blank": true + }, + { + "row": 8, + "col": 7, + "letter": 4, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 5, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 18, + "blank": true + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 5, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 4, + "blank": true + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 5, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 19, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 5, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 19, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 18, + "blank": true + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": true + }, + { + "row": 8, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 4, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 17, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 17, + "blank": true + }, + { + "row": 9, + "col": 7, + "letter": 4, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 18, + "blank": true + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 4, + "blank": true + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 19, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 19, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 18, + "blank": true + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 0, + "blank": true + }, + { + "row": 9, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 10, + "col": 7, + "letter": 4, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 17, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 17, + "blank": true + }, + { + "row": 10, + "col": 7, + "letter": 4, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 10, + "col": 7, + "letter": 18, + "blank": true + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 10, + "col": 7, + "letter": 4, + "blank": true + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 19, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 19, + "blank": false + }, + { + "row": 10, + "col": 7, + "letter": 18, + "blank": true + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 5, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 0, + "blank": true + }, + { + "row": 7, + "col": 7, + "letter": 17, + "blank": false + } + ], + "score": 8 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 5, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 0, + "blank": true + }, + { + "row": 7, + "col": 7, + "letter": 19, + "blank": false + } + ], + "score": 8 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 5, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 17, + "blank": true + } + ], + "score": 8 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 5, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 19, + "blank": true + } + ], + "score": 8 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 6, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": true + }, + { + "row": 7, + "col": 8, + "letter": 17, + "blank": false + } + ], + "score": 8 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 6, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": true + }, + { + "row": 7, + "col": 8, + "letter": 19, + "blank": false + } + ], + "score": 8 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 6, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 17, + "blank": true + } + ], + "score": 8 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 6, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 19, + "blank": true + } + ], + "score": 8 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 0, + "blank": true + }, + { + "row": 7, + "col": 9, + "letter": 17, + "blank": false + } + ], + "score": 8 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 0, + "blank": true + }, + { + "row": 7, + "col": 9, + "letter": 19, + "blank": false + } + ], + "score": 8 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 17, + "blank": true + } + ], + "score": 8 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 19, + "blank": true + } + ], + "score": 8 + }, + { + "dir": 1, + "tiles": [ + { + "row": 5, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 0, + "blank": true + }, + { + "row": 7, + "col": 7, + "letter": 17, + "blank": false + } + ], + "score": 8 + }, + { + "dir": 1, + "tiles": [ + { + "row": 5, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 0, + "blank": true + }, + { + "row": 7, + "col": 7, + "letter": 19, + "blank": false + } + ], + "score": 8 + }, + { + "dir": 1, + "tiles": [ + { + "row": 5, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 17, + "blank": true + } + ], + "score": 8 + }, + { + "dir": 1, + "tiles": [ + { + "row": 5, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 19, + "blank": true + } + ], + "score": 8 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": true + }, + { + "row": 8, + "col": 7, + "letter": 17, + "blank": false + } + ], + "score": 8 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": true + }, + { + "row": 8, + "col": 7, + "letter": 19, + "blank": false + } + ], + "score": 8 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 17, + "blank": true + } + ], + "score": 8 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 19, + "blank": true + } + ], + "score": 8 + }, + { + "dir": 1, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 0, + "blank": true + }, + { + "row": 9, + "col": 7, + "letter": 17, + "blank": false + } + ], + "score": 8 + }, + { + "dir": 1, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 0, + "blank": true + }, + { + "row": 9, + "col": 7, + "letter": 19, + "blank": false + } + ], + "score": 8 + }, + { + "dir": 1, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 17, + "blank": true + } + ], + "score": 8 + }, + { + "dir": 1, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 19, + "blank": true + } + ], + "score": 8 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 4, + "letter": 2, + "blank": true + }, + { + "row": 7, + "col": 5, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 4, + "blank": false + } + ], + "score": 6 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 5, + "letter": 2, + "blank": true + }, + { + "row": 7, + "col": 6, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 4, + "blank": false + } + ], + "score": 6 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 6, + "letter": 2, + "blank": true + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 4, + "blank": false + } + ], + "score": 6 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": true + }, + { + "row": 7, + "col": 8, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 10, + "letter": 4, + "blank": false + } + ], + "score": 6 + }, + { + "dir": 1, + "tiles": [ + { + "row": 4, + "col": 7, + "letter": 2, + "blank": true + }, + { + "row": 5, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 4, + "blank": false + } + ], + "score": 6 + }, + { + "dir": 1, + "tiles": [ + { + "row": 5, + "col": 7, + "letter": 2, + "blank": true + }, + { + "row": 6, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 4, + "blank": false + } + ], + "score": 6 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 7, + "letter": 2, + "blank": true + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 4, + "blank": false + } + ], + "score": 6 + }, + { + "dir": 1, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": true + }, + { + "row": 8, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 10, + "col": 7, + "letter": 4, + "blank": false + } + ], + "score": 6 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 5, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 13, + "blank": true + }, + { + "row": 7, + "col": 7, + "letter": 19, + "blank": false + } + ], + "score": 4 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 5, + "letter": 2, + "blank": true + }, + { + "row": 7, + "col": 6, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 17, + "blank": false + } + ], + "score": 4 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 5, + "letter": 2, + "blank": true + }, + { + "row": 7, + "col": 6, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 19, + "blank": false + } + ], + "score": 4 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 6, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 13, + "blank": true + }, + { + "row": 7, + "col": 8, + "letter": 19, + "blank": false + } + ], + "score": 4 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 6, + "letter": 2, + "blank": true + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 17, + "blank": false + } + ], + "score": 4 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 6, + "letter": 2, + "blank": true + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 19, + "blank": false + } + ], + "score": 4 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 13, + "blank": true + }, + { + "row": 7, + "col": 9, + "letter": 19, + "blank": false + } + ], + "score": 4 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": true + }, + { + "row": 7, + "col": 8, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 17, + "blank": false + } + ], + "score": 4 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": true + }, + { + "row": 7, + "col": 8, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 19, + "blank": false + } + ], + "score": 4 + }, + { + "dir": 1, + "tiles": [ + { + "row": 5, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 13, + "blank": true + }, + { + "row": 7, + "col": 7, + "letter": 19, + "blank": false + } + ], + "score": 4 + }, + { + "dir": 1, + "tiles": [ + { + "row": 5, + "col": 7, + "letter": 2, + "blank": true + }, + { + "row": 6, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 17, + "blank": false + } + ], + "score": 4 + }, + { + "dir": 1, + "tiles": [ + { + "row": 5, + "col": 7, + "letter": 2, + "blank": true + }, + { + "row": 6, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 19, + "blank": false + } + ], + "score": 4 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 13, + "blank": true + }, + { + "row": 8, + "col": 7, + "letter": 19, + "blank": false + } + ], + "score": 4 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 7, + "letter": 2, + "blank": true + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 17, + "blank": false + } + ], + "score": 4 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 7, + "letter": 2, + "blank": true + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 19, + "blank": false + } + ], + "score": 4 + }, + { + "dir": 1, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 13, + "blank": true + }, + { + "row": 9, + "col": 7, + "letter": 19, + "blank": false + } + ], + "score": 4 + }, + { + "dir": 1, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": true + }, + { + "row": 8, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 17, + "blank": false + } + ], + "score": 4 + }, + { + "dir": 1, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": true + }, + { + "row": 8, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 19, + "blank": false + } + ], + "score": 4 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 6, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 13, + "blank": true + } + ], + "score": 2 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + } + ], + "score": 2 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 13, + "blank": true + } + ], + "score": 2 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 13, + "blank": true + } + ], + "score": 2 + }, + { + "dir": 1, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + } + ], + "score": 2 + }, + { + "dir": 1, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 13, + "blank": true + } + ], + "score": 2 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 0, + "blank": true + } + ], + "score": 0 + }, + { + "dir": 1, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 0, + "blank": true + } + ], + "score": 0 + } + ] + }, + { + "name": "empty-single-word", + "placed": null, + "rack": { + "letters": [ + 2, + 0, + 17, + 4, + 3, + 19, + 18 + ], + "blanks": 0 + }, + "mode": 0, + "ignoreCrossWords": true, + "moves": [ + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 3, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 4, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 5, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 4, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 3, + "blank": false + } + ], + "score": 22 + }, + { + "dir": 1, + "tiles": [ + { + "row": 3, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 4, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 5, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 4, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 3, + "blank": false + } + ], + "score": 22 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 3, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 4, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 5, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 4, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 18, + "blank": false + } + ], + "score": 20 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 10, + "letter": 4, + "blank": false + }, + { + "row": 7, + "col": 11, + "letter": 3, + "blank": false + } + ], + "score": 20 + }, + { + "dir": 1, + "tiles": [ + { + "row": 3, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 4, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 5, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 4, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 18, + "blank": false + } + ], + "score": 20 + }, + { + "dir": 1, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 10, + "col": 7, + "letter": 4, + "blank": false + }, + { + "row": 11, + "col": 7, + "letter": 3, + "blank": false + } + ], + "score": 20 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 4, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 5, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 4, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 3, + "blank": false + } + ], + "score": 16 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 5, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 4, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 3, + "blank": false + } + ], + "score": 16 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 6, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 4, + "blank": false + }, + { + "row": 7, + "col": 10, + "letter": 3, + "blank": false + } + ], + "score": 16 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 10, + "letter": 4, + "blank": false + }, + { + "row": 7, + "col": 11, + "letter": 18, + "blank": false + } + ], + "score": 16 + }, + { + "dir": 1, + "tiles": [ + { + "row": 4, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 5, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 4, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 3, + "blank": false + } + ], + "score": 16 + }, + { + "dir": 1, + "tiles": [ + { + "row": 5, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 4, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 3, + "blank": false + } + ], + "score": 16 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 4, + "blank": false + }, + { + "row": 10, + "col": 7, + "letter": 3, + "blank": false + } + ], + "score": 16 + }, + { + "dir": 1, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 10, + "col": 7, + "letter": 4, + "blank": false + }, + { + "row": 11, + "col": 7, + "letter": 18, + "blank": false + } + ], + "score": 16 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 4, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 5, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 4, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 18, + "blank": false + } + ], + "score": 14 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 5, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 4, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 18, + "blank": false + } + ], + "score": 14 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 6, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 4, + "blank": false + }, + { + "row": 7, + "col": 10, + "letter": 18, + "blank": false + } + ], + "score": 14 + }, + { + "dir": 1, + "tiles": [ + { + "row": 4, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 5, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 4, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 18, + "blank": false + } + ], + "score": 14 + }, + { + "dir": 1, + "tiles": [ + { + "row": 5, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 4, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 18, + "blank": false + } + ], + "score": 14 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 4, + "blank": false + }, + { + "row": 10, + "col": 7, + "letter": 18, + "blank": false + } + ], + "score": 14 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 4, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 5, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 18, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 4, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 5, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 4, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 4, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 5, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 19, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 18, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 5, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 18, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 5, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 4, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 5, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 19, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 18, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 6, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 18, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 6, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 4, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 6, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 19, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 18, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 10, + "letter": 18, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 10, + "letter": 4, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 19, + "blank": false + }, + { + "row": 7, + "col": 10, + "letter": 18, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 1, + "tiles": [ + { + "row": 4, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 5, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 18, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 1, + "tiles": [ + { + "row": 4, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 5, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 4, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 1, + "tiles": [ + { + "row": 4, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 5, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 19, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 18, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 1, + "tiles": [ + { + "row": 5, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 18, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 1, + "tiles": [ + { + "row": 5, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 4, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 1, + "tiles": [ + { + "row": 5, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 19, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 18, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 18, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 4, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 19, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 18, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 1, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 10, + "col": 7, + "letter": 18, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 1, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 10, + "col": 7, + "letter": 4, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 1, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 19, + "blank": false + }, + { + "row": 10, + "col": 7, + "letter": 18, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 5, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 17, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 5, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 19, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 6, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 17, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 6, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 19, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 17, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 8, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 9, + "letter": 19, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 5, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 17, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 5, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 19, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 17, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 19, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 17, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 1, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 8, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 9, + "col": 7, + "letter": 19, + "blank": false + } + ], + "score": 10 + }, + { + "dir": 0, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + } + ], + "score": 2 + }, + { + "dir": 1, + "tiles": [ + { + "row": 7, + "col": 7, + "letter": 0, + "blank": false + } + ], + "score": 2 + } + ] + }, + { + "name": "two-ply", + "placed": [ + { + "row": 7, + "col": 3, + "letter": 2, + "blank": false + }, + { + "row": 7, + "col": 4, + "letter": 0, + "blank": false + }, + { + "row": 7, + "col": 5, + "letter": 17, + "blank": false + }, + { + "row": 7, + "col": 6, + "letter": 4, + "blank": false + }, + { + "row": 7, + "col": 7, + "letter": 3, + "blank": false + } + ], + "rack": { + "letters": [ + 2, + 0, + 17, + 4, + 3, + 19, + 18 + ], + "blanks": 0 + }, + "mode": 0, + "ignoreCrossWords": false, + "moves": [ + { + "dir": 1, + "tiles": [ + { + "row": 5, + "col": 5, + "letter": 2, + "blank": false + }, + { + "row": 6, + "col": 5, + "letter": 0, + "blank": false + }, + { + "row": 8, + "col": 5, + "letter": 4, + "blank": false + }, + { + "row": 9, + "col": 5, + "letter": 3, + "blank": false + } + ], + "score": 18 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 4, + "letter": 2, + "blank": false + }, + { + "row": 8, + "col": 4, + "letter": 17, + "blank": false + }, + { + "row": 9, + "col": 4, + "letter": 4, + "blank": false + }, + { + "row": 10, + "col": 4, + "letter": 3, + "blank": false + } + ], + "score": 16 + }, + { + "dir": 1, + "tiles": [ + { + "row": 8, + "col": 3, + "letter": 0, + "blank": false + }, + { + "row": 9, + "col": 3, + "letter": 17, + "blank": false + }, + { + "row": 10, + "col": 3, + "letter": 4, + "blank": false + }, + { + "row": 11, + "col": 3, + "letter": 3, + "blank": false + } + ], + "score": 16 + }, + { + "dir": 1, + "tiles": [ + { + "row": 5, + "col": 5, + "letter": 2, + "blank": false + }, + { + "row": 6, + "col": 5, + "letter": 0, + "blank": false + }, + { + "row": 8, + "col": 5, + "letter": 4, + "blank": false + }, + { + "row": 9, + "col": 5, + "letter": 18, + "blank": false + } + ], + "score": 15 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 4, + "letter": 2, + "blank": false + }, + { + "row": 8, + "col": 4, + "letter": 17, + "blank": false + }, + { + "row": 9, + "col": 4, + "letter": 4, + "blank": false + }, + { + "row": 10, + "col": 4, + "letter": 18, + "blank": false + } + ], + "score": 14 + }, + { + "dir": 1, + "tiles": [ + { + "row": 8, + "col": 3, + "letter": 0, + "blank": false + }, + { + "row": 9, + "col": 3, + "letter": 17, + "blank": false + }, + { + "row": 10, + "col": 3, + "letter": 4, + "blank": false + }, + { + "row": 11, + "col": 3, + "letter": 18, + "blank": false + } + ], + "score": 14 + }, + { + "dir": 1, + "tiles": [ + { + "row": 5, + "col": 5, + "letter": 2, + "blank": false + }, + { + "row": 6, + "col": 5, + "letter": 0, + "blank": false + }, + { + "row": 8, + "col": 5, + "letter": 18, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 1, + "tiles": [ + { + "row": 5, + "col": 5, + "letter": 2, + "blank": false + }, + { + "row": 6, + "col": 5, + "letter": 0, + "blank": false + }, + { + "row": 8, + "col": 5, + "letter": 4, + "blank": false + } + ], + "score": 12 + }, + { + "dir": 1, + "tiles": [ + { + "row": 3, + "col": 7, + "letter": 2, + "blank": false + }, + { + "row": 4, + "col": 7, + "letter": 0, + "blank": false + }, + { + "row": 5, + "col": 7, + "letter": 17, + "blank": false + }, + { + "row": 6, + "col": 7, + "letter": 4, + "blank": false + } + ], + "score": 11 + }, + { + "dir": 1, + "tiles": [ + { + "row": 4, + "col": 6, + "letter": 2, + "blank": false + }, + { + "row": 5, + "col": 6, + "letter": 0, + "blank": false + }, + { + "row": 6, + "col": 6, + "letter": 17, + "blank": false + }, + { + "row": 8, + "col": 6, + "letter": 3, + "blank": false + } + ], + "score": 11 + }, + { + "dir": 1, + "tiles": [ + { + "row": 5, + "col": 5, + "letter": 2, + "blank": false + }, + { + "row": 6, + "col": 5, + "letter": 0, + "blank": false + } + ], + "score": 11 + }, + { + "dir": 1, + "tiles": [ + { + "row": 4, + "col": 6, + "letter": 2, + "blank": false + }, + { + "row": 5, + "col": 6, + "letter": 0, + "blank": false + }, + { + "row": 6, + "col": 6, + "letter": 17, + "blank": false + }, + { + "row": 8, + "col": 6, + "letter": 18, + "blank": false + } + ], + "score": 9 + }, + { + "dir": 1, + "tiles": [ + { + "row": 4, + "col": 6, + "letter": 2, + "blank": false + }, + { + "row": 5, + "col": 6, + "letter": 0, + "blank": false + }, + { + "row": 6, + "col": 6, + "letter": 17, + "blank": false + } + ], + "score": 7 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 4, + "letter": 2, + "blank": false + }, + { + "row": 8, + "col": 4, + "letter": 17, + "blank": false + }, + { + "row": 9, + "col": 4, + "letter": 18, + "blank": false + } + ], + "score": 6 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 4, + "letter": 2, + "blank": false + }, + { + "row": 8, + "col": 4, + "letter": 17, + "blank": false + }, + { + "row": 9, + "col": 4, + "letter": 4, + "blank": false + } + ], + "score": 6 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 4, + "letter": 2, + "blank": false + }, + { + "row": 8, + "col": 4, + "letter": 19, + "blank": false + }, + { + "row": 9, + "col": 4, + "letter": 18, + "blank": false + } + ], + "score": 6 + }, + { + "dir": 1, + "tiles": [ + { + "row": 8, + "col": 3, + "letter": 0, + "blank": false + }, + { + "row": 9, + "col": 3, + "letter": 17, + "blank": false + }, + { + "row": 10, + "col": 3, + "letter": 18, + "blank": false + } + ], + "score": 6 + }, + { + "dir": 1, + "tiles": [ + { + "row": 8, + "col": 3, + "letter": 0, + "blank": false + }, + { + "row": 9, + "col": 3, + "letter": 17, + "blank": false + }, + { + "row": 10, + "col": 3, + "letter": 4, + "blank": false + } + ], + "score": 6 + }, + { + "dir": 1, + "tiles": [ + { + "row": 8, + "col": 3, + "letter": 0, + "blank": false + }, + { + "row": 9, + "col": 3, + "letter": 19, + "blank": false + }, + { + "row": 10, + "col": 3, + "letter": 18, + "blank": false + } + ], + "score": 6 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 4, + "letter": 2, + "blank": false + }, + { + "row": 8, + "col": 4, + "letter": 17, + "blank": false + } + ], + "score": 5 + }, + { + "dir": 1, + "tiles": [ + { + "row": 6, + "col": 4, + "letter": 2, + "blank": false + }, + { + "row": 8, + "col": 4, + "letter": 19, + "blank": false + } + ], + "score": 5 + }, + { + "dir": 1, + "tiles": [ + { + "row": 8, + "col": 3, + "letter": 0, + "blank": false + }, + { + "row": 9, + "col": 3, + "letter": 17, + "blank": false + } + ], + "score": 5 + }, + { + "dir": 1, + "tiles": [ + { + "row": 8, + "col": 3, + "letter": 0, + "blank": false + }, + { + "row": 9, + "col": 3, + "letter": 19, + "blank": false + } + ], + "score": 5 + } + ] + } + ] +} diff --git a/ui/src/lib/dict/testdata/sample_en.words.json b/ui/src/lib/dict/testdata/sample_en.words.json new file mode 100644 index 0000000..f5aa98a --- /dev/null +++ b/ui/src/lib/dict/testdata/sample_en.words.json @@ -0,0 +1,122 @@ +{ + "alphabet": "en", + "numAdded": 18, + "words": [ + "a", + "an", + "and", + "ant", + "car", + "care", + "cared", + "cares", + "cars", + "cat", + "cats", + "do", + "doe", + "does", + "dog", + "dogs", + "done", + "dot" + ], + "indexes": [ + [ + 0 + ], + [ + 0, + 13 + ], + [ + 0, + 13, + 3 + ], + [ + 0, + 13, + 19 + ], + [ + 2, + 0, + 17 + ], + [ + 2, + 0, + 17, + 4 + ], + [ + 2, + 0, + 17, + 4, + 3 + ], + [ + 2, + 0, + 17, + 4, + 18 + ], + [ + 2, + 0, + 17, + 18 + ], + [ + 2, + 0, + 19 + ], + [ + 2, + 0, + 19, + 18 + ], + [ + 3, + 14 + ], + [ + 3, + 14, + 4 + ], + [ + 3, + 14, + 4, + 18 + ], + [ + 3, + 14, + 6 + ], + [ + 3, + 14, + 6, + 18 + ], + [ + 3, + 14, + 13, + 4 + ], + [ + 3, + 14, + 19 + ] + ] +} diff --git a/ui/src/lib/dict/testdata/sample_ru.dawg b/ui/src/lib/dict/testdata/sample_ru.dawg new file mode 100644 index 0000000000000000000000000000000000000000..22627b76b1664bb4ae06dc44b9bc3b1238b0a12d GIT binary patch literal 37 scmZQzU{Gb_WGX6UW8-9~;9|a<#rB0Epyx_h4ns%>&ka_Nvu