Skip to content

Commit

Permalink
possible-answer-counter: generalized
Browse files Browse the repository at this point in the history
  • Loading branch information
Ryan Carpenter committed Jan 16, 2022
1 parent 7ea3a2b commit 12f43ba
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 82 deletions.
144 changes: 62 additions & 82 deletions src/Game.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { useEffect, useState } from "react";
import { useEffect, useState, ChangeEvent } from "react";
import { Row, RowState } from "./Row";
import dictionary from "./dictionary.json";
import { Clue, clue } from "./clue";
import { Keyboard } from "./Keyboard";
import targetList from "./targets.json";
import { dictionarySet, pick, resetRng, seed } from "./util";
import { pick, resetRng, seed, initExclusions } from "./util";

enum GameState {
Playing,
Expand All @@ -30,24 +30,18 @@ function Game(props: GameProps) {
const [currentGuess, setCurrentGuess] = useState<string>("");
const [wordLength, setWordLength] = useState(5);
const [hint, setHint] = useState<string>(
`${targets.length.toLocaleString()} possibilities`
`${targets
.filter(({ length }) => length === wordLength)
.length.toLocaleString()} possibilities`
);
const [target, setTarget] = useState(() => {
resetRng();
return randomTarget(wordLength);
});
const [gameNumber, setGameNumber] = useState(1);
const [exclusions, setExclusions] = useState<
Record<string | number, string[]>
>({
found: ["", "", "", "", ""],
nowhere: [],
0: [],
1: [],
2: [],
3: [],
4: [],
});
Record<"found" | "nowhere" | number, string[]>
>(initExclusions(wordLength));

const startNextGame = () => {
setTarget(randomTarget(wordLength));
Expand All @@ -56,6 +50,7 @@ function Game(props: GameProps) {
setHint("");
setGameState(GameState.Playing);
setGameNumber((x) => x + 1);
setExclusions(initExclusions(wordLength));
};

const onKey = (key: string) => {
Expand All @@ -68,10 +63,8 @@ function Game(props: GameProps) {
if (guesses.length === props.maxGuesses) return;
if (/^[a-z]$/.test(key)) {
setCurrentGuess((guess) => (guess + key).slice(0, wordLength));
setHint("");
} else if (key === "Backspace") {
setCurrentGuess((guess) => guess.slice(0, -1));
setHint("");
} else if (key === "Enter") {
if (currentGuess.length !== wordLength) {
setHint("Too short");
Expand Down Expand Up @@ -104,33 +97,22 @@ function Game(props: GameProps) {
)
.map(({ letter }) => letter);

setExclusions({
found: currentClue.reduce((agg, cur, index) => {
if (cur.clue === 2) agg.splice(index, 1, cur.letter);
return agg;
}, exclusions.found),
nowhere: [...exclusions.nowhere, ...notFound],
0:
currentClue[0].clue === 1
? [...exclusions[0], currentClue[0].letter]
: exclusions[0],
1:
currentClue[1].clue === 1
? [...exclusions[1], currentClue[1].letter]
: exclusions[1],
2:
currentClue[2].clue === 1
? [...exclusions[2], currentClue[2].letter]
: exclusions[2],
3:
currentClue[3].clue === 1
? [...exclusions[3], currentClue[3].letter]
: exclusions[3],
4:
currentClue[4].clue === 1
? [...exclusions[4], currentClue[4].letter]
: exclusions[4],
});
setExclusions(
currentClue.reduce(
(agg, { letter, clue }, index) => ({
...agg,
[index]:
clue === 1 ? [...exclusions[index], letter] : exclusions[index],
}),
{
found: currentClue.reduce((agg, cur, index) => {
if (cur.clue === 2) agg.splice(index, 1, cur.letter);
return agg;
}, exclusions.found),
nowhere: [...exclusions.nowhere, ...notFound],
}
)
);
}
}
};
Expand All @@ -141,37 +123,32 @@ function Game(props: GameProps) {

useEffect(() => {
if (exclusions.nowhere.length === 0) return;
const nowherePattern = new RegExp(`^[^${exclusions.nowhere.join("")}]+$`);
const notHerePattern = new RegExp(
`^${
exclusions.found[0] || exclusions[0].length
? `[^${exclusions[0].join("")}]`
: "."
}${
exclusions.found[1] || exclusions[1].length
? `[^${exclusions[1].join("")}]`
: "."
}${
exclusions.found[2] || exclusions[2].length
? `[^${exclusions[2].join("")}]`
: "."
}${
exclusions.found[3] || exclusions[3].length
? `[^${exclusions[3].join("")}]`
: "."
}${
exclusions.found[4] || exclusions[4].length
? `[^${exclusions[4].join("")}]`
: "."
}$`
);

console.log(exclusions, nowherePattern, notHerePattern);
const { found, nowhere, ...rest } = exclusions;
const nowherePattern = `(?=^[^${exclusions.nowhere.join("")}]+$)`;
const somewherePattern = Object.values(rest)
.reduce((agg: string[], cur: string[]) => [...agg, ...cur], [])
.filter(
(letter: string, index: number, array: string[]) =>
array.indexOf(letter) === index && !found.includes(letter)
)
.map((letter: string) => `(?=.*${letter})`)
.join("");
const byPositionPattern = `(?=^${exclusions.found
.map((foundLetter, index) => {
return (
foundLetter ||
(exclusions[index].length ? `[^${exclusions[index].join("")}]` : ".")
);
})
.join("")}$)`;

const possibilityCount = targets.filter(
(word) => nowherePattern.test(word) && notHerePattern.test(word)
).length;
setHint(`${possibilityCount.toLocaleString()} possibilities`);
const re = new RegExp(
[somewherePattern, nowherePattern, byPositionPattern].join("")
);
const possibilities = targets.filter((word) => re.test(word));
setHint(`${possibilities.length.toLocaleString()} possibilities`);
console.log({ exclusions, possibilities });
}, [exclusions]);

useEffect(() => {
Expand Down Expand Up @@ -212,6 +189,19 @@ function Game(props: GameProps) {
);
});

const handleWordLengthChange = (e: ChangeEvent<HTMLInputElement>) => {
const length = Number(e.target.value);
resetRng();
setGameNumber(1);
setGameState(GameState.Playing);
setGuesses([]);
setTarget(randomTarget(length));
setWordLength(length);
setHint(`${length} letters`);
setExclusions(initExclusions(length));
(document.activeElement as HTMLElement)?.blur();
};

return (
<div className="Game" style={{ display: props.hidden ? "none" : "block" }}>
<div className="Game-options">
Expand All @@ -226,17 +216,7 @@ function Game(props: GameProps) {
(guesses.length > 0 || currentGuess !== "")
}
value={wordLength}
onChange={(e) => {
const length = Number(e.target.value);
resetRng();
setGameNumber(1);
setGameState(GameState.Playing);
setGuesses([]);
setTarget(randomTarget(length));
setWordLength(length);
setHint(`${length} letters`);
(document.activeElement as HTMLElement)?.blur();
}}
onChange={handleWordLengthChange}
></input>
<button
style={{ flex: "0" }}
Expand Down
11 changes: 11 additions & 0 deletions src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,14 @@ export function resetRng(): void {
export function pick<T>(array: Array<T>): T {
return array[Math.floor(array.length * random())];
}

export function initExclusions(
wordLength: number
): Record<"found" | "nowhere" | number, string[]> {
return new Array(wordLength)
.fill([] as string[])
.reduce((agg, value, index) => ({ ...agg, [index]: value }), {
found: new Array(wordLength).fill(""),
nowhere: [],
});
}

0 comments on commit 12f43ba

Please sign in to comment.