Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

finalize game logic #6

Merged
merged 8 commits into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 38 additions & 11 deletions src/Wordle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,18 @@ import {console} from "forge-std/console.sol";
contract Wordle {
using StringUtils for string;

// events
event NoMoreAttempts(string message);
event CorrectGuess(string guess, string message);
event RemainingAttempts(uint256 attemptsLeft, string message);

// declare hidden word variable
string public HIDDEN_WORD;
StructTypes.CharState[] public HIDDEN_WORD_HITMAP;
StructTypes.CharState[] public ALPHABET;
uint256 public ATTEMPTS = 0;
uint256 public ATTEMPTS;

// setup hidden word
// todo: implement obfuscation. would keccak256 be a good approach?
function hideWord(string calldata word) public {
constructor(string memory word) {
if (!word.isASCII()) {
revert("Non-ASCII strings are not supported.");
}
Expand All @@ -25,13 +28,14 @@ contract Wordle {
revert("Word must be 5 characters long.");
}

// generates the hitmap of the word and returns it
HIDDEN_WORD = word;
HIDDEN_WORD_HITMAP = StringUtils.generateHitmap(word);
ALPHABET = StringUtils.generateHitmap("abcdefghijklmnopqrstuvwxyz");
ATTEMPTS = 1;
}

// get methods
// verify if hidden word was setup correctly
// todo: remove once tests are finishied
function getHiddenWord() public view returns (StructTypes.CharState[] memory) {
return HIDDEN_WORD_HITMAP;
}
Expand All @@ -44,16 +48,15 @@ contract Wordle {
return ATTEMPTS;
}

// setup alphabet hitmap
function setupAlphabet() public {
ALPHABET = StringUtils.generateHitmap("abcdefghijklmnopqrstuvwxyz");
}

/*
Processes the guess, comparing it to the hidden word and assessing
and updating the hitmap and alphabet accordingly.
*/
function tryGuess(string calldata guess) public returns (bool) {
if (!guess.isASCII()) {
revert("Non-ASCII strings are not supported.");
}

ATTEMPTS++;
StructTypes.CharState[] memory guessHitmap = StringUtils.generateHitmap(guess);

Expand Down Expand Up @@ -100,4 +103,28 @@ contract Wordle {
// Check for the winning condition after processing all characters.
return StringUtils.isHitmapComplete(HIDDEN_WORD_HITMAP);
}

/*
Main game function that checks if attempts are exhausted
and processes the user's guess accordingly.
New attempts are managed within tryGuess().
*/
function handleAttempt(string calldata guess) public returns (bool) {
// using 1-index for clarity
if (ATTEMPTS >= 7) {
emit NoMoreAttempts("No more attempts remaining.");
return false; // Game over
}

// Perform a new attempt
bool newAttempt = tryGuess(guess);

if (newAttempt) {
emit CorrectGuess(guess, "Well done!");
return true; // Correct guess
} else {
emit RemainingAttempts(7 - ATTEMPTS, "Attempts left."); // Clear message
return false; // Incorrect guess
Comment on lines +126 to +127
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could not replicate this on forge using vm.expectEmit(true, true, true, true) and replicating the message.
Was getting the error that the log was not being emitted, however things were logging correctly. This is the right way to setup emit events, right?

}
}
}
38 changes: 26 additions & 12 deletions test/Wordle.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@ contract WordleTest is Test {
Wordle wordle;

function setUp() public {
wordle = new Wordle();
wordle = new Wordle("BONGO");
}

// test word hiding
function test_hideWord() public {
// correct input
wordle.hideWord("BINGO");
StructTypes.CharState[] memory hitmap = wordle.getHiddenWord();
wordle = new Wordle("BINGO");

// test if hitmap is generated correctly
StructTypes.CharState[] memory hitmap = wordle.getHiddenWord();

// check if letters are correctly mapped
assertEq(hitmap[0].char, "b");
Expand All @@ -37,18 +37,18 @@ contract WordleTest is Test {

// non-ascii input
vm.expectRevert("Non-ASCII strings are not supported.");
wordle.hideWord(unicode"👋");
wordle = new Wordle(unicode"👋");

// wrong size
vm.expectRevert("Word must be 5 characters long.");
wordle.hideWord("Banana");
wordle = new Wordle("Banana");
vm.expectRevert("Word must be 5 characters long.");
wordle.hideWord("Bun");
wordle = new Wordle("Bun");
}

// test alphabet initialization
function test_alphabet() public {
wordle.setupAlphabet();
wordle = new Wordle("HELLO");
StructTypes.CharState[] memory alphabet = wordle.getAlphabet();
assertEq(alphabet[0].char, "a");
assertEq(alphabet[1].char, "b");
Expand Down Expand Up @@ -84,17 +84,14 @@ contract WordleTest is Test {

// test guess mechanic
function test_tryGuess() public {
wordle.setupAlphabet();

// setup hidden word
wordle.hideWord("BONGO");
wordle = new Wordle("BONGO");

// test wrong guess
assertFalse(wordle.tryGuess("olive"));

// test attempt increment
uint256 attempts = wordle.getAttempts();
assertEq(attempts, 1);
assertEq(attempts, 2);

// test hitmap updates
StructTypes.CharState[] memory hitmap = wordle.getHiddenWord();
Expand All @@ -110,4 +107,21 @@ contract WordleTest is Test {
// test correct guess
assertTrue(wordle.tryGuess("BONGO"));
}

// test attempt handling
function test_handleAttempt() public {
wordle = new Wordle("BINGO");
StructTypes.CharState[] memory hitmap = wordle.getHiddenWord();

// test if attempts and messages are emited correctly
assertFalse(wordle.handleAttempt("olive"));

// test attempt limit reached
assertFalse(wordle.handleAttempt("oliva"));
assertFalse(wordle.handleAttempt("super"));
assertFalse(wordle.handleAttempt("alive"));
assertFalse(wordle.handleAttempt("bongo"));
assertFalse(wordle.handleAttempt("pengu"));
assertFalse(wordle.handleAttempt("bingo"));
}
}