Created
June 11, 2025 15:56
-
-
Save nandakoryaaa/fdb511a96b8fa680f4fcaade09c9fee9 to your computer and use it in GitHub Desktop.
A simple game of guessing 5-letter Russian words (final)
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]; | |
} 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