From 85d338511ff36fecbe19579a6eabc0c67aac26de Mon Sep 17 00:00:00 2001 From: tblackwell-tm Date: Wed, 6 Mar 2024 10:48:00 +0000 Subject: [PATCH] initialiseCells accept object for params and include allowMissingSolutions logic --- src/components/Crossword/Crossword.tsx | 12 ++-- src/redux/cellsSlice.test.ts | 10 +-- src/redux/cluesSlice.test.ts | 10 +-- src/utils/cell.test.ts | 90 +++++++++++++------------- src/utils/cell.ts | 28 ++++++-- src/utils/clue.test.ts | 30 ++++----- src/utils/test.ts | 10 +-- 7 files changed, 102 insertions(+), 88 deletions(-) diff --git a/src/components/Crossword/Crossword.tsx b/src/components/Crossword/Crossword.tsx index ad980f6..c5781e0 100644 --- a/src/components/Crossword/Crossword.tsx +++ b/src/components/Crossword/Crossword.tsx @@ -98,12 +98,12 @@ export default function Crossword({ React.useEffect(() => { try { // initialise cells - const initCells = initialiseCells( - data.dimensions.cols, - data.dimensions.rows, - data.entries, - loadGrid ?? guessGrid, - ); + const initCells = initialiseCells({ + cols: data.dimensions.cols, + rows: data.dimensions.rows, + entries: data.entries, + guessGrid: loadGrid ?? guessGrid, + }); dispatch(cellsActionUpdateGrid(initCells)); // initialise clues diff --git a/src/redux/cellsSlice.test.ts b/src/redux/cellsSlice.test.ts index d89dc8a..df32be9 100644 --- a/src/redux/cellsSlice.test.ts +++ b/src/redux/cellsSlice.test.ts @@ -10,11 +10,11 @@ function getState() { } test('it updates grid', () => { - const cells = initialiseCells( - testData.dimensions.cols, - testData.dimensions.rows, - testData.entries, - ); + const cells = initialiseCells({ + cols: testData.dimensions.cols, + rows: testData.dimensions.rows, + entries: testData.entries, + }); store.dispatch(updateGrid(cells)); expect(getState()).toStrictEqual(cells); }); diff --git a/src/redux/cluesSlice.test.ts b/src/redux/cluesSlice.test.ts index 4c77189..4d6e5ad 100644 --- a/src/redux/cluesSlice.test.ts +++ b/src/redux/cluesSlice.test.ts @@ -17,11 +17,11 @@ function getState() { } test('it updates grid', () => { - const cells = initialiseCells( - testData.dimensions.cols, - testData.dimensions.rows, - testData.entries, - ); + const cells = initialiseCells({ + cols: testData.dimensions.cols, + rows: testData.dimensions.rows, + entries: testData.entries, + }); const clues = initialiseClues(testData.entries, cells); diff --git a/src/utils/cell.test.ts b/src/utils/cell.test.ts index e3bfbe4..04a6637 100644 --- a/src/utils/cell.test.ts +++ b/src/utils/cell.test.ts @@ -95,80 +95,80 @@ test('blankNeighbours without neighbours', () => { test('initialiseCells with invalid data 1', () => { expect(() => - initialiseCells( - invalidData1.dimensions.cols, - invalidData1.dimensions.rows, - invalidData1.entries, - ), + initialiseCells({ + cols: invalidData1.dimensions.cols, + rows: invalidData1.dimensions.rows, + entries: invalidData1.entries, + }), ).toThrow('Crossword data error: solution length mismatch'); }); test('initialiseCells with invalid data 2', () => { expect(() => - initialiseCells( - invalidData2.dimensions.cols, - invalidData2.dimensions.rows, - invalidData2.entries, - ), + initialiseCells({ + cols: invalidData2.dimensions.cols, + rows: invalidData2.dimensions.rows, + entries: invalidData2.entries, + }), ).toThrow('Crossword data error: out of bounds'); }); test('initialiseCells with invalid data 3', () => { expect(() => - initialiseCells( - invalidData3.dimensions.cols, - invalidData3.dimensions.rows, - invalidData3.entries, - ), + initialiseCells({ + cols: invalidData3.dimensions.cols, + rows: invalidData3.dimensions.rows, + entries: invalidData3.entries, + }), ).toThrow('Crossword data error: solution character clash'); }); test('initialiseCells with invalid data 4', () => { expect(() => - initialiseCells( - invalidData4.dimensions.cols, - invalidData4.dimensions.rows, - invalidData4.entries, - ), + initialiseCells({ + cols: invalidData4.dimensions.cols, + rows: invalidData4.dimensions.rows, + entries: invalidData4.entries, + }), ).toThrow('Crossword data error: overlapping across solutions'); }); test('initialiseCells with invalid data 5', () => { expect(() => - initialiseCells( - invalidData5.dimensions.cols, - invalidData5.dimensions.rows, - invalidData5.entries, - ), + initialiseCells({ + cols: invalidData5.dimensions.cols, + rows: invalidData5.dimensions.rows, + entries: invalidData5.entries, + }), ).toThrow('Crossword data error: overlapping down solutions'); }); test('initialiseCells with invalid data 6', () => { expect(() => - initialiseCells( - invalidData6.dimensions.cols, - invalidData6.dimensions.rows, - invalidData6.entries, - ), + initialiseCells({ + cols: invalidData6.dimensions.cols, + rows: invalidData6.dimensions.rows, + entries: invalidData6.entries, + }), ).toThrow('Crossword data error: clue id missing from group'); }); test('initialiseCells with invalid data 7', () => { expect(() => - initialiseCells( - invalidData7.dimensions.cols, - invalidData7.dimensions.rows, - invalidData7.entries, - ), + initialiseCells({ + cols: invalidData7.dimensions.cols, + rows: invalidData7.dimensions.rows, + entries: invalidData7.entries, + }), ).toThrow('Crossword data error: group clue id not found'); }); test('initialiseCells with valid data', () => { - const cells = initialiseCells( - validData.dimensions.cols, - validData.dimensions.rows, - validData.entries, - ); + const cells = initialiseCells({ + cols: validData.dimensions.cols, + rows: validData.dimensions.rows, + entries: validData.entries, + }); expect(cells.length).toBe(23); expect(cells).toEqual([ @@ -366,12 +366,12 @@ test('initialiseCells with valid data and guess grid', () => { validData.dimensions.rows, gridChar, ); - const cells = initialiseCells( - validData.dimensions.cols, - validData.dimensions.rows, - validData.entries, + const cells = initialiseCells({ + cols: validData.dimensions.cols, + rows: validData.dimensions.rows, + entries: validData.entries, guessGrid, - ); + }); expect(cells.length).toBe(23); expect(cells).toEqual([ diff --git a/src/utils/cell.ts b/src/utils/cell.ts index f9b4043..fc5c700 100644 --- a/src/utils/cell.ts +++ b/src/utils/cell.ts @@ -46,12 +46,19 @@ export function blankNeighbours( * @param entries * @returns */ -export function initialiseCells( - cols: number, - rows: number, - entries: GuardianClue[], - guessGrid?: GuessGrid, -) { +export function initialiseCells({ + cols, + rows, + entries, + guessGrid, + allowMissingSolutions = false, +}: { + cols: number; + rows: number; + entries: GuardianClue[]; + guessGrid?: GuessGrid; + allowMissingSolutions?: boolean; +}) { const cells: Cell[] = []; const entryIds = entries.map((entry) => entry.id); @@ -65,6 +72,7 @@ export function initialiseCells( if (col < 0 || col >= cols || row < 0 || row >= rows) { throw new Error('Crossword data error: out of bounds'); } else if ( + !allowMissingSolutions && entry.solution !== undefined && entry.length !== entry.solution.length ) { @@ -96,7 +104,7 @@ export function initialiseCells( cells.push(newCell); } else { // merge cell - if (currentCell.val !== entry.solution?.[i]) { + if (!allowMissingSolutions && currentCell.val !== entry.solution?.[i]) { throw new Error('Crossword data error: solution character clash'); } else if ( across && @@ -111,6 +119,12 @@ export function initialiseCells( } else { currentCell.num = i === 0 ? entry.number : currentCell.num; currentCell.clueIds = [...currentCell.clueIds, entry.id]; + + // overwrite with new value + const newChar = entry.solution?.[i]; + if (newChar !== undefined) { + currentCell.val = newChar as Char; + } } } } diff --git a/src/utils/clue.test.ts b/src/utils/clue.test.ts index 1f3acb9..ec09f35 100644 --- a/src/utils/clue.test.ts +++ b/src/utils/clue.test.ts @@ -152,11 +152,11 @@ describe('getCrossingClueIds', () => { describe('initialiseClues', () => { test('clues get initialised', () => { - const cells = initialiseCells( - testData.dimensions.cols, - testData.dimensions.rows, - testData.entries, - ); + const cells = initialiseCells({ + cols: testData.dimensions.cols, + rows: testData.dimensions.rows, + entries: testData.entries, + }); const clues = initialiseClues(testData.entries, cells); expect(clues).toEqual([ @@ -234,11 +234,11 @@ describe('initialiseClues', () => { }); test('clues get initialised with selected clue', () => { - const cells = initialiseCells( - testData.dimensions.cols, - testData.dimensions.rows, - testData.entries, - ); + const cells = initialiseCells({ + cols: testData.dimensions.cols, + rows: testData.dimensions.rows, + entries: testData.entries, + }); const clues = initialiseClues(testData.entries, cells, '1-across'); expect(clues).toEqual( @@ -262,11 +262,11 @@ describe('initialiseClues', () => { }); test('clues get initialised with answered clues', () => { - const cells = initialiseCells( - testData.dimensions.cols, - testData.dimensions.rows, - testData.entries, - ); + const cells = initialiseCells({ + cols: testData.dimensions.cols, + rows: testData.dimensions.rows, + entries: testData.entries, + }); // reveal all cells store.dispatch(cellsUpdateGrid(cells)); diff --git a/src/utils/test.ts b/src/utils/test.ts index ec3e20d..483f716 100644 --- a/src/utils/test.ts +++ b/src/utils/test.ts @@ -11,12 +11,12 @@ export function initialiseStore( data: GuardianCrossword, guessGrid?: GuessGrid, ) { - const cells = initialiseCells( - data.dimensions.cols, - data.dimensions.rows, - data.entries, + const cells = initialiseCells({ + cols: data.dimensions.cols, + rows: data.dimensions.rows, + entries: data.entries, guessGrid, - ); + }); const clues = initialiseClues(data.entries, cells);