From 38760693c21f1fd9ce257edf7554927ac42a2898 Mon Sep 17 00:00:00 2001 From: Soup For My Family Date: Wed, 10 Jun 2026 02:52:59 -0600 Subject: [PATCH] Handle duplicate yellows + better rule testing --- src/wordle.zig | 51 ++++++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/src/wordle.zig b/src/wordle.zig index 2eb80ff..901db00 100644 --- a/src/wordle.zig +++ b/src/wordle.zig @@ -1,3 +1,5 @@ +const std = @import("std"); + /// The length of Wordle words. pub const WordLen = 5; @@ -19,8 +21,11 @@ pub 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; + // init clues, defaulting to gray clues + var clues: Clues = @splat(Clue.Gray); + + // track which letters have been used for yellow clues + var duplicates: [WordLen]bool = @splat(false); // compare each letter pairwise for (guess, 0..) |guessLetter, idx| { @@ -30,13 +35,11 @@ pub fn checkGuess(guess: Word, solution: Word) Clues { continue; } - // default to a gray clue - clues[idx] = Clue.Gray; - // if a matching letter in the solution can be found, write yellow - for (solution) |solutionLetter| { - if (guessLetter == solutionLetter) { + for (solution, &duplicates) |solutionLetter, *duplicate| { + if (guessLetter == solutionLetter and !duplicate.*) { clues[idx] = Clue.Yellow; + duplicate.* = true; break; } } @@ -54,30 +57,26 @@ pub fn strToWord(str: WordLiteral) Word { } /// Asserts that two word literals produce the expected clues. -fn expectGuessClues(guess: WordLiteral, solution: WordLiteral, expectClues: WordLiteral) error{Mismatch}!void { +fn expectGuessClues(guess: WordLiteral, solution: WordLiteral, expectClues: WordLiteral) !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, expectCluesWord) |clue, expectedChar| { - // convert character to associated clue variant - const expected = switch (expectedChar) { - ' ' => Clue.Gray, - 'Y' => Clue.Yellow, - 'G' => Clue.Green, - else => unreachable, + // convert the clues to a word + var cluesWord: Word = undefined; + for (clues, &cluesWord) |src, *dst| { + dst.* = switch (src) { + Clue.Gray => ' ', + Clue.Yellow => 'Y', + Clue.Green => 'G', }; - - // if clues don't match, return an error - if (expected != clue) { - return error.Mismatch; - } } + + // test the equality of the strings + try std.testing.expectEqualStrings(&cluesWord, expectClues); } test "full match" { @@ -92,6 +91,10 @@ test "no match" { try expectGuessClues("salet", "fuzzy", " "); } -test "duplicate letters" { - try expectGuessClues("fuzzy", "zesty", " Y "); +test "anagram" { + try expectGuessClues("beats", "abets", "YYYGG"); +} + +test "duplicate letters" { + try expectGuessClues("fuzzy", "zesty", " Y G"); }