Basic Wordle rules
This commit is contained in:
97
src/wordle.zig
Normal file
97
src/wordle.zig
Normal file
@@ -0,0 +1,97 @@
|
||||
/// The length of Wordle words.
|
||||
const WordLen = 5;
|
||||
|
||||
/// A single Wordle word (ASCII).
|
||||
const Word = [WordLen]u8;
|
||||
|
||||
/// The type of string literals representing words.
|
||||
const WordLiteral = *const [WordLen:0]u8;
|
||||
|
||||
/// A clue for a spot given a guess.
|
||||
const Clue = enum {
|
||||
Gray,
|
||||
Yellow,
|
||||
Green,
|
||||
};
|
||||
|
||||
/// The list of clues for a full guess.
|
||||
const Clues = [WordLen]Clue;
|
||||
|
||||
/// Guesses a word given a solution and returns the clues.
|
||||
pub fn checkGuess(guess: Word, solution: Word) Clues {
|
||||
// init clues
|
||||
var clues: Clues = undefined;
|
||||
|
||||
// compare each letter pairwise
|
||||
for (guess, 0..WordLen) |guessLetter, idx| {
|
||||
// if letters match, the clue is green
|
||||
if (guessLetter == solution[idx]) {
|
||||
clues[idx] = Clue.Green;
|
||||
continue;
|
||||
}
|
||||
|
||||
// default to a gray clue
|
||||
clues[idx] = Clue.Gray;
|
||||
|
||||
// if a matching letter in the solution can be found, write yellow
|
||||
for (solution, 0..WordLen) |solutionLetter, _| {
|
||||
if (guessLetter == solutionLetter) {
|
||||
clues[idx] = Clue.Yellow;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// return completed clues
|
||||
return clues;
|
||||
}
|
||||
|
||||
/// Converts a fixed-length string literal into a word.
|
||||
fn strToWord(str: WordLiteral) Word {
|
||||
var buffer: Word = undefined;
|
||||
@memcpy(&buffer, str);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/// Asserts that two word literals produce the expected clues.
|
||||
fn expectGuessClues(guess: WordLiteral, solution: WordLiteral, expectClues: WordLiteral) error{Mismatch}!void {
|
||||
// convert literals to the non-null word type
|
||||
const guessWord = strToWord(guess);
|
||||
const solutionWord = strToWord(solution);
|
||||
const expectCluesWord = strToWord(expectClues);
|
||||
|
||||
// check the guess and produce clues
|
||||
const clues = checkGuess(guessWord, solutionWord);
|
||||
|
||||
// confirm that the expected clues match the clues
|
||||
for (clues, 0..) |clue, idx| {
|
||||
// convert character to associated clue variant
|
||||
const expected = switch (expectCluesWord[idx]) {
|
||||
' ' => Clue.Gray,
|
||||
'Y' => Clue.Yellow,
|
||||
'G' => Clue.Green,
|
||||
else => unreachable,
|
||||
};
|
||||
|
||||
// if clues don't match, return an error
|
||||
if (expected != clue) {
|
||||
return error.Mismatch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test "full match" {
|
||||
try expectGuessClues("crane", "crane", "GGGGG");
|
||||
}
|
||||
|
||||
test "one off" {
|
||||
try expectGuessClues("crane", "crank", "GGGG ");
|
||||
}
|
||||
|
||||
test "no match" {
|
||||
try expectGuessClues("salet", "fuzzy", " ");
|
||||
}
|
||||
|
||||
test "duplicate letters" {
|
||||
try expectGuessClues("fuzzy", "zesty", " Y ");
|
||||
}
|
||||
Reference in New Issue
Block a user