scrabble-solver
Version:
Scrabble Solver 2 - Free, open-source, cross-platform, multi-language analysis tool for Scrabble, Scrabble Duel, Super Scrabble, Letter League, Literaki, and Kelimelik. Quickly find the top-scoring words using the given board and tiles.
142 lines (141 loc) • 4.63 kB
JavaScript
;
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 = (currentWord) => {
return currentWord.map((cell) => cell.tile.character).join('');
};