2022-01-22 21:43:34 +00:00
|
|
|
import { Difficulty, englishNumbers, ordinal } from "./util";
|
2022-01-17 22:25:44 +00:00
|
|
|
|
2022-01-01 02:04:48 +00:00
|
|
|
export enum Clue {
|
|
|
|
Absent,
|
|
|
|
Elsewhere,
|
|
|
|
Correct,
|
|
|
|
}
|
|
|
|
|
|
|
|
export interface CluedLetter {
|
|
|
|
clue?: Clue;
|
|
|
|
letter: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function clue(word: string, target: string): CluedLetter[] {
|
2022-01-01 18:35:03 +00:00
|
|
|
let elusive: string[] = [];
|
|
|
|
target.split("").forEach((letter, i) => {
|
2022-01-01 02:04:48 +00:00
|
|
|
if (word[i] !== letter) {
|
2022-01-01 18:35:03 +00:00
|
|
|
elusive.push(letter);
|
2022-01-01 02:04:48 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
return word.split("").map((letter, i) => {
|
|
|
|
let j: number;
|
|
|
|
if (target[i] === letter) {
|
|
|
|
return { clue: Clue.Correct, letter };
|
2022-01-01 18:35:03 +00:00
|
|
|
} else if ((j = elusive.indexOf(letter)) > -1) {
|
|
|
|
// "use it up" so we don't clue at it twice
|
|
|
|
elusive[j] = "";
|
2022-01-01 02:04:48 +00:00
|
|
|
return { clue: Clue.Elsewhere, letter };
|
|
|
|
} else {
|
|
|
|
return { clue: Clue.Absent, letter };
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
export function clueClass(clue: Clue): string {
|
|
|
|
if (clue === Clue.Absent) {
|
|
|
|
return "letter-absent";
|
|
|
|
} else if (clue === Clue.Elsewhere) {
|
|
|
|
return "letter-elsewhere";
|
|
|
|
} else {
|
|
|
|
return "letter-correct";
|
|
|
|
}
|
|
|
|
}
|
2022-01-13 23:16:27 +00:00
|
|
|
|
|
|
|
export function clueWord(clue: Clue): string {
|
|
|
|
if (clue === Clue.Absent) {
|
|
|
|
return "no";
|
|
|
|
} else if (clue === Clue.Elsewhere) {
|
2022-01-14 16:19:42 +00:00
|
|
|
return "elsewhere";
|
2022-01-13 23:16:27 +00:00
|
|
|
} else {
|
|
|
|
return "correct";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export function describeClue(clue: CluedLetter[]): string {
|
|
|
|
return clue
|
|
|
|
.map(({ letter, clue }) => letter.toUpperCase() + " " + clueWord(clue!))
|
|
|
|
.join(", ");
|
|
|
|
}
|
2022-01-17 22:25:44 +00:00
|
|
|
|
|
|
|
export function violation(
|
2022-01-22 16:46:14 +00:00
|
|
|
difficulty: Difficulty,
|
2022-01-17 22:25:44 +00:00
|
|
|
clues: CluedLetter[],
|
|
|
|
guess: string
|
|
|
|
): string | undefined {
|
2022-01-22 16:46:14 +00:00
|
|
|
if (difficulty === Difficulty.Normal) {
|
|
|
|
return undefined;
|
|
|
|
}
|
2022-01-17 22:25:44 +00:00
|
|
|
let i = 0;
|
|
|
|
for (const { letter, clue } of clues) {
|
2022-01-22 16:46:14 +00:00
|
|
|
const upper = letter.toUpperCase();
|
|
|
|
const nth = ordinal(i + 1);
|
2022-01-23 11:35:41 +00:00
|
|
|
if (clue === Clue.Correct) {
|
2022-01-22 16:46:14 +00:00
|
|
|
if (guess[i] !== letter) {
|
|
|
|
return nth + " letter must be " + upper;
|
|
|
|
}
|
2022-01-17 22:25:44 +00:00
|
|
|
} else if (clue === Clue.Elsewhere) {
|
2022-01-22 16:46:14 +00:00
|
|
|
if (!guess.includes(letter)) {
|
|
|
|
return "Guess must contain " + upper;
|
|
|
|
}
|
2022-01-17 22:25:44 +00:00
|
|
|
}
|
2022-01-23 11:35:41 +00:00
|
|
|
if (difficulty === Difficulty.UltraHard) {
|
2022-01-24 11:16:07 +00:00
|
|
|
if (clue !== Clue.Correct && guess[i] === letter) {
|
|
|
|
return nth + " letter can't be " + upper;
|
|
|
|
}
|
2022-01-23 11:35:41 +00:00
|
|
|
const clueCount = clues.filter(
|
|
|
|
(c) => c.letter === letter && c.clue !== Clue.Absent
|
|
|
|
).length;
|
|
|
|
const guessCount = guess.split(letter).length - 1;
|
|
|
|
const hasAbsent = clues.some(
|
|
|
|
(c) => c.letter === letter && c.clue === Clue.Absent
|
|
|
|
);
|
|
|
|
const amount = englishNumbers[clueCount];
|
|
|
|
const s = clueCount !== 1 ? "s" : "";
|
|
|
|
if (hasAbsent) {
|
|
|
|
if (guessCount !== clueCount) {
|
|
|
|
if (clueCount === 0) {
|
|
|
|
return `Guess can't contain ${upper}`;
|
|
|
|
} else {
|
|
|
|
return `Guess must contain exactly ${amount} ${upper}${s}`;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (guessCount < clueCount) {
|
|
|
|
return `Guess must contain at least ${amount} ${upper}${s}`;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-01-17 22:25:44 +00:00
|
|
|
++i;
|
|
|
|
}
|
|
|
|
return undefined;
|
|
|
|
}
|