UNPKG

scrabble-solver

Version:

Scrabble Solver 2 - Free, open-source, cross-platform, multi-language analysis tool for Scrabble, Scrabble Duel, Super Scrabble, Letter League, Crossplay, Literaki, and Kelimelik. Quickly find the top-scoring words using the given board and tiles.

142 lines (141 loc) 4.62 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Board = void 0; const constants_1 = require("@scrabble-solver/constants"); const Cell_1 = require("./Cell"); const Tile_1 = require("./Tile"); class Board { static fromStringArray(stringArray) { return new Board({ rows: stringArray.map((row, y) => row.split('').map((character, x) => new Cell_1.Cell({ isEmpty: !character || character === constants_1.EMPTY_CELL, tile: character === constants_1.EMPTY_CELL ? Tile_1.Tile.Null : new Tile_1.Tile({ character }), x, y, }))), }); } constructor({ rows }) { this.rows = rows; this.columnsCount = rows[0].length; this.rowsCount = rows.length; } get center() { const x = Math.floor(this.columnsCount / 2); const y = Math.floor(this.rowsCount / 2); return this.rows[y][x]; } clone() { const rows = this.rows.map((row) => row.map((cell) => cell.clone())); return new Board({ rows }); } collides(cell) { return this.collidesUp(cell) || this.collidesDown(cell) || this.collidesLeft(cell) || this.collidesRight(cell); } collidesDown({ x, y }) { return y < this.rowsCount - 1 && !this.rows[y + 1][x].isEmpty; } collidesLeft({ x, y }) { return x > 0 && !this.rows[y][x - 1].isEmpty; } collidesRight({ x, y }) { return x < this.columnsCount - 1 && !this.rows[y][x + 1].isEmpty; } collidesUp({ x, y }) { return y > 0 && !this.rows[y - 1][x].isEmpty; } equals(other) { return (this.columnsCount === other.columnsCount && this.rowsCount === other.rowsCount && this.rows.every((row, rowIndex) => { return row.every((cell, cellIndex) => { return cell.equals(other.rows[rowIndex][cellIndex]); }); })); } getBlanksCount() { return this.rows.reduce((count, row) => { return count + row.reduce((rowCount, cell) => rowCount + (cell.tile.isBlank ? 1 : 0), 0); }, 0); } getColumn(index) { return this.rows.map((row) => row[index]); } getRow(index) { return this.rows[index]; } getTilesCount() { return this.rows.reduce((count, row) => { return count + row.reduce((rowCount, cell) => rowCount + (cell.hasTile() ? 1 : 0), 0); }, 0); } getWords() { const horizontalWords = getHorizontalWords(this.rows); const verticalWords = getHorizontalWords(transpose(this.rows)); return [...horizontalWords, ...verticalWords]; } isEmpty() { return this.rows.every((row) => row.every(({ isEmpty }) => isEmpty)); } toJson() { return this.rows.map((row) => row.map((cell) => cell.toJson())); } toString() { return this.rows.map((row) => row.map(String).join('')).join('\n'); } updateCell(x, y, updateCell) { this.rows[y][x] = updateCell(this.rows[y][x]); } updateRow(y, updateRow) { this.rows[y] = updateRow(this.rows[y]); } } exports.Board = Board; Board.create = (width, height) => { const rows = Array(height); const emptyRow = Array(width).fill(' ').join(''); const emptyRows = rows.fill(emptyRow); return Board.fromStringArray(emptyRows); }; Board.fromJson = (json) => { return new Board({ rows: json.map((row) => row.map(Cell_1.Cell.fromJson)), }); }; const transpose = (array) => { const rows = array.length; const cols = array[0].length; const transposed = Array(cols) .fill(null) .map(() => Array(rows)); for (let y = 0; y < rows; ++y) { for (let x = 0; x < cols; ++x) { transposed[x][y] = array[y][x]; } } return transposed; }; const getHorizontalWords = (cells) => { const words = []; for (const row of cells) { let currentWord = []; for (const cell of row) { if (!cell.isEmpty) { currentWord.push(cell); } else if (currentWord.length > 0) { if (currentWord.length > 1) { words.push(wordToString(currentWord)); } currentWord = []; } } if (currentWord.length > 1) { words.push(wordToString(currentWord)); } } return words; }; const wordToString = (word) => { return word.map((cell) => cell.tile.character).join(''); };