Zack Buhman e15f0a9eaf wordle: minimally working game
A few "minor" features are missing, including showing the correct word if you
get it wrong.
2023-05-10 10:15:48 -07:00

149 lines
2.9 KiB
C++

#include <stdint.h>
#include <stdbool.h>
#include "wordle.hpp"
#include "word_list.hpp"
namespace wordle {
void init_screen(struct screen& s, uint32_t rand)
{
s.edit.row = 0;
s.edit.index = 0;
for (uint32_t j = 0; j < word_length; j++) {
for (uint32_t i = 0; i < guesses; i++) {
s.rows[i].letters[j] = ' ';
s.rows[i].clues[j] = clue::none;
}
}
for (uint32_t k = 0; k < 26; k++) {
s.clues[k] = clue::none;
}
constexpr uint32_t answer_length = (sizeof (answers)) / (sizeof (uint32_t));
s.word_ix = answers[rand % answer_length];
}
bool type_letter(struct screen& s, const uint8_t letter)
{
if (s.edit.row >= guesses)
return false;
uint8_t l;
if (s.edit.index >= word_length)
return false;
if (letter >= 'a' && letter <= 'z') {
l = letter - ('a' - 'A'); // upcase
} else if (letter >= 'A' && letter <= 'Z') {
l = letter;
} else {
return false;
}
struct row& r = s.rows[s.edit.row];
r.letters[s.edit.index++] = l;
return true;
}
bool backspace(struct screen& s)
{
if (s.edit.row >= guesses)
return false;
if (s.edit.index <= 0)
return false;
struct row& r = s.rows[s.edit.row];
r.letters[--s.edit.index] = ' ';
return true;
}
static inline int32_t word_in_list(const uint8_t * word)
{
constexpr uint32_t word_list_items = (sizeof word_list) / (word_length);
for (uint32_t i = 0; i < word_list_items; i++) {
for (uint32_t j = 0; j < word_length; j++) {
if (word_list[i][j] != word[j])
goto next_word;
}
// word_length loop exited and all letters matched
return true;
next_word:
continue;
}
// exhausted word list; nothing matches
return false;
}
constexpr inline enum clue next_clue(enum clue a, enum clue b)
{
if (a == clue::exact || b == clue::exact)
return clue::exact;
if (a == clue::present || b == clue::present)
return clue::present;
if (a == clue::absent || b == clue::absent)
return clue::absent;
return clue::none;
}
static inline void update_clues(enum clue * clues, struct row &r, const uint8_t * word)
{
for (uint32_t i = 0; i < word_length; i++) {
enum clue &c = r.clues[i];
c = clue::absent;
const uint8_t l = r.letters[i];
if (l == word[i]) {
c = clue::exact;
} else {
// also check for position errors
for (uint32_t j = 0; j < word_length; j++) {
if (word[j] == l) {
c = clue::present;
break;
}
}
}
int32_t l_ix = static_cast<int32_t>(l) - static_cast<int32_t>('A');
if (l_ix >= 0 && l_ix < 26) {
// update global clues
clues[l_ix] = next_clue(clues[l_ix], c);
}
}
}
bool confirm_word(struct screen& s)
{
if (s.edit.row >= guesses)
return false;
if (s.edit.index < word_length)
return false;
if (!(word_in_list(s.rows[s.edit.row].letters)))
return false;
update_clues(s.clues, s.rows[s.edit.row], word_list[s.word_ix]);
s.edit.row++;
s.edit.index = 0;
return true;
}
}