#include #include #include #include #include #include #include #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; }