commit
5ed51b7e9c
2 changed files with 208 additions and 0 deletions
@ -0,0 +1 @@ |
|||||
|
Proof that wordle is solvable in 6 moves. |
||||
@ -0,0 +1,207 @@ |
|||||
|
#include <inttypes.h> |
||||
|
#include <stdbool.h> |
||||
|
#include <stdio.h> |
||||
|
#include <strings.h> |
||||
|
#include <stdlib.h> |
||||
|
|
||||
|
#define WORD_LENGTH 5 |
||||
|
|
||||
|
/* represents a 5-bit letter */ |
||||
|
typedef uint8_t let_t; |
||||
|
|
||||
|
/* represents a 5-bit letter + 3-bit position */ |
||||
|
typedef uint8_t lpos_t; |
||||
|
|
||||
|
/* represents a set of possible letters (technically, 26-bits) */ |
||||
|
typedef uint32_t let_set_t; |
||||
|
|
||||
|
/* represents 5 5-bit letters, a word */ |
||||
|
typedef uint32_t word_t; |
||||
|
|
||||
|
#define let_from_char(c) (((c) - 'a') & 0x1F) |
||||
|
|
||||
|
#define let_to_char(c) ((c) + 'a') |
||||
|
|
||||
|
lpos_t cptolp(char c, uint8_t pos) { |
||||
|
return (let_from_char(c) << 3) | pos; |
||||
|
} |
||||
|
|
||||
|
let_set_t ls_add(let_set_t set, let_t letter) { |
||||
|
return set | (1 << letter); |
||||
|
} |
||||
|
|
||||
|
let_set_t ls_test(let_set_t set, let_t letter) { |
||||
|
return (set & (1 << letter)) != 0; |
||||
|
} |
||||
|
|
||||
|
uint8_t lp_pos(lpos_t lp) { |
||||
|
return 0x07 & lp; |
||||
|
} |
||||
|
|
||||
|
char lp_char(lpos_t lp) { |
||||
|
return let_to_char(lp >> 3); |
||||
|
} |
||||
|
|
||||
|
/* result is a 2-bit value: */ |
||||
|
typedef enum result { |
||||
|
RES_BLACK = 0x01, |
||||
|
RES_YELLOW = 0x02, |
||||
|
RES_GREEN = 0x03 |
||||
|
} result_t; |
||||
|
|
||||
|
/* represents a wordle result: 5 2-bit result codes */ |
||||
|
typedef uint16_t result_set_t; |
||||
|
|
||||
|
result_set_t rs_set(result_t res, size_t index, result_t value) { |
||||
|
return res | ((value & 0x3) << (2 * index)); |
||||
|
} |
||||
|
|
||||
|
result_t rs_get(result_t res, size_t index) { |
||||
|
return (res >> (2 * index)) & 0x3; |
||||
|
} |
||||
|
|
||||
|
char word_charat(word_t word, size_t index) { |
||||
|
return (char) ((word >> (index * 5)) & 0x1F) + 'a'; |
||||
|
} |
||||
|
|
||||
|
/* converts a 5-letter word to its compacted representation */ |
||||
|
word_t strtoword(char *str) { |
||||
|
word_t word = 0; |
||||
|
for (size_t i = 0; i < WORD_LENGTH; ++i) { |
||||
|
word |= (str[i] - 'a') << (5 * i); |
||||
|
} |
||||
|
return word; |
||||
|
} |
||||
|
|
||||
|
void wordtostr(char *out, word_t word) { |
||||
|
for (size_t i = 0; i < WORD_LENGTH; ++i) { |
||||
|
out[i] = word_charat(word, i); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
result_set_t guess_match_werd(char *answer, char *guess) { |
||||
|
bool guess_consumed[WORD_LENGTH] = {false}; |
||||
|
bool answer_consumed[WORD_LENGTH] = {false}; |
||||
|
result_set_t result_set = 0; |
||||
|
for (size_t i = 0; i < WORD_LENGTH; ++i) { |
||||
|
if (answer[i] == guess[i]) { |
||||
|
answer_consumed[i] = true; |
||||
|
guess_consumed[i] = true; |
||||
|
result_set = rs_set(result_set, i, RES_GREEN); |
||||
|
} |
||||
|
} |
||||
|
for (size_t i = 0; i < WORD_LENGTH; ++i) { |
||||
|
if (guess_consumed[i]) { continue; } |
||||
|
bool found = false; |
||||
|
for (size_t j = 0; j < WORD_LENGTH; ++j) { |
||||
|
if (answer_consumed[j]) { continue; } |
||||
|
if (answer[j] == guess[i]) { |
||||
|
answer_consumed[j] = true; |
||||
|
found = true; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
if (found) { |
||||
|
result_set = rs_set(result_set, i, RES_YELLOW); |
||||
|
} else { |
||||
|
result_set = rs_set(result_set, i, RES_BLACK); |
||||
|
} |
||||
|
} |
||||
|
return result_set; |
||||
|
} |
||||
|
|
||||
|
result_set_t guess_match(word_t answer_word, word_t guess_word) { |
||||
|
char answer[6] = {0}, |
||||
|
guess[6] = {0}; |
||||
|
wordtostr(answer, answer_word); |
||||
|
wordtostr(guess, guess_word); |
||||
|
return guess_match_werd(answer, guess); |
||||
|
} |
||||
|
|
||||
|
/* returns whether or not the game was won */ |
||||
|
typedef struct wordle_game { |
||||
|
word_t target; |
||||
|
uint32_t turn_limit; |
||||
|
int (*guess_fn)(word_t *, void *); |
||||
|
void *guess_fn_data; |
||||
|
void (*display_fn)(result_set_t, void *); |
||||
|
void *display_fn_data; |
||||
|
} wordle_game_t; |
||||
|
|
||||
|
bool play_game(wordle_game_t *game) { |
||||
|
for (uint32_t turn = 1; turn <= game->turn_limit; ++turn) { |
||||
|
word_t guess = 0; |
||||
|
if (game->guess_fn(&guess, game->guess_fn_data) != 0) { |
||||
|
printf("guesser failure\n"); |
||||
|
} |
||||
|
result_set_t result_set = guess_match(game->target, guess); |
||||
|
game->display_fn(result_set, game->display_fn_data); |
||||
|
if (guess == game->target) { |
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
struct linebuf { |
||||
|
char *buffer; |
||||
|
size_t capacity; |
||||
|
}; |
||||
|
|
||||
|
int term_guess(word_t *word, void *data) { |
||||
|
struct linebuf *linebuf = data; |
||||
|
while (true) { |
||||
|
ssize_t bytes_read = getline(&(linebuf->buffer), &(linebuf->capacity), stdin); |
||||
|
if (bytes_read == -1) { |
||||
|
return -1; |
||||
|
} |
||||
|
char *buf_end = linebuf->buffer; |
||||
|
strsep(&buf_end, "\n"); |
||||
|
if (strchr(linebuf->buffer, '\0') - linebuf->buffer == WORD_LENGTH) { |
||||
|
*word = strtoword(linebuf->buffer); |
||||
|
return 0; |
||||
|
} else { |
||||
|
continue; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void term_display(result_set_t result_set, void *ignored) { |
||||
|
(void) ignored; |
||||
|
for (size_t i = 0; i < WORD_LENGTH; ++i) { |
||||
|
switch (rs_get(result_set, i)) { |
||||
|
case RES_BLACK: |
||||
|
fputc(' ', stdout); |
||||
|
break; |
||||
|
case RES_YELLOW: |
||||
|
fputc('Y', stdout); |
||||
|
break; |
||||
|
case RES_GREEN: |
||||
|
fputc('G', stdout); |
||||
|
break; |
||||
|
default: |
||||
|
fputc('X', stdout); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
fputs(" result", stdout); |
||||
|
fputc('\n', stdout); |
||||
|
} |
||||
|
|
||||
|
int main(int argc, char *argv[]) { |
||||
|
struct linebuf lb = { |
||||
|
.capacity = 6, |
||||
|
.buffer = (char *) malloc(lb.capacity), |
||||
|
}; |
||||
|
wordle_game_t game = { |
||||
|
.target = strtoword("total"), |
||||
|
.turn_limit = 6, |
||||
|
.guess_fn = term_guess, |
||||
|
.guess_fn_data = &lb, |
||||
|
.display_fn = term_display, |
||||
|
.display_fn_data = NULL, |
||||
|
}; |
||||
|
int x = play_game(&game); |
||||
|
printf("endgame %d\n", x); |
||||
|
return 0; |
||||
|
} |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue