wordle: minimally working game
A few "minor" features are missing, including showing the correct word if you get it wrong.
This commit is contained in:
parent
cfad16c514
commit
e15f0a9eaf
1
.gitignore
vendored
1
.gitignore
vendored
@ -11,3 +11,4 @@ res/mai.data
|
|||||||
tools/ttf-convert
|
tools/ttf-convert
|
||||||
common/keyboard.cpp
|
common/keyboard.cpp
|
||||||
common/keyboard.hpp
|
common/keyboard.hpp
|
||||||
|
wordle/word_list.hpp
|
7
Makefile
7
Makefile
@ -62,6 +62,11 @@ smpc/input_keyboard.elf: smpc/input_keyboard.o sh/lib1funcs.o res/dejavusansmono
|
|||||||
|
|
||||||
wordle/main_saturn.o: common/keyboard.hpp
|
wordle/main_saturn.o: common/keyboard.hpp
|
||||||
|
|
||||||
|
wordle/word_list.hpp: wordle/word_list.csv wordle/word_list.py
|
||||||
|
python wordle/word_list.py > $@
|
||||||
|
|
||||||
|
wordle/wordle.o: wordle/word_list.hpp
|
||||||
|
|
||||||
wordle/wordle.elf: wordle/main_saturn.o wordle/wordle.o wordle/draw.o sh/lib1funcs.o res/dejavusansmono.font.bin.o common/keyboard.o common/draw_font.o common/palette.o
|
wordle/wordle.elf: wordle/main_saturn.o wordle/wordle.o wordle/draw.o sh/lib1funcs.o res/dejavusansmono.font.bin.o common/keyboard.o common/draw_font.o common/palette.o
|
||||||
|
|
||||||
|
|
||||||
@ -74,4 +79,4 @@ clean-sh:
|
|||||||
-regextype posix-egrep \
|
-regextype posix-egrep \
|
||||||
-regex '.*\.(iso|o|bin|elf|cue)$$' \
|
-regex '.*\.(iso|o|bin|elf|cue)$$' \
|
||||||
-exec rm {} \;
|
-exec rm {} \;
|
||||||
rm -f common/keyboard.cpp common/keyboard.hpp
|
rm -f common/keyboard.cpp common/keyboard.hpp wordle/word_list.hpp
|
||||||
|
@ -56,7 +56,8 @@ uint32_t single_character_centered(state const& s,
|
|||||||
const int32_t x1, // in 26.6 fixed point
|
const int32_t x1, // in 26.6 fixed point
|
||||||
const int32_t y1,
|
const int32_t y1,
|
||||||
const int32_t x2,
|
const int32_t x2,
|
||||||
const int32_t y2)
|
const int32_t y2,
|
||||||
|
uint16_t color)
|
||||||
{
|
{
|
||||||
//assert(c <= s.char_code_offset);
|
//assert(c <= s.char_code_offset);
|
||||||
const T c_offset = c - s._font->char_code_offset;
|
const T c_offset = c - s._font->char_code_offset;
|
||||||
@ -64,12 +65,10 @@ uint32_t single_character_centered(state const& s,
|
|||||||
glyph_bitmap const& bitmap = s._glyphs[c_offset].bitmap;
|
glyph_bitmap const& bitmap = s._glyphs[c_offset].bitmap;
|
||||||
glyph_metrics const& metrics = s._glyphs[c_offset].metrics;
|
glyph_metrics const& metrics = s._glyphs[c_offset].metrics;
|
||||||
|
|
||||||
constexpr uint16_t magenta = (0x31 << 10) | (0x31 << 0);
|
|
||||||
|
|
||||||
vdp1.vram.cmd[cmd_ix].CTRL = CTRL__JP__JUMP_NEXT | CTRL__COMM__POLYLINE;
|
vdp1.vram.cmd[cmd_ix].CTRL = CTRL__JP__JUMP_NEXT | CTRL__COMM__POLYLINE;
|
||||||
vdp1.vram.cmd[cmd_ix].LINK = 0;
|
vdp1.vram.cmd[cmd_ix].LINK = 0;
|
||||||
vdp1.vram.cmd[cmd_ix].PMOD = PMOD__ECD | PMOD__SPD;
|
vdp1.vram.cmd[cmd_ix].PMOD = PMOD__ECD | PMOD__SPD;
|
||||||
vdp1.vram.cmd[cmd_ix].COLR = COLR__RGB | magenta; // non-palettized (rgb15) color data
|
vdp1.vram.cmd[cmd_ix].COLR = COLR__RGB | color; // non-palettized (rgb15) color data
|
||||||
vdp1.vram.cmd[cmd_ix].XA = x1;
|
vdp1.vram.cmd[cmd_ix].XA = x1;
|
||||||
vdp1.vram.cmd[cmd_ix].YA = y1;
|
vdp1.vram.cmd[cmd_ix].YA = y1;
|
||||||
vdp1.vram.cmd[cmd_ix].XB = x2;
|
vdp1.vram.cmd[cmd_ix].XB = x2;
|
||||||
|
@ -47,7 +47,7 @@ void main()
|
|||||||
vdp1.vram.cmd[1].XA = 0;
|
vdp1.vram.cmd[1].XA = 0;
|
||||||
vdp1.vram.cmd[1].YA = 0;
|
vdp1.vram.cmd[1].YA = 0;
|
||||||
|
|
||||||
constexpr uint16_t magenta = (0x31 << 10) | (0x31 << 0);
|
constexpr uint16_t magenta = (31 << 10) | (31 << 0);
|
||||||
vdp1.vram.cmd[2].CTRL = CTRL__JP__JUMP_NEXT | CTRL__COMM__POLYGON;
|
vdp1.vram.cmd[2].CTRL = CTRL__JP__JUMP_NEXT | CTRL__COMM__POLYGON;
|
||||||
vdp1.vram.cmd[2].LINK = 0;
|
vdp1.vram.cmd[2].LINK = 0;
|
||||||
// "Set [ECD] to '1' for polygons, polylines, and lines"
|
// "Set [ECD] to '1' for polygons, polylines, and lines"
|
||||||
|
@ -13,10 +13,10 @@ const static uint8_t layout[3][10] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
void keyboard(struct screen const& s, void (*draw_char)(uint8_t, int32_t, int32_t, int32_t, int32_t))
|
void keyboard(struct screen const& s, void (*draw_char)(uint8_t, int32_t, int32_t, int32_t, int32_t, enum clue))
|
||||||
{
|
{
|
||||||
constexpr int32_t origin_x[3] = {46, 57, 69};
|
constexpr int32_t origin_x[3] = {46, 57, 69};
|
||||||
constexpr int32_t origin_y = 170;
|
constexpr int32_t origin_y = 160;
|
||||||
constexpr uint32_t rows = 3;
|
constexpr uint32_t rows = 3;
|
||||||
constexpr uint32_t cols[3] = {10, 9, 7};
|
constexpr uint32_t cols[3] = {10, 9, 7};
|
||||||
|
|
||||||
@ -29,19 +29,20 @@ void keyboard(struct screen const& s, void (*draw_char)(uint8_t, int32_t, int32_
|
|||||||
int32_t x2 = x1 + box_dim;
|
int32_t x2 = x1 + box_dim;
|
||||||
int32_t y2 = y1 + box_dim;
|
int32_t y2 = y1 + box_dim;
|
||||||
|
|
||||||
draw_char(l, x1, y1, x2, y2);
|
int32_t l_ix = static_cast<int32_t>(l) - static_cast<int32_t>('A');
|
||||||
|
draw_char(l, x1, y1, x2, y2, s.clues[l_ix]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void guesses(struct screen const& s, void (*draw_char)(uint8_t, int32_t, int32_t, int32_t, int32_t))
|
void guesses(struct screen const& s, void (*draw_char)(uint8_t, int32_t, int32_t, int32_t, int32_t, enum clue))
|
||||||
{
|
{
|
||||||
// first row is at (104,23).
|
// first row is at (104,23).
|
||||||
// midpoint is +(10,10)
|
// midpoint is +(10,10)
|
||||||
// grid is +(13,13)
|
// grid is +(13,13)
|
||||||
|
|
||||||
constexpr int32_t origin_x = 103;
|
constexpr int32_t origin_x = 103;
|
||||||
constexpr int32_t origin_y = 17;
|
constexpr int32_t origin_y = 12;
|
||||||
|
|
||||||
for (uint32_t row = 0; row < wordle::guesses; row++) {
|
for (uint32_t row = 0; row < wordle::guesses; row++) {
|
||||||
|
|
||||||
@ -55,7 +56,7 @@ void guesses(struct screen const& s, void (*draw_char)(uint8_t, int32_t, int32_t
|
|||||||
int32_t x2 = x1 + box_dim;
|
int32_t x2 = x1 + box_dim;
|
||||||
int32_t y2 = y1 + box_dim;
|
int32_t y2 = y1 + box_dim;
|
||||||
|
|
||||||
draw_char(l, x1, y1, x2, y2);
|
draw_char(l, x1, y1, x2, y2, r.clues[col]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
namespace wordle {
|
namespace wordle {
|
||||||
namespace draw {
|
namespace draw {
|
||||||
void keyboard(struct screen const& s, void (*draw_char)(uint8_t, int32_t, int32_t, int32_t, int32_t));
|
void keyboard(struct screen const& s, void (*draw_char)(uint8_t, int32_t, int32_t, int32_t, int32_t, enum clue));
|
||||||
void guesses(struct screen const& s, void (*draw_char)(uint8_t, int32_t, int32_t, int32_t, int32_t));
|
void guesses(struct screen const& s, void (*draw_char)(uint8_t, int32_t, int32_t, int32_t, int32_t, enum clue));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,23 @@ struct intback_state {
|
|||||||
static intback_state intback;
|
static intback_state intback;
|
||||||
static int oreg_ix;
|
static int oreg_ix;
|
||||||
|
|
||||||
|
|
||||||
|
struct xorshift32_state {
|
||||||
|
uint32_t a;
|
||||||
|
};
|
||||||
|
|
||||||
|
uint32_t xorshift32(struct xorshift32_state *state)
|
||||||
|
{
|
||||||
|
uint32_t x = state->a;
|
||||||
|
x ^= x << 13;
|
||||||
|
x ^= x >> 17;
|
||||||
|
x ^= x << 5;
|
||||||
|
return state->a = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static xorshift32_state random_state = { 0x12345678 };
|
||||||
|
static uint32_t frame_count = 0;
|
||||||
|
|
||||||
void smpc_int(void) __attribute__ ((interrupt_handler));
|
void smpc_int(void) __attribute__ ((interrupt_handler));
|
||||||
void smpc_int(void) {
|
void smpc_int(void) {
|
||||||
scu.reg.IST &= ~(IST__SMPC);
|
scu.reg.IST &= ~(IST__SMPC);
|
||||||
@ -71,6 +88,7 @@ void smpc_int(void) {
|
|||||||
- up to 2 controllers may be connected
|
- up to 2 controllers may be connected
|
||||||
- multitaps are not parsed correctly
|
- multitaps are not parsed correctly
|
||||||
*/
|
*/
|
||||||
|
|
||||||
while (oreg_ix < 31) {
|
while (oreg_ix < 31) {
|
||||||
reg8 const& oreg = smpc.reg.oreg[oreg_ix++];
|
reg8 const& oreg = smpc.reg.oreg[oreg_ix++];
|
||||||
switch (intback.fsm++) {
|
switch (intback.fsm++) {
|
||||||
@ -103,7 +121,20 @@ void smpc_int(void) {
|
|||||||
if (kbd_bits & 0b1000) { // Make
|
if (kbd_bits & 0b1000) { // Make
|
||||||
enum keysym k = scancode_to_keysym(keysym);
|
enum keysym k = scancode_to_keysym(keysym);
|
||||||
char16_t c = keysym_to_char16(k);
|
char16_t c = keysym_to_char16(k);
|
||||||
(void)c;
|
if (k != keysym::UNKNOWN) {
|
||||||
|
if (c >= 'a' && c <= 'z') {
|
||||||
|
// uppercase
|
||||||
|
wordle::type_letter(wordle_state, c);
|
||||||
|
} else if (k == keysym::ENTER) {
|
||||||
|
wordle::confirm_word(wordle_state);
|
||||||
|
} else if (k == keysym::BACKSPACE) {
|
||||||
|
wordle::backspace(wordle_state);
|
||||||
|
} else if (k == keysym::ESC) {
|
||||||
|
random_state.a += frame_count;
|
||||||
|
uint32_t rand = xorshift32(&random_state);
|
||||||
|
wordle::init_screen(wordle_state, rand);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else if (kbd_bits & 0b0001) { // Break
|
} else if (kbd_bits & 0b0001) { // Break
|
||||||
|
|
||||||
@ -135,16 +166,28 @@ void smpc_int(void) {
|
|||||||
|
|
||||||
// rendering
|
// rendering
|
||||||
|
|
||||||
void draw_char(uint8_t c, int32_t x1, int32_t y1, int32_t x2, int32_t y2)
|
inline constexpr uint16_t clue_color(enum wordle::clue c)
|
||||||
|
{
|
||||||
|
switch (c) {
|
||||||
|
default:
|
||||||
|
case wordle::clue::exact: return ( 0 << 10) | (31 << 5) | ( 0 << 0);
|
||||||
|
case wordle::clue::present: return ( 7 << 10) | (19 << 5) | (22 << 0);
|
||||||
|
case wordle::clue::absent: return ( 4 << 10) | ( 4 << 5) | ( 4 << 0);
|
||||||
|
case wordle::clue::none: return (14 << 10) | (14 << 5) | (14 << 0);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_char(uint8_t l, int32_t x1, int32_t y1, int32_t x2, int32_t y2, enum wordle::clue c)
|
||||||
{
|
{
|
||||||
draw_state.cmd_ix =
|
draw_state.cmd_ix =
|
||||||
draw_font::single_character_centered(draw_state.font,
|
draw_font::single_character_centered(draw_state.font,
|
||||||
draw_state.cmd_ix,
|
draw_state.cmd_ix,
|
||||||
c,
|
l,
|
||||||
x1,
|
x1,
|
||||||
y1,
|
y1,
|
||||||
x2,
|
x2,
|
||||||
y2);
|
y2,
|
||||||
|
clue_color(c));
|
||||||
}
|
}
|
||||||
|
|
||||||
void render()
|
void render()
|
||||||
@ -162,6 +205,8 @@ void v_blank_in_int() {
|
|||||||
scu.reg.IST &= ~(IST__V_BLANK_IN);
|
scu.reg.IST &= ~(IST__V_BLANK_IN);
|
||||||
scu.reg.IMS = ~(IMS__SMPC | IMS__V_BLANK_IN);
|
scu.reg.IMS = ~(IMS__SMPC | IMS__V_BLANK_IN);
|
||||||
|
|
||||||
|
frame_count++;
|
||||||
|
|
||||||
sh2.reg.FRC.H = 0;
|
sh2.reg.FRC.H = 0;
|
||||||
sh2.reg.FRC.L = 0;
|
sh2.reg.FRC.L = 0;
|
||||||
sh2.reg.FTCSR = 0; // clear flags
|
sh2.reg.FTCSR = 0; // clear flags
|
||||||
@ -219,8 +264,8 @@ void main()
|
|||||||
v_blank_in();
|
v_blank_in();
|
||||||
|
|
||||||
// wordle init
|
// wordle init
|
||||||
const uint8_t word[] = "67890";
|
const uint8_t word_ix = 6;
|
||||||
wordle::init_screen(wordle_state, word);
|
wordle::init_screen(wordle_state, word_ix);
|
||||||
// end wordle init
|
// end wordle init
|
||||||
|
|
||||||
// DISP: Please make sure to change this bit from 0 to 1 during V blank.
|
// DISP: Please make sure to change this bit from 0 to 1 during V blank.
|
||||||
|
12972
wordle/word_list.csv
Normal file
12972
wordle/word_list.csv
Normal file
File diff suppressed because it is too large
Load Diff
41
wordle/word_list.py
Normal file
41
wordle/word_list.py
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
abspath = os.path.abspath(__file__)
|
||||||
|
dirname = os.path.dirname(abspath)
|
||||||
|
os.chdir(dirname)
|
||||||
|
|
||||||
|
print("namespace wordle {")
|
||||||
|
print("const uint8_t word_list[][word_length] = {")
|
||||||
|
|
||||||
|
answers = list()
|
||||||
|
|
||||||
|
with open("word_list.csv", "r") as f:
|
||||||
|
index = 0
|
||||||
|
for line in f:
|
||||||
|
l = line.strip()
|
||||||
|
if not l:
|
||||||
|
continue
|
||||||
|
word, occurrence, day = l.split(",")
|
||||||
|
w = word.upper()
|
||||||
|
o = eval(occurrence)
|
||||||
|
d = day.strip()
|
||||||
|
|
||||||
|
if o > 1e-08:
|
||||||
|
print(f"{{'{w[0]}', '{w[1]}', '{w[2]}', '{w[3]}', '{w[4]}'}},")
|
||||||
|
if day:
|
||||||
|
answers.append(index)
|
||||||
|
index+=1
|
||||||
|
|
||||||
|
print("};")
|
||||||
|
|
||||||
|
print()
|
||||||
|
|
||||||
|
print("const uint32_t answers[] = {")
|
||||||
|
for answer in answers:
|
||||||
|
print(f"{answer},")
|
||||||
|
print("};")
|
||||||
|
|
||||||
|
print("}")
|
||||||
|
print(f"words: {index}", file=sys.stderr)
|
||||||
|
print(f"answers: {len(answers)}", file=sys.stderr)
|
@ -2,10 +2,11 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include "wordle.hpp"
|
#include "wordle.hpp"
|
||||||
|
#include "word_list.hpp"
|
||||||
|
|
||||||
namespace wordle {
|
namespace wordle {
|
||||||
|
|
||||||
void init_screen(struct screen& s, const uint8_t * word)
|
void init_screen(struct screen& s, uint32_t rand)
|
||||||
{
|
{
|
||||||
s.edit.row = 0;
|
s.edit.row = 0;
|
||||||
s.edit.index = 0;
|
s.edit.index = 0;
|
||||||
@ -13,66 +14,48 @@ void init_screen(struct screen& s, const uint8_t * word)
|
|||||||
for (uint32_t j = 0; j < word_length; j++) {
|
for (uint32_t j = 0; j < word_length; j++) {
|
||||||
for (uint32_t i = 0; i < guesses; i++) {
|
for (uint32_t i = 0; i < guesses; i++) {
|
||||||
s.rows[i].letters[j] = ' ';
|
s.rows[i].letters[j] = ' ';
|
||||||
|
s.rows[i].clues[j] = clue::none;
|
||||||
}
|
}
|
||||||
|
|
||||||
s.word[j] = word[j];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
s.rows[0].letters[0] = 'A';
|
for (uint32_t k = 0; k < 26; k++) {
|
||||||
s.rows[0].letters[1] = 'B';
|
s.clues[k] = clue::none;
|
||||||
s.rows[0].letters[2] = 'C';
|
}
|
||||||
s.rows[0].letters[3] = 'D';
|
|
||||||
s.rows[0].letters[4] = 'E';
|
|
||||||
|
|
||||||
s.rows[1].letters[0] = 'F';
|
constexpr uint32_t answer_length = (sizeof (answers)) / (sizeof (uint32_t));
|
||||||
s.rows[1].letters[1] = 'G';
|
s.word_ix = answers[rand % answer_length];
|
||||||
s.rows[1].letters[2] = 'H';
|
|
||||||
s.rows[1].letters[3] = 'I';
|
|
||||||
s.rows[1].letters[4] = 'J';
|
|
||||||
|
|
||||||
s.rows[2].letters[0] = 'K';
|
|
||||||
s.rows[2].letters[1] = 'L';
|
|
||||||
s.rows[2].letters[2] = 'M';
|
|
||||||
s.rows[2].letters[3] = 'N';
|
|
||||||
s.rows[2].letters[4] = 'O';
|
|
||||||
|
|
||||||
s.rows[3].letters[0] = 'P';
|
|
||||||
s.rows[3].letters[1] = 'Q';
|
|
||||||
s.rows[3].letters[2] = 'R';
|
|
||||||
s.rows[3].letters[3] = 'S';
|
|
||||||
s.rows[3].letters[4] = 'T';
|
|
||||||
|
|
||||||
s.rows[4].letters[0] = 'U';
|
|
||||||
s.rows[4].letters[1] = 'V';
|
|
||||||
s.rows[4].letters[2] = 'W';
|
|
||||||
s.rows[4].letters[3] = 'X';
|
|
||||||
s.rows[4].letters[4] = 'Y';
|
|
||||||
|
|
||||||
s.rows[5].letters[0] = 'Z';
|
|
||||||
s.rows[5].letters[1] = '1';
|
|
||||||
s.rows[5].letters[2] = '2';
|
|
||||||
s.rows[5].letters[3] = '3';
|
|
||||||
s.rows[5].letters[4] = '4';
|
|
||||||
|
|
||||||
s.all_letters = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool type_letter(struct screen& s, const uint8_t letter)
|
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)
|
if (s.edit.index >= word_length)
|
||||||
return false;
|
return false;
|
||||||
if (!(letter >= 'a' && letter <= 'z'))
|
if (letter >= 'a' && letter <= 'z') {
|
||||||
|
l = letter - ('a' - 'A'); // upcase
|
||||||
|
} else if (letter >= 'A' && letter <= 'Z') {
|
||||||
|
l = letter;
|
||||||
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
struct row& r = s.rows[s.edit.row];
|
struct row& r = s.rows[s.edit.row];
|
||||||
|
|
||||||
r.letters[s.edit.index++] = letter;
|
r.letters[s.edit.index++] = l;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool backspace(struct screen& s)
|
bool backspace(struct screen& s)
|
||||||
{
|
{
|
||||||
|
if (s.edit.row >= guesses)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (s.edit.index <= 0)
|
if (s.edit.index <= 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -83,4 +66,83 @@ bool backspace(struct screen& s)
|
|||||||
return true;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -6,14 +6,15 @@ constexpr uint32_t word_length = 5;
|
|||||||
constexpr uint32_t guesses = 6;
|
constexpr uint32_t guesses = 6;
|
||||||
|
|
||||||
enum class clue {
|
enum class clue {
|
||||||
correct,
|
exact,
|
||||||
position,
|
present,
|
||||||
absent,
|
absent,
|
||||||
none
|
none
|
||||||
};
|
};
|
||||||
|
|
||||||
struct row {
|
struct row {
|
||||||
uint8_t letters[word_length];
|
uint8_t letters[word_length];
|
||||||
|
enum clue clues[word_length];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct edit {
|
struct edit {
|
||||||
@ -24,10 +25,12 @@ struct edit {
|
|||||||
struct screen {
|
struct screen {
|
||||||
struct edit edit;
|
struct edit edit;
|
||||||
struct row rows[guesses];
|
struct row rows[guesses];
|
||||||
uint8_t word[word_length];
|
uint32_t word_ix;
|
||||||
uint32_t all_letters;
|
enum clue clues[26];
|
||||||
};
|
};
|
||||||
|
|
||||||
void init_screen(struct screen& s, const uint8_t * word);
|
void init_screen(struct screen& s, uint32_t word_ix);
|
||||||
|
bool type_letter(struct screen& s, const uint8_t letter);
|
||||||
|
bool backspace(struct screen& s);
|
||||||
|
bool confirm_word(struct screen& s);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user