Created
June 7, 2025 10:24
-
-
Save nandakoryaaa/6b1821e8e0e1ec13abc8dc1dcb795185 to your computer and use it in GitHub Desktop.
A game of guessing 5-letter Russian words - now with Windows Unicode support
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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]; | |
} InputWord; | |
static const char* words[10] = { | |
"сабля", "сакля", "пакля", "сопля", "сосна", | |
"весна", "осень", "овраг", "насос", "киоск" | |
}; | |
InputWord get_random_word(const InputWord* dict_words, size_t word_cnt) | |
{ | |
size_t rand_index = rand() * (word_cnt - 1) / RAND_MAX; | |
return dict_words[rand_index]; | |
} | |
uint8_t has_letter(const char* letters, uint32_t test_letter) | |
{ | |
for (size_t i = 0; i < LETTER_CNT; i++) { | |
if (letters[i] == test_letter) { | |
return 1; | |
} | |
} | |
return 0; | |
} | |
WordStatus check_word(const char* letters, const char* test_letters) | |
{ | |
WordStatus ws = { .ok_cnt = 0 }; | |
for (size_t i = 0; i < LETTER_CNT; i++) { | |
uint32_t letter = letters[i]; | |
uint32_t test_letter = test_letters[i]; | |
if (letter == test_letter) { | |
// есть на своём месте | |
ws.status[i] = OK_LETTER; | |
ws.ok_cnt++; | |
} else if (has_letter(letters, test_letter)) { | |
// есть в другом месте | |
ws.status[i] = HAS_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\n", (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"); | |
} | |
InputWord from_utf8(const wchar_t* wbuf) | |
{ | |
InputWord 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; | |
} | |
InputWord from_utf16(const wchar_t* wbuf) | |
{ | |
InputWord 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; | |
} | |
InputWord get_word_stdin() | |
{ | |
InputWord 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; | |
} | |
InputWord 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 (InputWord) { .letters = {0} }; | |
} | |
return from_utf16(wbuf); | |
} | |
int main() | |
{ | |
srand(time(NULL) ^ getpid()); | |
size_t word_cnt = 10; | |
InputWord input; | |
WordStatus ws; | |
InputWord dict_words[10]; | |
uint8_t result = 1; | |
for (size_t i = 0; i < word_cnt; i++) { | |
dict_words[i] = from_utf8((wchar_t*)words[i]); | |
if (dict_words[i].letters[0] == 0) { | |
result = 0; | |
break; | |
} | |
} | |
printf("result: %u\n", result); | |
while (1) { | |
InputWord word = get_random_word(dict_words, word_cnt); | |
for (int try_cnt = 1; try_cnt < 7; try_cnt++) { | |
printf("try #%u: ", try_cnt); | |
input = get_word(); | |
ws = check_word(word.letters, input.letters); | |
print_utf8(input.letters); | |
print_status(&ws); | |
if (ws.ok_cnt == LETTER_CNT) { | |
break; | |
} | |
} | |
if (ws.ok_cnt == LETTER_CNT) { | |
printf("YOU WON!\n"); | |
} else { | |
printf("YOU LOST!\n"); | |
} | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment