Skip to content

Commit

Permalink
utils dir created
Browse files Browse the repository at this point in the history
  • Loading branch information
Deykun committed May 31, 2024
1 parent fd86258 commit 1f63d84
Show file tree
Hide file tree
Showing 4 changed files with 191 additions and 138 deletions.
143 changes: 5 additions & 138 deletions src/store/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ import { LOCAL_STORAGE, SUPPORTED_DICTIONARY_BY_LANG } from '@const';

import { getHasSpecialCharacters } from '@utils/normilzeWord';

import { getLetterOccuranceInWord } from './utils/getLetterOccuranceInWord';
import { getKeyboardState } from './utils/getKeyboardState';

export const selectIsProcessing = (state: RootState) => state.game.isProcessing;
export const selectWordToGuess = (state: RootState) => state.game.wordToGuess;
export const selectWordToSubmit = (state: RootState) => state.game.wordToSubmit;
Expand Down Expand Up @@ -94,10 +97,6 @@ const selectPositionLetters = (state: RootState) => state.game.letters.position;

export const selectGuesses = (state: RootState) => state.game.guesses;

// hello -> 2
// https://stackoverflow.com/a/72347965/6743808 - claims is the fastest
const getLetterOccuranceInWord = (letter: string, word: string) => word.length - word.replaceAll(letter, '').length;

const getLetterState = (
letter: string,
wordToSubmit: string,
Expand Down Expand Up @@ -274,148 +273,16 @@ export const selectWordState = (word: string) => createSelector(
},
);

const getIsTextMatchingOrder = (text: string, order: string[]) => {
const {
isMatching,
} = order.reduce((stack, subtext) => {
if (!stack.restString.includes(subtext)) {
return {
restString: '',
isMatching: false,
};
}

const [, ...rest] = stack.restString.split(subtext);
stack.restString = rest.join('');

return stack;
}, {
restString: text,
isMatching: true,
});

return isMatching;
};

export const selectKeyboardState = createSelector(
selectWordToGuess,
selectWordToSubmit,
selectIncorrectLetters,
selectPositionLetters,
selectFlatAffixes,
(wordToGuess, wordToSubmit, incorrectLetter, positionLetters, flatAffixes) => {
if (!wordToSubmit || !wordToSubmit.replaceAll(' ', '')) {
return {
status: AffixStatus.Unknown,
};
}

const uniqueWordLetters = [...(new Set(wordToSubmit.split('')))].filter(letter => letter !== ' ');

const incorrectTyppedLetters = uniqueWordLetters.filter((uniqueLetter) => {
const isIncorrect = incorrectLetter[uniqueLetter] > 0;
if (!isIncorrect) {
return false;
}

const isCorrectSometimes = positionLetters[uniqueLetter] > 0;
if (isCorrectSometimes) {
const occurrencesOfLetterInSubmitWord = getLetterOccuranceInWord(uniqueLetter, wordToSubmit);

return occurrencesOfLetterInSubmitWord > positionLetters[uniqueLetter];
}

return true;
return getKeyboardState({
wordToGuess, wordToSubmit, incorrectLetter, positionLetters, flatAffixes,
});

const hasIncorrectLetterTyped = incorrectTyppedLetters.length > 0;
if (hasIncorrectLetterTyped) {
return {
status: AffixStatus.Incorrect,
details: incorrectTyppedLetters.join(', '),
};
}

// TODO: add info at the end if no special letter typed
const hasWordToGuessSpecialCharacters = wordToGuess && getHasSpecialCharacters(wordToGuess);
const hasWordToSubmitSpecialCharacters = wordToSubmit && getHasSpecialCharacters(wordToSubmit);
const specialCharacterTypedWhenNotNeeded = !hasWordToGuessSpecialCharacters && hasWordToSubmitSpecialCharacters;
if (specialCharacterTypedWhenNotNeeded) {
return {
status: AffixStatus.Incorrect,
details: [], // TODO: add special
};
}

const uniqueRequiredLetters = Object.keys(positionLetters);
const allKnownLettersAreTyped = uniqueRequiredLetters.every((uniqueLetter) => {
const occurrencesOfLetterInSubmitWord = getLetterOccuranceInWord(uniqueLetter, wordToSubmit);

return occurrencesOfLetterInSubmitWord >= positionLetters[uniqueLetter];
});

if (allKnownLettersAreTyped) {
if (flatAffixes) {
const isWrongStart = !wordToSubmit.startsWith(flatAffixes.start);
if (isWrongStart) {
return {
status: AffixStatus.IncorrectStart,
details: flatAffixes.start,
};
}

if (flatAffixes.notStart.includes(wordToSubmit[0])) {
return {
status: AffixStatus.IncorrectStart,
details: wordToSubmit[0],
};
}

const isWrongEnd = !wordToSubmit.endsWith(flatAffixes.end);
if (isWrongEnd) {
return {
status: AffixStatus.IncorrectEnd,
details: flatAffixes.end,
};
}

if (flatAffixes.notEnd.includes(wordToSubmit[wordToSubmit.length - 1])) {
return {
status: AffixStatus.IncorrectEnd,
details: wordToSubmit[wordToSubmit.length - 1],
};
}

const wrongMiddles = flatAffixes.middle.filter(flatAffix => !wordToSubmit.includes(flatAffix));
const isWrongMiddle = wrongMiddles.length > 0;
if (isWrongMiddle) {
return {
status: AffixStatus.IncorrectMiddle,
details: wrongMiddles.join(', '),
};
}

if (flatAffixes.correctOrders.length > 0) {
const wrongOrders = flatAffixes.correctOrders.filter(order => !getIsTextMatchingOrder(wordToSubmit, order));
const isWrongOrder = wrongOrders.length > 0;
if (isWrongOrder) {
return {
status: AffixStatus.IncorrectOrder,
details: wrongOrders.join(', '),
};
}
}
}

return {
status: AffixStatus.Correct,
};
}

// If not all known letters are typed, we know that the word is incorrect, but we don't display it.
return {
status: AffixStatus.Unknown,
};
},
);

Expand Down
28 changes: 28 additions & 0 deletions src/store/utils/getKeyboardState.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { describe, expect, it } from '@jest/globals';

// import { AffixStatus } from '@common-types';

import { getKeyboardState } from './getKeyboardState';

describe('getKeyboardState', () => {
describe('getKeyboardState', () => {
it('should embed date inside number', () => {
expect(getKeyboardState({
wordToGuess: 'start',
wordToSubmit: 'start',
incorrectLetter: {},
positionLetters: {},
flatAffixes: {
start: '',
notStart: [],
middle: [],
correctOrders: [],
notEnd: [],
end: '',
},
})).toBe({
status: '',
});
});
});
});
155 changes: 155 additions & 0 deletions src/store/utils/getKeyboardState.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import { AffixStatus, FlatAffixes, UsedLetters } from '@common-types';

import { getHasSpecialCharacters } from '@utils/normilzeWord';

import { getLetterOccuranceInWord } from './getLetterOccuranceInWord';

const getIsTextMatchingOrder = (text: string, order: string[]) => {
const {
isMatching,
} = order.reduce((stack, subtext) => {
if (!stack.restString.includes(subtext)) {
return {
restString: '',
isMatching: false,
};
}

const [, ...rest] = stack.restString.split(subtext);
stack.restString = rest.join('');

return stack;
}, {
restString: text,
isMatching: true,
});

return isMatching;
};

export const getKeyboardState = ({
wordToGuess,
wordToSubmit,
incorrectLetter,
positionLetters,
flatAffixes,
}: {
wordToGuess: string,
wordToSubmit: string,
incorrectLetter: UsedLetters,
positionLetters: UsedLetters,
flatAffixes: FlatAffixes,
}) => {
if (!wordToSubmit || !wordToSubmit.replaceAll(' ', '')) {
return {
status: AffixStatus.Unknown,
};
}

const uniqueWordLetters = [...(new Set(wordToSubmit.split('')))].filter(letter => letter !== ' ');

const incorrectTyppedLetters = uniqueWordLetters.filter((uniqueLetter) => {
const isIncorrect = incorrectLetter[uniqueLetter] > 0;
if (!isIncorrect) {
return false;
}

const isCorrectSometimes = positionLetters[uniqueLetter] > 0;
if (isCorrectSometimes) {
const occurrencesOfLetterInSubmitWord = getLetterOccuranceInWord(uniqueLetter, wordToSubmit);

return occurrencesOfLetterInSubmitWord > positionLetters[uniqueLetter];
}

return true;
});

const hasIncorrectLetterTyped = incorrectTyppedLetters.length > 0;
if (hasIncorrectLetterTyped) {
return {
status: AffixStatus.Incorrect,
details: incorrectTyppedLetters.join(', '),
};
}

// TODO: add info at the end if no special letter typed
const hasWordToGuessSpecialCharacters = wordToGuess && getHasSpecialCharacters(wordToGuess);
const hasWordToSubmitSpecialCharacters = wordToSubmit && getHasSpecialCharacters(wordToSubmit);
const specialCharacterTypedWhenNotNeeded = !hasWordToGuessSpecialCharacters && hasWordToSubmitSpecialCharacters;
if (specialCharacterTypedWhenNotNeeded) {
return {
status: AffixStatus.Incorrect,
details: [], // TODO: add special
};
}

const uniqueRequiredLetters = Object.keys(positionLetters);
const allKnownLettersAreTyped = uniqueRequiredLetters.every((uniqueLetter) => {
const occurrencesOfLetterInSubmitWord = getLetterOccuranceInWord(uniqueLetter, wordToSubmit);

return occurrencesOfLetterInSubmitWord >= positionLetters[uniqueLetter];
});

if (allKnownLettersAreTyped) {
if (flatAffixes) {
const isWrongStart = !wordToSubmit.startsWith(flatAffixes.start);
if (isWrongStart) {
return {
status: AffixStatus.IncorrectStart,
details: flatAffixes.start,
};
}

if (flatAffixes.notStart.includes(wordToSubmit[0])) {
return {
status: AffixStatus.IncorrectStart,
details: wordToSubmit[0],
};
}

const isWrongEnd = !wordToSubmit.endsWith(flatAffixes.end);
if (isWrongEnd) {
return {
status: AffixStatus.IncorrectEnd,
details: flatAffixes.end,
};
}

if (flatAffixes.notEnd.includes(wordToSubmit[wordToSubmit.length - 1])) {
return {
status: AffixStatus.IncorrectEnd,
details: wordToSubmit[wordToSubmit.length - 1],
};
}

const wrongMiddles = flatAffixes.middle.filter(flatAffix => !wordToSubmit.includes(flatAffix));
const isWrongMiddle = wrongMiddles.length > 0;
if (isWrongMiddle) {
return {
status: AffixStatus.IncorrectMiddle,
details: wrongMiddles.join(', '),
};
}

if (flatAffixes.correctOrders.length > 0) {
const wrongOrders = flatAffixes.correctOrders.filter(order => !getIsTextMatchingOrder(wordToSubmit, order));
const isWrongOrder = wrongOrders.length > 0;
if (isWrongOrder) {
return {
status: AffixStatus.IncorrectOrder,
details: wrongOrders.join(', '),
};
}
}
}

return {
status: AffixStatus.Correct,
};
}

// If not all known letters are typed, we know that the word is incorrect, but we don't display it.
return {
status: AffixStatus.Unknown,
};
};
3 changes: 3 additions & 0 deletions src/store/utils/getLetterOccuranceInWord.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// hello -> 2
// https://stackoverflow.com/a/72347965/6743808 - claims is the fastest
export const getLetterOccuranceInWord = (letter: string, word: string) => word.length - word.replaceAll(letter, '').length;

0 comments on commit 1f63d84

Please sign in to comment.