@scrabble-solver/solver 2.8.7 → 2.8.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/build/fillPattern.d.ts +5 -0
  2. package/build/fillPattern.js +52 -0
  3. package/build/generateEndIndices.d.ts +3 -0
  4. package/build/generateEndIndices.js +9 -0
  5. package/build/generateHorizontalPatterns.d.ts +3 -0
  6. package/build/generateHorizontalPatterns.js +18 -0
  7. package/build/generatePattern.d.ts +8 -0
  8. package/build/generatePattern.js +22 -0
  9. package/build/generatePatterns.d.ts +3 -0
  10. package/build/generatePatterns.js +13 -0
  11. package/build/generateStartIndices.d.ts +3 -0
  12. package/build/generateStartIndices.js +9 -0
  13. package/build/generateVectors.d.ts +6 -0
  14. package/build/generateVectors.js +8 -0
  15. package/build/generateVerticalPatterns.d.ts +3 -0
  16. package/build/generateVerticalPatterns.js +18 -0
  17. package/build/getCellsScore.d.ts +3 -0
  18. package/build/getCellsScore.js +16 -0
  19. package/build/getPatternHash.d.ts +3 -0
  20. package/build/getPatternHash.js +13 -0
  21. package/build/getPatternScore.d.ts +3 -0
  22. package/build/getPatternScore.js +15 -0
  23. package/build/getUniquePatterns.js +5 -11
  24. package/build/index.d.ts +1 -1
  25. package/build/index.js +3 -3
  26. package/build/solve.d.ts +4 -0
  27. package/build/solve.js +23 -0
  28. package/package.json +6 -6
  29. package/src/fillPattern.test.ts +107 -0
  30. package/src/fillPattern.ts +70 -0
  31. package/src/generateEndIndices.test.ts +18 -0
  32. package/src/generateEndIndices.ts +10 -0
  33. package/src/generateHorizontalPatterns.test.ts +31 -0
  34. package/src/generateHorizontalPatterns.ts +17 -0
  35. package/src/generatePattern.ts +35 -0
  36. package/src/generatePatterns.ts +13 -0
  37. package/src/generateStartIndices.test.ts +14 -0
  38. package/src/generateStartIndices.ts +10 -0
  39. package/src/generateVectors.test.ts +12 -0
  40. package/src/generateVectors.ts +15 -0
  41. package/src/generateVerticalPatterns.test.ts +32 -0
  42. package/src/generateVerticalPatterns.ts +17 -0
  43. package/src/getCellsScore.ts +22 -0
  44. package/src/getPatternHash.test.ts +17 -0
  45. package/src/getPatternHash.ts +14 -0
  46. package/src/getPatternScore.test.ts +60 -0
  47. package/src/getPatternScore.ts +15 -0
  48. package/src/getUniquePatterns.ts +1 -10
  49. package/src/index.ts +1 -1
  50. package/src/{Solver.test.ts → solve.test.ts} +14 -13
  51. package/src/solve.ts +25 -0
  52. package/build/PatternsFiller.d.ts +0 -12
  53. package/build/PatternsFiller.js +0 -70
  54. package/build/PatternsGenerator.d.ts +0 -32
  55. package/build/PatternsGenerator.js +0 -66
  56. package/build/ScoresCalculator.d.ts +0 -17
  57. package/build/ScoresCalculator.js +0 -37
  58. package/build/Solver.d.ts +0 -10
  59. package/build/Solver.js +0 -30
  60. package/src/PatternsFiller.test.ts +0 -92
  61. package/src/PatternsFiller.ts +0 -91
  62. package/src/PatternsGenerator.test.ts +0 -89
  63. package/src/PatternsGenerator.ts +0 -103
  64. package/src/ScoresCalculator.test.ts +0 -70
  65. package/src/ScoresCalculator.ts +0 -52
  66. package/src/Solver.ts +0 -39
package/build/Solver.d.ts DELETED
@@ -1,10 +0,0 @@
1
- import { Trie } from '@kamilmielnik/trie';
2
- import { Board, Config, Result, Tile } from '@scrabble-solver/types';
3
- declare class Solver {
4
- private readonly patternsFiller;
5
- private readonly patternsGenerator;
6
- private readonly scoresCalculator;
7
- constructor(config: Config, trie: Trie);
8
- solve(board: Board, tiles: Tile[]): Result[];
9
- }
10
- export default Solver;
package/build/Solver.js DELETED
@@ -1,30 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const types_1 = require("@scrabble-solver/types");
7
- const getUniquePatterns_1 = __importDefault(require("./getUniquePatterns"));
8
- const PatternsFiller_1 = __importDefault(require("./PatternsFiller"));
9
- const PatternsGenerator_1 = __importDefault(require("./PatternsGenerator"));
10
- const ScoresCalculator_1 = __importDefault(require("./ScoresCalculator"));
11
- class Solver {
12
- constructor(config, trie) {
13
- this.patternsFiller = new PatternsFiller_1.default(config, trie);
14
- this.patternsGenerator = new PatternsGenerator_1.default(config);
15
- this.scoresCalculator = new ScoresCalculator_1.default(config);
16
- }
17
- solve(board, tiles) {
18
- const patterns = this.patternsGenerator.generate(board);
19
- const filledPatterns = patterns.flatMap((pattern) => this.patternsFiller.fill(pattern, tiles));
20
- const uniquePatterns = (0, getUniquePatterns_1.default)(filledPatterns);
21
- const results = uniquePatterns.map((pattern, index) => new types_1.Result({
22
- cells: pattern.cells,
23
- collisions: pattern.getCollisions().map((collision) => collision.cells),
24
- id: index,
25
- points: this.scoresCalculator.calculate(pattern),
26
- }));
27
- return results;
28
- }
29
- }
30
- exports.default = Solver;
@@ -1,92 +0,0 @@
1
- import { literaki } from '@scrabble-solver/configs';
2
- import { dictionaries } from '@scrabble-solver/dictionaries';
3
- import { Board, Cell, Locale, Tile, VerticalPattern } from '@scrabble-solver/types';
4
-
5
- import PatternsFiller from './PatternsFiller';
6
-
7
- describe('PatternsFiller', () => {
8
- const board = Board.fromStringArray([' t ', 'do ', ' ']);
9
- const locale = Locale.PL_PL;
10
- const config = literaki[locale];
11
- let patternsFiller: PatternsFiller | undefined;
12
-
13
- beforeAll(() => {
14
- return dictionaries.get(locale).then((trie) => {
15
- patternsFiller = new PatternsFiller(config, trie);
16
- });
17
- });
18
-
19
- it('does not affect non-blank tiles', () => {
20
- const permutations = patternsFiller!.generateBlankTilesPermutations([
21
- new Tile({ character: 'a', isBlank: false }),
22
- new Tile({ character: 'b', isBlank: false }),
23
- new Tile({ character: 'c', isBlank: false }),
24
- ]);
25
- expect(permutations.length).toBe(1);
26
- expect(permutations[0].map(String).join('')).toEqual('abc');
27
- });
28
-
29
- it('replaces blank tiles', () => {
30
- const permutations = patternsFiller!.generateBlankTilesPermutations([
31
- new Tile({ character: 'a', isBlank: false }),
32
- new Tile({ character: 'a', isBlank: false }),
33
- new Tile({ character: '', isBlank: true }),
34
- ]);
35
- expect(permutations.length).toBe(config.alphabet.length);
36
- expect(permutations[0][2].toJson()).toEqual({
37
- character: config.alphabet[0],
38
- isBlank: true,
39
- });
40
- expect(permutations[permutations.length - 1][2].toJson()).toEqual({
41
- character: config.alphabet[config.alphabet.length - 1],
42
- isBlank: true,
43
- });
44
- });
45
-
46
- it('fills patterns', () => {
47
- const pattern = new VerticalPattern({
48
- board,
49
- cells: [
50
- new Cell({ x: 0, y: 0 }),
51
- new Cell({ x: 0, y: 1, tile: new Tile({ character: 'd', isBlank: false }) }),
52
- new Cell({ x: 0, y: 2 }),
53
- ],
54
- });
55
- const tiles = [
56
- new Tile({ character: 'o', isBlank: false }),
57
- new Tile({ character: 'a', isBlank: false }),
58
- new Tile({ character: 'd', isBlank: false }),
59
- ];
60
- const filledPatterns = patternsFiller!.fill(pattern, tiles);
61
- expect(filledPatterns.length).toBe(1);
62
- });
63
-
64
- it('does not modify filled patterns', () => {
65
- const pattern = new VerticalPattern({
66
- board,
67
- cells: [
68
- new Cell({ x: 0, y: 0, isEmpty: false, tile: new Tile({ character: 'o', isBlank: false }) }),
69
- new Cell({ x: 0, y: 1, isEmpty: false, tile: new Tile({ character: 'k', isBlank: false }) }),
70
- new Cell({ x: 0, y: 2, isEmpty: false, tile: new Tile({ character: 'o', isBlank: false }) }),
71
- ],
72
- });
73
- const tiles = [new Tile({ character: 'ń', isBlank: false })];
74
- const filledPatterns = patternsFiller!.fill(pattern, tiles);
75
- expect(filledPatterns.length).toBe(1);
76
- expect(filledPatterns[0]).toEqual(pattern);
77
- });
78
-
79
- it('does not accept non-placeable filled patterns', () => {
80
- const pattern = new VerticalPattern({
81
- board,
82
- cells: [
83
- new Cell({ x: 0, y: 0, isEmpty: false, tile: new Tile({ character: 'd', isBlank: false }) }),
84
- new Cell({ x: 0, y: 1, isEmpty: false, tile: new Tile({ character: 'd', isBlank: false }) }),
85
- new Cell({ x: 0, y: 2, isEmpty: false, tile: new Tile({ character: 'd', isBlank: false }) }),
86
- ],
87
- });
88
- const tiles = [new Tile({ character: 'ń', isBlank: false })];
89
- const filledPatterns = patternsFiller!.fill(pattern, tiles);
90
- expect(filledPatterns.length).toBe(0);
91
- });
92
- });
@@ -1,91 +0,0 @@
1
- import { Trie } from '@kamilmielnik/trie';
2
- import { EMPTY_CELL } from '@scrabble-solver/constants';
3
- import { Config, Pattern, Tile } from '@scrabble-solver/types';
4
-
5
- class PatternsFiller {
6
- private readonly trie: Trie;
7
-
8
- private readonly config: Config;
9
-
10
- constructor(config: Config, trie: Trie) {
11
- this.config = config;
12
- this.trie = trie;
13
- }
14
-
15
- public fill(pattern: Pattern, tiles: Tile[]): Pattern[] {
16
- const patterns: Pattern[] = [];
17
-
18
- if (pattern.getEmptyCellsCount() > tiles.length) {
19
- return [];
20
- }
21
-
22
- const onPatternFound = (newPattern: Pattern) => patterns.push(newPattern);
23
- const tilesPermutations = this.generateBlankTilesPermutations(tiles);
24
-
25
- for (let index = 0; index < tilesPermutations.length; ++index) {
26
- const tilesPermutation = tilesPermutations[index];
27
- this.fillPattern(pattern, pattern.toString(), tilesPermutation, onPatternFound);
28
- }
29
-
30
- return patterns;
31
- }
32
-
33
- public fillPattern(
34
- pattern: Pattern,
35
- word: string,
36
- tiles: Tile[],
37
- onPatternFound: (newPattern: Pattern) => void,
38
- ): void {
39
- const indexOfFirstCellWithoutTile = pattern.getIndexOfFirstCellWithoutTile();
40
-
41
- if (indexOfFirstCellWithoutTile === -1) {
42
- if (this.canAddPattern(pattern, word)) {
43
- onPatternFound(pattern.clone());
44
- }
45
- } else {
46
- for (let index = 0; index < tiles.length; ++index) {
47
- const tile = tiles[index];
48
- const previousTile = pattern.cells[indexOfFirstCellWithoutTile].tile;
49
- pattern.cells[indexOfFirstCellWithoutTile].tile = tile;
50
- const indexOfNextCellWithoutTile = pattern.getIndexOfFirstCellWithoutTile();
51
- const indexOfFirstEmptyLetter = word.indexOf(EMPTY_CELL);
52
- const newWordPrefix = word.substring(0, indexOfFirstEmptyLetter) + tile.character;
53
- const newWord = newWordPrefix + word.substring(indexOfFirstEmptyLetter + 1);
54
- if (indexOfNextCellWithoutTile === -1) {
55
- if (this.canAddPattern(pattern, newWord)) {
56
- onPatternFound(pattern.clone());
57
- }
58
- } else if (this.trie.hasPrefix(newWordPrefix)) {
59
- tiles.splice(index, 1);
60
- this.fillPattern(pattern, newWord, tiles, onPatternFound);
61
- tiles.splice(index, 0, tile);
62
- }
63
- pattern.cells[indexOfFirstCellWithoutTile].tile = previousTile;
64
- }
65
- }
66
- }
67
-
68
- public canAddPattern(pattern: Pattern, word: string): boolean {
69
- return this.trie.has(word) && pattern.getCollisions().every((collision) => this.trie.has(collision.toString()));
70
- }
71
-
72
- public generateBlankTilesPermutations(tiles: Tile[]): Tile[][] {
73
- const { alphabet } = this.config;
74
- const firstBlankIndex = tiles.findIndex(({ character, isBlank }) => isBlank && !alphabet.includes(character));
75
-
76
- if (firstBlankIndex === -1) {
77
- return [tiles];
78
- }
79
-
80
- const remainingTiles = tiles.slice(0, firstBlankIndex).concat(tiles.slice(firstBlankIndex + 1));
81
-
82
- return this.config.alphabet.reduce<Tile[][]>((permutations, character) => {
83
- const newTile = new Tile({ character, isBlank: true });
84
- const newTiles = [...remainingTiles, newTile];
85
-
86
- return permutations.concat(this.generateBlankTilesPermutations(newTiles));
87
- }, []);
88
- }
89
- }
90
-
91
- export default PatternsFiller;
@@ -1,89 +0,0 @@
1
- import { EMPTY_CELL } from '@scrabble-solver/constants';
2
- import { Board, Cell, Config } from '@scrabble-solver/types';
3
-
4
- import PatternsGenerator from './PatternsGenerator';
5
-
6
- const board = Board.fromStringArray([' t ', 'do ', ' ']);
7
-
8
- const patternsGenerator = new PatternsGenerator({
9
- boardHeight: 3,
10
- boardWidth: 3,
11
- maximumCharactersCount: 7,
12
- } as Config);
13
-
14
- describe('PatternsGenerator', () => {
15
- const emptyCell: Cell = { hasTile: () => false } as Cell;
16
- const filledCell: Cell = { hasTile: () => true } as Cell;
17
-
18
- it('generates start indices', () => {
19
- const cells = [filledCell, filledCell, emptyCell, emptyCell, emptyCell, filledCell];
20
- const startIndices = patternsGenerator.generateStartIndices(cells);
21
- expect(startIndices).toEqual([0, 3, 4]);
22
- });
23
-
24
- it('generates end indices', () => {
25
- const tests = [
26
- {
27
- input: patternsGenerator.generateEndIndices(
28
- [filledCell, filledCell, emptyCell, emptyCell, emptyCell, filledCell],
29
- 3,
30
- ),
31
- output: [5],
32
- },
33
- {
34
- input: patternsGenerator.generateEndIndices(
35
- [filledCell, filledCell, emptyCell, emptyCell, emptyCell, filledCell, emptyCell],
36
- 3,
37
- ),
38
- output: [5, 6],
39
- },
40
- ];
41
-
42
- tests.forEach(({ input, output }) => expect(input).toEqual(output));
43
- });
44
-
45
- it('generates vectors', () => {
46
- const vectors = patternsGenerator.generateVectors({
47
- getNthVector: () => [],
48
- vectorsCount: 3,
49
- });
50
- expect(vectors.length).toBe(3);
51
- expect(vectors).toEqual([[], [], []]);
52
- });
53
-
54
- it('generates some vertical patterns', () => {
55
- const vertical = patternsGenerator.generateVertical(board);
56
- expect(vertical.length).toBeGreaterThan(0);
57
- });
58
-
59
- it('generates proper vertical patterns', () => {
60
- const vertical = patternsGenerator.generateVertical(board);
61
- expect(vertical.map(({ cells }) => cells.map(String))).toEqual([
62
- [EMPTY_CELL, 'd'],
63
- [EMPTY_CELL, 'd', EMPTY_CELL],
64
- ['d', EMPTY_CELL],
65
- ['t', 'o', EMPTY_CELL],
66
- [EMPTY_CELL, EMPTY_CELL],
67
- [EMPTY_CELL, EMPTY_CELL, EMPTY_CELL],
68
- [EMPTY_CELL, EMPTY_CELL],
69
- ]);
70
- });
71
-
72
- it('generates some horizontal patterns', () => {
73
- const horizontal = patternsGenerator.generateHorizontal(board);
74
- expect(horizontal.length).toBeGreaterThan(0);
75
- });
76
-
77
- it('generates proper horizontal patterns', () => {
78
- const horizontal = patternsGenerator.generateHorizontal(board);
79
- expect(horizontal.map(({ cells }) => cells.map(String))).toEqual([
80
- [EMPTY_CELL, 't'],
81
- [EMPTY_CELL, 't', EMPTY_CELL],
82
- ['t', EMPTY_CELL],
83
- ['d', 'o', EMPTY_CELL],
84
- [EMPTY_CELL, EMPTY_CELL],
85
- [EMPTY_CELL, EMPTY_CELL, EMPTY_CELL],
86
- [EMPTY_CELL, EMPTY_CELL],
87
- ]);
88
- });
89
- });
@@ -1,103 +0,0 @@
1
- import { Board, Cell, Config, HorizontalPattern, Pattern, VerticalPattern } from '@scrabble-solver/types';
2
-
3
- class PatternsGenerator {
4
- private readonly config: Config;
5
-
6
- constructor(config: Config) {
7
- this.config = config;
8
- }
9
-
10
- public generate(board: Board): Pattern[] {
11
- return [...this.generateHorizontal(board), ...this.generateVertical(board)];
12
- }
13
-
14
- public generateHorizontal(board: Board): HorizontalPattern[] {
15
- return this.generatePatterns({
16
- board,
17
- getNthVector: (index) => board.getRow(index),
18
- PatternModel: HorizontalPattern,
19
- vectorsCount: this.config.boardHeight,
20
- });
21
- }
22
-
23
- public generateVertical(board: Board): VerticalPattern[] {
24
- return this.generatePatterns({
25
- board,
26
- getNthVector: (index) => board.getColumn(index),
27
- PatternModel: VerticalPattern,
28
- vectorsCount: this.config.boardWidth,
29
- });
30
- }
31
-
32
- public generatePatterns<P extends Pattern>({
33
- board,
34
- getNthVector,
35
- vectorsCount,
36
- PatternModel,
37
- }: {
38
- board: Board;
39
- getNthVector: (index: number) => Cell[];
40
- PatternModel: new (parameters: { board: Board; cells: Cell[] }) => P;
41
- vectorsCount: number;
42
- }): P[] {
43
- return this.generateVectors({ getNthVector, vectorsCount }).reduce<P[]>((patterns, cells) => {
44
- return patterns.concat(this.generateCellsPatterns<P>({ board, PatternModel, cells }));
45
- }, []);
46
- }
47
-
48
- public generateVectors({
49
- getNthVector,
50
- vectorsCount,
51
- }: {
52
- getNthVector: (index: number) => Cell[];
53
- vectorsCount: number;
54
- }): Cell[][] {
55
- return Array(vectorsCount)
56
- .fill(0)
57
- .map((_, index) => getNthVector(index));
58
- }
59
-
60
- public generateCellsPatterns<P extends Pattern>({
61
- board,
62
- cells,
63
- PatternModel,
64
- }: {
65
- board: Board;
66
- cells: Cell[];
67
- PatternModel: new (parameters: { board: Board; cells: Cell[] }) => P;
68
- }): P[] {
69
- return this.generateStartIndices(cells).flatMap((startIndex) => {
70
- const endIndices = this.generateEndIndices(cells, startIndex);
71
- const patterns: P[] = [];
72
-
73
- for (const endIndex of endIndices) {
74
- const pattern = new PatternModel({
75
- board,
76
- cells: cells.slice(startIndex, endIndex + 1),
77
- });
78
-
79
- if (pattern.canBePlaced(this.config)) {
80
- patterns.push(pattern);
81
- }
82
- }
83
-
84
- return patterns;
85
- });
86
- }
87
-
88
- public generateStartIndices(cells: Cell[]): number[] {
89
- return Array(cells.length - 1)
90
- .fill(0)
91
- .map((_, startIndex) => startIndex)
92
- .filter((startIndex) => startIndex === 0 || !cells[startIndex - 1].hasTile());
93
- }
94
-
95
- public generateEndIndices(cells: Cell[], startIndex: number): number[] {
96
- return Array(cells.length - startIndex - 1)
97
- .fill(0)
98
- .map((_, endIndex) => endIndex + startIndex + 1)
99
- .filter((endIndex) => endIndex >= cells.length - 1 || !cells[endIndex + 1].hasTile());
100
- }
101
- }
102
-
103
- export default PatternsGenerator;
@@ -1,70 +0,0 @@
1
- import { literaki } from '@scrabble-solver/configs';
2
- import { Board, Cell, HorizontalPattern, Locale, Pattern, Tile, VerticalPattern } from '@scrabble-solver/types';
3
-
4
- import ScoresCalculator from './ScoresCalculator';
5
-
6
- const config = literaki[Locale.PL_PL];
7
- const scoresCalculator = new ScoresCalculator(config);
8
- const board = Board.fromStringArray([
9
- ' kasom ',
10
- ' i ',
11
- ' napiją ',
12
- ' w i ',
13
- ' krabim ',
14
- ' z ',
15
- ' ę eh ',
16
- 'f s srać ',
17
- 'i z t s ',
18
- 'knebel e ',
19
- 'a ew warcz',
20
- 'ł żyło wody ',
21
- 'o pecyj chu',
22
- ' y ',
23
- ' t ',
24
- ]);
25
-
26
- describe('ScoresCalculator', () => {
27
- it('gives proper score without collisions', () => {
28
- const pattern = new Pattern({
29
- board,
30
- cells: [
31
- new Cell({ x: 0, y: 0, tile: new Tile({ character: 'ź' }), isEmpty: true }),
32
- new Cell({ x: 1, y: 0, tile: new Tile({ character: 'a' }), isEmpty: true }),
33
- new Cell({ x: 2, y: 0, tile: new Tile({ character: 'a' }), isEmpty: true }),
34
- new Cell({ x: 3, y: 0, tile: new Tile({ character: 'a' }), isEmpty: true }),
35
- new Cell({ x: 4, y: 0, tile: new Tile({ character: 'a' }), isEmpty: true }),
36
- new Cell({ x: 5, y: 0, tile: new Tile({ character: 'a' }), isEmpty: true }),
37
- new Cell({ x: 6, y: 0, tile: new Tile({ character: 'a' }), isEmpty: true }),
38
- new Cell({ x: 7, y: 0, tile: new Tile({ character: 'ź' }), isEmpty: false }),
39
- ],
40
- });
41
- const score = scoresCalculator.calculate(pattern);
42
- expect(score).toBe(128);
43
- });
44
-
45
- it('gives proper score with collisions', () => {
46
- const pattern = new VerticalPattern({
47
- board,
48
- cells: [
49
- new Cell({ x: 2, y: 11, tile: new Tile({ character: 'l' }), isEmpty: true }),
50
- new Cell({ x: 2, y: 12, tile: new Tile({ character: 'i' }), isEmpty: true }),
51
- new Cell({ x: 2, y: 13, tile: new Tile({ character: 'n' }), isEmpty: true }),
52
- new Cell({ x: 2, y: 14, tile: new Tile({ character: 'o' }), isEmpty: true }),
53
- ],
54
- });
55
- const score = scoresCalculator.calculate(pattern);
56
- expect(score).toBe(44);
57
- });
58
-
59
- it('gives proper score for blank', () => {
60
- const pattern = new HorizontalPattern({
61
- board,
62
- cells: [
63
- new Cell({ x: 13, y: 14, tile: new Tile({ character: 'o', isBlank: true }), isEmpty: true }),
64
- new Cell({ x: 12, y: 14, tile: new Tile({ character: 't' }), isEmpty: false }),
65
- ],
66
- });
67
- const score = scoresCalculator.calculate(pattern);
68
- expect(score).toBe(2);
69
- });
70
- });
@@ -1,52 +0,0 @@
1
- import { NO_BONUS } from '@scrabble-solver/constants';
2
- import { Cell, Config, Pattern } from '@scrabble-solver/types';
3
-
4
- class ScoresCalculator {
5
- private readonly config: Config;
6
-
7
- constructor(config: Config) {
8
- this.config = config;
9
- }
10
-
11
- public calculate(pattern: Pattern): number {
12
- return this.calculatePatternScoreWithCollisions(pattern) + this.calculateBonusScore(pattern);
13
- }
14
-
15
- public calculateBonusScore(pattern: Pattern): number {
16
- const areAllTilesUsed = pattern.getEmptyCellsCount() === this.config.maximumCharactersCount;
17
- return areAllTilesUsed ? this.config.allTilesBonusScore : 0;
18
- }
19
-
20
- public calculatePatternScoreWithCollisions(pattern: Pattern): number {
21
- return pattern
22
- .getCollisions()
23
- .reduce(
24
- (patternsScore, collisionPattern) => patternsScore + this.calculatePatternScore(collisionPattern),
25
- this.calculatePatternScore(pattern),
26
- );
27
- }
28
-
29
- public calculatePatternScore(pattern: Pattern): number {
30
- const { multiplier, score } = pattern.cells.reduce(this.reduceCellScore, {
31
- multiplier: 1,
32
- score: 0,
33
- });
34
- return score * multiplier;
35
- }
36
-
37
- public reduceCellScore = (
38
- { multiplier, score }: { multiplier: number; score: number },
39
- cell: Cell,
40
- ): { multiplier: number; score: number } => {
41
- const bonus = this.config.getCellBonus(cell);
42
- const { characterMultiplier, wordMultiplier } = bonus && bonus.canApply(this.config, cell) ? bonus.value : NO_BONUS;
43
- const characterScore = cell.tile.isBlank ? this.config.blankScore : this.config.pointsMap[cell.tile.character];
44
-
45
- return {
46
- multiplier: multiplier * wordMultiplier,
47
- score: score + characterScore * characterMultiplier,
48
- };
49
- };
50
- }
51
-
52
- export default ScoresCalculator;
package/src/Solver.ts DELETED
@@ -1,39 +0,0 @@
1
- import { Trie } from '@kamilmielnik/trie';
2
- import { Board, Config, Result, Tile } from '@scrabble-solver/types';
3
-
4
- import getUniquePatterns from './getUniquePatterns';
5
- import PatternsFiller from './PatternsFiller';
6
- import PatternsGenerator from './PatternsGenerator';
7
- import ScoresCalculator from './ScoresCalculator';
8
-
9
- class Solver {
10
- private readonly patternsFiller: PatternsFiller;
11
-
12
- private readonly patternsGenerator: PatternsGenerator;
13
-
14
- private readonly scoresCalculator: ScoresCalculator;
15
-
16
- constructor(config: Config, trie: Trie) {
17
- this.patternsFiller = new PatternsFiller(config, trie);
18
- this.patternsGenerator = new PatternsGenerator(config);
19
- this.scoresCalculator = new ScoresCalculator(config);
20
- }
21
-
22
- public solve(board: Board, tiles: Tile[]): Result[] {
23
- const patterns = this.patternsGenerator.generate(board);
24
- const filledPatterns = patterns.flatMap((pattern) => this.patternsFiller.fill(pattern, tiles));
25
- const uniquePatterns = getUniquePatterns(filledPatterns);
26
- const results = uniquePatterns.map(
27
- (pattern, index) =>
28
- new Result({
29
- cells: pattern.cells,
30
- collisions: pattern.getCollisions().map((collision) => collision.cells),
31
- id: index,
32
- points: this.scoresCalculator.calculate(pattern),
33
- }),
34
- );
35
- return results;
36
- }
37
- }
38
-
39
- export default Solver;