Skip to content

Instantly share code, notes, and snippets.

@nandakoryaaa
Created June 7, 2025 10:24
Show Gist options
  • Select an option

  • Save nandakoryaaa/6b1821e8e0e1ec13abc8dc1dcb795185 to your computer and use it in GitHub Desktop.

Select an option

Save nandakoryaaa/6b1821e8e0e1ec13abc8dc1dcb795185 to your computer and use it in GitHub Desktop.

Revisions

  1. nandakoryaaa created this gist Jun 7, 2025.
    239 changes: 239 additions & 0 deletions 5_utf16.c
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,239 @@
    #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;
    }