Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Limit shape span, increase grid size #8

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/components/Game.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ function GameMessage({gameState}) {

function Game({dispatchGameState, gameState, isDaily}) {
const gameOver = gameIsSolvedQ(gameState.foundSolutions);
const gridSize = Math.sqrt(gameState.letters.length);

return (
<div id="game">
Expand Down Expand Up @@ -85,7 +86,7 @@ function Game({dispatchGameState, gameState, isDaily}) {
<GameMessage gameOver={gameOver} gameState={gameState}></GameMessage>
)}

<div id="board">
<div id="board" className={`size${gridSize}`}>
{gameState.letters.map((letter, index) => (
<Letter
letter={letter}
Expand Down
2 changes: 1 addition & 1 deletion src/components/Shape.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export function Shape({

return (
<div className="shapeAndWord">
<div className="shape">{boxes}</div>
<div className={`shape size${gridSize}`}>{boxes}</div>
<div className="foundWord">{word}</div>
</div>
);
Expand Down
6 changes: 4 additions & 2 deletions src/logic/gameInit.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,15 @@ export function gameInit({
return {...savedState, playedIndexes: [], result: ""};
}

const gridSize = 4;

difficultyLevel = isDaily ? getDifficultyLevelForDay() : difficultyLevel || 3;

const [minWordLength, maxWordLength] =
getShapeSizeForDifficulty(difficultyLevel);

// if the min word length is >=5, set the grid size to 5; otherwise, set it to 4
// This helps prevent shapes that have a low number of possible placements
const gridSize = minWordLength >= 5 ? 5 : 4;

const [letters, shapes, officialSolutions] = getGame({
gridSize,
minWordLength,
Expand Down
9 changes: 9 additions & 0 deletions src/logic/getColumnIndex.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Gets the column index of a given index in a grid, assuming a square grid
export function getColumnIndex(index, gridSize) {
// error if index exceeds the grid size
if (index >= gridSize * gridSize || index < 0) {
throw new Error("Index is not within grid size");
}

return index % gridSize;
}
56 changes: 56 additions & 0 deletions src/logic/getColumnIndex.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import {getColumnIndex} from "./getColumnIndex";

describe("getColumnIndex", () => {
test("returns the column index of a given index (grid size 4)", () => {
const indexes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
const gridSize = 4;
const expectedColumns = [0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3];
const result = indexes.map((index) => getColumnIndex(index, gridSize));
expect(result).toEqual(expectedColumns);
});

test("returns the column index of a given index (grid size 5)", () => {
const indexes = [
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24,
];
const gridSize = 5;
const expectedColumns = [
0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4,
];
const result = indexes.map((index) => getColumnIndex(index, gridSize));
expect(result).toEqual(expectedColumns);
});

test("returns the column index of a given index (grid size 1)", () => {
const index = 0;
const gridSize = 1;
const expectedColumn = 0;
const result = getColumnIndex(index, gridSize);
expect(result).toEqual(expectedColumn);
});

test("errors if index exceeds gridSize", () => {
const index = 4;
const gridSize = 2;
expect(() => getColumnIndex(index, gridSize)).toThrow(
"Index is not within grid size",
);
});

test("errors if index is negative", () => {
const index = -1;
const gridSize = 2;
expect(() => getColumnIndex(index, gridSize)).toThrow(
"Index is not within grid size",
);
});

test("errors if gridSize is 0", () => {
const index = 0;
const gridSize = 0;
expect(() => getColumnIndex(index, gridSize)).toThrow(
"Index is not within grid size",
);
});
});
12 changes: 11 additions & 1 deletion src/logic/getLettersAndShapes.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {trie} from "./trie";
import {shuffleArray} from "@skedwards88/word_logic";
import {omitDuplicateWordsAcrossShapes} from "./omitDuplicateWordsAcrossShapes";
import {centerIndexes} from "./centerIndexes";
import {omitShapesThatExceedSize} from "./omitShapesThatExceedSize";

export function getLettersAndShapes({
gridSize,
Expand All @@ -23,7 +24,16 @@ export function getLettersAndShapes({
trie: trie,
});

const shuffledWordIndexes = shuffleArray(wordIndexes, pseudoRandomGenerator);
// Remove wordIndexes that exceed a shape width or height of gridSize - 1
const wordIndexesOfAppropriateSize = omitShapesThatExceedSize({
wordIndexes,
gridSize,
});

const shuffledWordIndexes = shuffleArray(
wordIndexesOfAppropriateSize,
pseudoRandomGenerator,
);

// Figure out what shape each word makes
// by centering the word indexes in the grid
Expand Down
9 changes: 9 additions & 0 deletions src/logic/getRowIndex.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Gets the row index of a given index in a grid, assuming a square grid
export function getRowIndex(index, gridSize) {
// error if index exceeds the grid size
if (index >= gridSize * gridSize || index < 0) {
throw new Error("Index is not within grid size");
}

return Math.floor(index / gridSize);
}
56 changes: 56 additions & 0 deletions src/logic/getRowIndex.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import {getRowIndex} from "./getRowIndex";

describe("getRowIndex", () => {
test("returns the row index of a given index (grid size 4)", () => {
const indexes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
const gridSize = 4;
const expectedRows = [0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3];
const result = indexes.map((index) => getRowIndex(index, gridSize));
expect(result).toEqual(expectedRows);
});

test("returns the row index of a given index (grid size 5)", () => {
const indexes = [
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24,
];
const gridSize = 5;
const expectedRows = [
0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4,
];
const result = indexes.map((index) => getRowIndex(index, gridSize));
expect(result).toEqual(expectedRows);
});

test("returns the row index of a given index (grid size 1)", () => {
const index = 0;
const gridSize = 1;
const expectedRow = 0;
const result = getRowIndex(index, gridSize);
expect(result).toEqual(expectedRow);
});

test("errors if index exceeds gridSize", () => {
const index = 4;
const gridSize = 2;
expect(() => getRowIndex(index, gridSize)).toThrow(
"Index is not within grid size",
);
});

test("errors if index is negative", () => {
const index = -1;
const gridSize = 2;
expect(() => getRowIndex(index, gridSize)).toThrow(
"Index is not within grid size",
);
});

test("errors if gridSize is 0", () => {
const index = 0;
const gridSize = 0;
expect(() => getRowIndex(index, gridSize)).toThrow(
"Index is not within grid size",
);
});
});
22 changes: 22 additions & 0 deletions src/logic/omitShapesThatExceedSize.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import {getColumnIndex} from "./getColumnIndex";
import {getRowIndex} from "./getRowIndex";

// Remove wordIndexes that exceed a shape width or height of gridSize - 1
export function omitShapesThatExceedSize({wordIndexes, gridSize}) {
const filteredWordIndexes = wordIndexes.filter((indexes) => {
const rowIndexes = indexes.map((index) => getRowIndex(index, gridSize));
const columnIndexes = indexes.map((index) =>
getColumnIndex(index, gridSize),
);
const maxRow = Math.max(...rowIndexes);
const minRow = Math.min(...rowIndexes);
const maxColumn = Math.max(...columnIndexes);
const minColumn = Math.min(...columnIndexes);

return (
maxRow - minRow < gridSize - 1 && maxColumn - minColumn < gridSize - 1
);
});

return filteredWordIndexes;
}
103 changes: 103 additions & 0 deletions src/logic/omitShapesThatExceedSize.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import {omitShapesThatExceedSize} from "./omitShapesThatExceedSize";

describe("omitShapesThatExceedSize", () => {
test("removes wordIndexes that exceed a shape width or height of gridSize - 1 (grid size 5)", () => {
const wordIndexes = [
[0, 1, 2, 3], // width 4, height 1
[2, 3, 4, 0, 1], // width 5, height 1
[15, 18, 19, 20, 16, 17], // width 5, height 2
[10, 11, 12, 13, 14, 15, 16], // width 5, height 2
[0, 1, 2, 3, 5, 6, 7, 8], // width 4, height 2
[15, 10, 5, 0], // width 1, height 4
[2, 7, 12, 17, 22], // width 1, height 5
[0, 5, 10, 15, 20, 2], // width 2, height 5
[3, 7, 11, 15], // width 4, height 4
[0, 6, 12, 18, 24], // width 5, height 5
];
const gridSize = 5;
const expectedWordIndexes = [
[0, 1, 2, 3], // width 4, height 1
[0, 1, 2, 3, 5, 6, 7, 8], // width 4, height 2
[15, 10, 5, 0], // width 1, height 4
[3, 7, 11, 15], // width 4, height 4
];
const result = omitShapesThatExceedSize({wordIndexes, gridSize});
expect(result).toEqual(expectedWordIndexes);
});

test("removes wordIndexes that exceed a shape width or height of gridSize - 1 (grid size 4)", () => {
const wordIndexes = [
[1, 2, 3], // width 3, height 1
[0, 1, 2, 3], // width 4, height 1
[2, 3, 7, 1], // width 3, height 2
[2, 3, 4, 0, 1], // width 4, height 2
[7, 8, 9, 10, 11, 12], // width 4, height 3
[8, 4, 9, 10, 12], // width 3, height 3
[12, 8, 4, 0], // width 1, height 4
[12, 8, 4], // width 1, height 3
[0, 4, 8, 12, 5], // width 2, height 4
[0, 4, 8, 5], // width 2, height 3
[3, 6, 9, 12], // width 4, height 4
];
const gridSize = 4;
const expectedWordIndexes = [
[1, 2, 3], // width 3, height 1
[2, 3, 7, 1], // width 3, height 2
[8, 4, 9, 10, 12], // width 3, height 3
[12, 8, 4], // width 1, height 3
[0, 4, 8, 5], // width 2, height 3
];
const result = omitShapesThatExceedSize({wordIndexes, gridSize});
expect(result).toEqual(expectedWordIndexes);
});

test("works with empty wordIndexes input", () => {
const wordIndexes = [];
const gridSize = 4;
const expectedWordIndexes = [];
const result = omitShapesThatExceedSize({wordIndexes, gridSize});
expect(result).toEqual(expectedWordIndexes);
});

test("works with singleton wordIndexes input", () => {
const wordIndexes = [[0, 1, 2, 3]];
const gridSize = 4;
const expectedWordIndexes = [];
const result = omitShapesThatExceedSize({wordIndexes, gridSize});
expect(result).toEqual(expectedWordIndexes);
});

test("does not remove any indexes if all are within size", () => {
const wordIndexes = [
[1, 2, 3], // width 3, height 1
[2, 3, 7, 1], // width 3, height 2
[8, 4, 9, 10, 12], // width 3, height 3
[12, 8, 4], // width 1, height 3
[0, 4, 8, 5], // width 2, height 3
];
const gridSize = 4;
const expectedWordIndexes = [
[1, 2, 3], // width 3, height 1
[2, 3, 7, 1], // width 3, height 2
[8, 4, 9, 10, 12], // width 3, height 3
[12, 8, 4], // width 1, height 3
[0, 4, 8, 5], // width 2, height 3
];
const result = omitShapesThatExceedSize({wordIndexes, gridSize});
expect(result).toEqual(expectedWordIndexes);
});

test("removes all input if all exceed size", () => {
const wordIndexes = [
[0, 1, 2, 3], // width 4, height 1
[2, 3, 4, 0, 1], // width 4, height 2
[7, 8, 9, 10, 11, 12], // width 4, height 3
[12, 8, 4, 0], // width 1, height 4
[3, 6, 9, 12], // width 4, height 4
];
const gridSize = 4;
const expectedWordIndexes = [];
const result = omitShapesThatExceedSize({wordIndexes, gridSize});
expect(result).toEqual(expectedWordIndexes);
});
});
Loading
Loading