Skip to content

Instantly share code, notes, and snippets.

@nandakoryaaa
Created June 11, 2025 15:56
Show Gist options
  • Save nandakoryaaa/fdb511a96b8fa680f4fcaade09c9fee9 to your computer and use it in GitHub Desktop.
Save nandakoryaaa/fdb511a96b8fa680f4fcaade09c9fee9 to your computer and use it in GitHub Desktop.
A simple game of guessing 5-letter Russian words (final)
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <process.h>
#include <time.h>
#include <string.h>
#include <windows.h>
#define LETTER_CNT 5
static const uint16_t russian_utf16[] = {
// А Б В Г Д Е Ё Ж З И Й К Л М Н О П
1040, 1041, 1042, 1043, 1044, 1045, /*1025,*/ 1046, 1047, 1048, 1049, 1050, 1051, 1052, 1053, 1054, 1055,
// Р С Т У Ф Х Ц Ч Ш Щ Ъ Ы Ь Э Ю Я
1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071,
// а б в г д е ё ж з и й к л м н о п
1072, 1073, 1074, 1075, 1076, 1077, /*1105,*/ 1078, 1079, 1080, 1081, 1082, 1083, 1084, 1085, 1086, 1087,
// р с т у ф х ц ч ш щ ъ ы ь э ю я
1088, 1089, 1090, 1091, 1092, 1093, 1094, 1095, 1096, 1097, 1098, 1099, 1100, 1101, 1102, 1103
};
const uint16_t russian_utf8[] = {
// А-Я
0x90D0, 0x91D0, 0x92D0, 0x93D0, 0x94D0, 0x95D0, /*0x81D0,*/ 0x96D0,
0x97D0, 0x98D0, 0x99D0, 0x9AD0, 0x9BD0, 0x9CD0, 0x9DD0, 0x9ED0,
0x9FD0, 0xA0D0, 0xA1D0, 0xA2D0, 0xA3D0, 0xA4D0, 0xA5D0, 0xA6D0,
0xA7D0, 0xA8D0, 0xA9D0, 0xAAD0, 0xABD0, 0xACD0, 0xADD0, 0xAED0,
0xAFD0
};
typedef enum {
NO_LETTER, HAS_LETTER, OK_LETTER
} LetterStatus;
typedef struct {
LetterStatus status[LETTER_CNT];
size_t ok_cnt;
} WordStatus;
typedef struct {
char letters[LETTER_CNT];
} Word;
typedef struct {
Word* words;
size_t cnt;
} WordStorage;
Word get_random_word(WordStorage wstor)
{
size_t rand_index = rand() * wstor.cnt / (RAND_MAX + 1);
return wstor.words[rand_index];
}
uint8_t find_word(WordStorage wstor, uint8_t* letters)
{
for (size_t i = 0; i < wstor.cnt; i++) {
if (
wstor.words[i].letters[0] == letters[0]
&& wstor.words[i].letters[1] == letters[1]
&& wstor.words[i].letters[2] == letters[2]
&& wstor.words[i].letters[3] == letters[3]
&& wstor.words[i].letters[4] == letters[4]
) {
return 1;
}
}
return 0;
}
WordStatus check_word(const char* letters, const char* test_letters)
{
WordStatus ws = { .ok_cnt = 0 };
uint8_t letter_cnt[33] = { 0 };
for (size_t i = 0; i < LETTER_CNT; i++) {
if (letters[i] == test_letters[i]) {
ws.status[i] = OK_LETTER;
ws.ok_cnt++;
} else {
letter_cnt[letters[i]]++;
}
}
for (size_t i = 0; i < LETTER_CNT; i++) {
if (ws.status[i] != OK_LETTER) {
uint32_t test_letter = test_letters[i];
if (letter_cnt[test_letter]) {
// есть в другом месте
ws.status[i] = HAS_LETTER;
letter_cnt[test_letter]--;
} else {
// нет вообще
ws.status[i] = NO_LETTER;
}
}
}
return ws;
}
void print_utf_dev(const char* word)
{
wchar_t wbuf[LETTER_CNT + 1];
for (size_t i = 0; i < LETTER_CNT; i++) {
wchar_t wc = russian_utf16[word[i] - 1];
uint8_t low_byte = ((wc >> 6) & 31) | 0xC0;
uint8_t high_byte = (wc & 63) | 0x80;
wbuf[i] = (high_byte << 8 | low_byte);
}
wbuf[LETTER_CNT] = 0;
printf("%s\n", (char*)wbuf);
}
void print_utf8(const char* word)
{
wchar_t wbuf[LETTER_CNT + 1];
for (size_t i = 0; i < LETTER_CNT; i++) {
wbuf[i] = russian_utf8[word[i] - 1];
}
wbuf[LETTER_CNT] = 0;
printf("%s", (char*)wbuf);
}
void print_status(const WordStatus* ws)
{
const char status_display[3] = { 'x', '-', '+' };
for (size_t i = 0; i < LETTER_CNT; i++) {
printf("%c", status_display[ws->status[i]]);
}
printf("\n");
}
Word from_utf8(const wchar_t* wbuf)
{
Word input;
for (size_t pos = 0; pos < LETTER_CNT; pos++) {
wchar_t wc = wbuf[pos];
if ((wc & 0xE0) != 0xC0) {
input.letters[0] = 0;
return input;
}
wc = ((wc >> 8) & 63) | ((wc & 31) << 6);
if (wc < 1040 || wc > 1103) {
input.letters[0] = 0;
return input;
}
if (wc > 1071) {
wc -= 32;
}
input.letters[pos] = wc - 1039;
}
return input;
}
Word from_utf16(const wchar_t* wbuf)
{
Word input;
for (size_t pos = 0; pos < LETTER_CNT; pos++) {
wchar_t wc = wbuf[pos];
if (wc < 1040 || wc > 1103) {
input.letters[0] = 0;
return input;
}
if (wc > 1071) {
wc -= 32;
}
input.letters[pos] = wc - 1039;
}
return input;
}
Word get_word_stdin()
{
Word input;
fgets(input.letters, sizeof(input.letters), stdin);
if (input.letters[strlen(input.letters) - 1] != '\n') {
// читать остаток во временный буфер
char buf[100];
do {
fgets(buf, sizeof(buf), stdin);
} while (buf[strlen(buf) - 1] != '\n');
}
return input;
}
Word get_word()
{
void* stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
wchar_t wbuf[LETTER_CNT + 3];
unsigned long int char_cnt = 0;
uint32_t read_cnt = 0;
do {
ReadConsoleW(
stdin_handle, wbuf, LETTER_CNT + 2, &char_cnt, NULL
);
read_cnt++;
} while (wbuf[char_cnt - 1] != '\n');
if (read_cnt > 1) {
return (Word) { .letters = { 0 } };
}
return from_utf16(wbuf);
}
WordStorage read_file(const char* filename)
{
char buf[32];
FILE* fp = fopen(filename, "r");
fgets(buf, sizeof(buf), fp);
size_t cnt = atoi(buf);
WordStorage wstor = {
.words = malloc(cnt * sizeof(Word)),
.cnt = 0
};
while (cnt && !feof(fp)) {
fgets(buf, sizeof(buf), fp);
Word word = from_utf8((wchar_t*)buf);
if (word.letters[0] == 0) {
break;
}
wstor.words[wstor.cnt++] = word;
cnt--;
}
fclose(fp);
if (wstor.cnt == 0 || cnt > 0) {
free(wstor.words);
wstor.words = NULL;
wstor.cnt = 0;
}
return wstor;
}
int main(int argc, char** argv)
{
WordStorage wstor = read_file(argv[1]);
if (wstor.cnt == 0) {
printf("file read error\n");
return 1;
}
printf("read %u words from file\n", wstor.cnt);
srand(time(NULL) ^ getpid());
size_t word_cnt = 10;
Word input;
WordStatus ws;
while (1) {
Word word = get_random_word(wstor);
uint8_t try_cnt = 1;
while (try_cnt < 7) {
printf("try #%u: ", try_cnt);
input = get_word();
if (!find_word(wstor, input.letters)) {
printf("word does not exist, try again\n");
continue;
}
ws = check_word(word.letters, input.letters);
print_utf8(input.letters);
printf("\n");
print_status(&ws);
if (ws.ok_cnt == LETTER_CNT) {
break;
}
try_cnt++;
}
if (ws.ok_cnt == LETTER_CNT) {
printf("YOU WON!\n");
} else {
printf("YOU LOST! (");
print_utf8(word.letters);
printf(")\n");
}
}
free(wstor.words);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment