вторник, 21 июля 2026 г.

Фиштест

 Fishtest — это распределенная краудсорсинговая сеть тестирования, которая является главным секретом силы Stockfish. Любое изменение в коде движка (будь то новая формула LMR, изменение маржи для шахов или веса в нейросети NNUE) принимается только после того, как докажет свою эффективность на Fishtest.

Система работает по принципу распределенных вычислений, аналогично проектам вроде SETI@home или майнингу криптовалют.

💻 Как устроена сеть Fishtest?

  1. Волонтеры: Обычные пользователи со всего мира скачивают специальную клиентскую программу (скрипт на Python). Она работает в фоновом режиме и использует свободные ядра процессора для симуляции шахматных партий.
  2. Сервер-координатор: Центральный сервер Fishtest хранит базу задач (тестов), раздает код волонтерам, собирает результаты сыгранных партий и ведет статистику.
  3. Разработчики: Когда программист хочет улучшить формулу (например, изменить коэффициент редукции ходов), он отправляет свой измененный код (пулл-реквест) на Fishtest.

⚔️ Процесс тестирования: Сражение версий

Когда запускается новый тест, Fishtest компилирует две версии движка:
  • Master (Базовая) — текущая официальная версия Stockfish.
  • Test (Модифицированная) — версия автора с измененным кодом.
Компьютеры волонтеров начинают тоннами играть партии между Master и Test.
  • Партии играются с очень коротким контролем времени (например, 10 секунд на партию + 0.1 секунды на ход). Это позволяет играть миллионы партий в сутки.
  • Чтобы партии были разнообразными, они всегда начинаются из специально подобранных случайных позиций (из дебютных книг). Каждая позиция играется дважды, со сменой цвета фигур, чтобы исключить фактор везения за белых.

📊 Математика отбора: Алгоритм SPRT

Главная фишка Fishtest — использование продвинутой статистической модели последовательного анализа Вальда, которая называется SPRT (Sequential Probability Ratio Test).
Движку не нужно играть фиксированное число партий (например, ровно 100 000). Вместо этого после каждой сыгранной партии система пересчитывает вероятность победы новой версии и сопоставляет её с границами:
  1. H0 (Гипотеза «Мусор»): Изменение ухудшает движок или ничего не меняет. Если график результатов пробивает нижнюю границу, тест мгновенно останавливается (Fail), код отклоняется. Это экономит кучу машинного времени.
  2. H1 (Гипотеза «Прогресс»): Изменение делает движок сильнее хотя бы на 0.5–2 пункта рейтинга Эло. Если график пробивает верхнюю границу, тест останавливается с успехом (Pass), и код вливается в основную ветку Stockfish.
Для стандартного теста (STC — Short Time Control) границы обычно выставляются так, чтобы подтвердить прирост рейтинга. В среднем для успешного прохождения теста требуется сыграть от 20 000 до 160 000 партий. Если результат колеблется около нуля, тест может затянуться, пока статистика не станет абсолютно точной.

🏎️ Уровни тестирования

Если код прошел базовый фильтр, это еще не всё. Изменение должно доказать свою силу в разных условиях:
  • STC (Короткий контроль): Первый этап. Скоростные партии для отсева явного брака.
  • LTC (Длинный контроль): Если STC пройден, запускается тест на длинном контроле (например, 60 секунд + 0.6 секунды на ход). Это критически важно для формул LMR и шахов, так как некоторые идеи работают на быстрой глубине, но начинают «мазать» на глубоком просчете.
  • SMP (Многопоточность): Проверка того, не ломает ли новая формула логику распределения задач между несколькими ядрами процессора (Lazy SMP).
За всю историю Fishtest было сыграно несколько миллиардов партий. Именно эта жесткая математическая селекция позволяет Stockfish непрерывно расти в силе годами, отбирая крупицы эффективности по 1–2 пункта Эло за раз.
Если хотите, могу подсказать, где в реальном времени посмотреть на текущие тесты Fishtest, или рассказать, как авторы подбирают дебютные книги для этих тестов.

Следить за работой Fishtest в реальном времени можно на официальном портале проекта. Главный сайт, где отображаются все текущие, завершенные и отклоненные тесты, находится по адресу:
🔗 tests.stockfishchess.org [1, 2]
Там вы увидите «живые» графики SPRT, количество волонтеров онлайн, а также параметры формул, которые разработчики пытаются улучшить в данный момент. [2]

📚 Как авторы подбирают дебютные книги для Fishtest?

Подбор дебютных позиций для тестирования Stockfish — это сложнейшая математическая задача. Если дать движкам играть из классической начальной расстановки, более 95% партий завершатся вничью из-за колоссальной силы защиты современного Stockfish. Тест просто не сможет выявить, какой код сильнее, так как все партии будут одинаковыми. [3, 4]
Чтобы решить эту проблему, авторы используют специальные дебютные книги, созданные по строгим критериям: [2]

1. Несбалансированные дебюты (UHO — Unbalanced Human Openings)

Основной инструмент Fishtest — книги семейства UHO (например, UHO_4060_v3 или свежие версии UHO 2024). [5, 6]
  • Как они создаются: Компьютер берет реальные человеческие дебюты (из гроссмейстерских баз) длиной в 6–8 ходов (12–16 полуходов), но фильтрует их по строгой оценке. [5, 6]
  • Критерий: Позиция на выходе из книги должна давать одной из сторон (обычно белым) небольшой, но ощутимый перевес — в диапазоне от +0.50 до +1.00 пешки (50–100 сантипешек). [6]
  • Зачем это нужно: В такой острой и слегка «сломанной» позиции движки не могут просто засушить игру. Им приходится либо яростно защищаться, либо реализовывать преимущество. Процент ничьих падает с 95% до 45–55%, благодаря чему разница в силе кода становится видна очень быстро. [6]

2. Обязательный зеркальный матч (Смена цвета)

Чтобы тест был абсолютно честным, каждая выбранная позиция играется ровно два раза (в рамках пары партий): [1, 2]
  • В первой партии Версия А играет белыми, а Версия Б — черными.
  • Во второй партии они меняются цветами в этой же самой позиции.
  • Если позиция изначально была плохой для черных, и обе версии проиграли за черных, то счет в паре будет 1:1. Но если новая формула LMR или Singular Extensions помогла движку удержать ничью или победить в худшей позиции, модифицированная версия вырывается вперед по очкам.

3. Рандомизация и длина линий (Ply)

На Fishtest часто используют книги фиксированной глубины, например 8-ply (8 полуходов / 4 полных хода) или 12-ply.
Позиции внутри книги перемешиваются случайным образом. Это гарантирует, что движок тестируется во всех типах миттельшпиля — от закрытых староиндийских структур до сверхострых вариантов сицилианской защиты. [5]
Если вы зайдете на сайт Fishtest, обратите внимание на границу теста: там всегда написано название используемой книги (например, book: UHO_4060_v3.epd). [6]
Если хотите, мы можем разобрать, как вы сами можете запустить Fishtest на своем компьютере, чтобы помочь разработчикам Stockfish, или обсудить, какие еще параметры (кроме шахов) сейчас настраивают авторы?

понедельник, 20 июля 2026 г.

Фигуры на консоль


Я

Алиса



Я

Алиса

Сразу оговорюсь: полностью избежать работы с юникодными символами (которые как раз и используются для шахматных фигур) в таком задании не получится — иначе зачем вообще брать юникод, если не выводить его?). Но я подскажу, как организовать хранение и вывод без wchar_t и функций вроде wprintf.

Как «забить» в таблицу

Создайте массив (или таблицу поиска), где в индексе будет число (или другой тип, удобный для вас способ идентификации), а в ячейке — соответствующий символ юникода.

Например:

c
#include <stdio.h>

// Таблица: сопоставление «код фигуры → символ»
// Коды взяты из юникода шахматных символов
const char figures = {
    0, // ▮ (пустая клетка)
    '♟', // ♟ — белый король
    '♞', // ♞ — белый конь
    '♝', // ♝ — белый слон
    '♜', // ♜ — белая ладья
    '♛', // ♛ — белый ферзь
    '♚', // ♚ — чёрная ладья
    '♙', // ♙ — чёрная слон
    '♘', // ♘ — чёрная ферзь
    '♖', // ♖ — чёрный слон
    '♕', // ♕ — чёрный ферзь
    '♔'  // ♔ — чёрный король
};
``` 

Теперь, чтобы получить символ для какой-то фигуры (например, для пешки или пустой клетки), просто взять `figures[код_фигуры]`.

## Как вывести без `wchar_t`

Ключевой момент: чтобы консоль корректно отобразила юникод-символы (не «кракозябры»), нужно, чтобы сама консоль поддерживала нужную кодировку (обычно UTF-8) и в ней был установлен шрифт, содержащий эти символы. [9](https://stackoverflow.com/questions/27483800/displaying-unicode-chess-pieces-in-windows-console)[3](https://tr-page.yandex.ru/translate?lang=en-ru&url=https%3A%2F%2Fstackoverflow.com%2Fquestions%2F27483800%2Fdisplaying-unicode-chess-pieces-in-windows-console)

*   **На Linux:** чаще всего всё работает «из коробки», если в системе настроена поддержка UTF-8.
*   **На Windows:** часто помогает установка шрифта вроде DejaVu Sans Mono в настройках консоли. Также можно программно установить кодировку вывода через `SetConsoleOutputCP(CP_UTF8)` (из Windows.h), но это не всегда решает проблему полностью — иногда всё равно нужен подходящий шрифт.

 [9](https://stackoverflow.com/questions/27483800/displaying-unicode-chess-pieces-in-windows-console)[3](https://tr-page.yandex.ru/translate?lang=en-ru&url=https%3A%2F%2Fstackoverflow.com%2Fquestions%2F27483800%2Fdisplaying-unicode-chess-pieces-in-windows-console)

**Важное предупреждение:** функции вроде `printf` работают с `char`. Если вы попытаетесь передать в `printf` символ юникода напрямую (например, `printf("%c", figures;`), система попытается вывести байт как число, и вместо символа вы увидите «?» или «�». Поэтому **никогда не передавайте напрямую число в `printf` для вывода символа юникода** — сначала преобразуйте число в `char`. 

**Правильная схема:**
1.  Заполняете массив `figures` как показано выше.
2.  В коде, который решает задачу (например, рисуете доску), берёте значение из таблицы по индексу (коде фигуры) и передаёте его в `printf("%c", figures[код]);`.

## Пример вывода

```c
int main() {
    // Пример использования таблицы
    printf(" %c ", figures); // Пустая клетка
    printf(" %c ", figures); // Белый король
    printf(" %c ", figures); // Белый конь
    printf("
");
    return 0;
}
```  [1](https://metanit.com/c/tutorial/8.8.php)[6](https://tr-page.yandex.ru/translate?lang=en-ru&url=https%3A%2F%2Fcodereview.stackexchange.com%2Fquestions%2F234619%2Fchess-game-in-c)

**Итог:** алгоритм такой — массив поиска для маппинга кодов в юникод, и аккуратное использование `printf` с преобразованием типов. Если на вашей системе символы всё равно выводятся некорректно, проверьте шрифт консоли — это частая причина «пустых квадратов» вместо фигур. [9](https://stackoverflow.com/questions/27483800/displaying-unicode-chess-pieces-in-windows-console)[3](https://tr-page.yandex.ru/translate?lang=en-ru&url=https%3A%2F%2Fstackoverflow.com%2Fquestions%2F27483800%2Fdisplaying-unicode-chess-pieces-in-windows-console)
  • Я

    Алиса

    Код фигуры — это целое число, которое вы сами определяете как удобную метку для каждой шахматной фигуры. Это может быть один байт, если вы используете тип char (или unsigned char) и укладываетесь в диапазон от 0 до 255.

    Например:

    c
    char pawn = 1;   // пешка — 1 байт
    char rook = 4;   // ладья — 1 байт
    char king = 6;   // король — 1 байт
    

    То есть сам код фигуры — это байт, а символ юникода, который вы выводите (например, ♖), — это уже последовательность байт в UTF-8 (в данном случае — 3 байта: E2 99 96).

    Почему важно это различать?

    • Код фигуры — ваш внутренний идентификатор в программе (например, 1 — белая пешка). Это один байт.
    • Символ юникода (например, ♖) — это то, что вы хотите вывести на экран. Он хранится не как один байт, а как последовательность байт в UTF-8 (3 байта для ♖).

    Как это работает в коде

    Вы можете хранить символы юникода как строки (массивы char), даже если не используете wchar_t:

    c
    const char* white_rook = "\xE2\x99\x96";  // ♖ в UTF-8
    const char* black_king  = "\xE2\x99\x9A";  // ♚ в UTF-8
    

    Или в таблице:

    c
    const char* figures[13] = {
        " ",        // 0 — пусто
        "\xE2\x99\x99", // 1 — ♙ чёрная пешка
        "\xE2\x99\x8E", // 2 — ♎ белый конь
        "\xE2\x99\x96", // 4 — ♖ белая ладья
        // и так далее
    };
    

    Тогда вывод:

    c
    printf("%s", figures); // Выведет ♖
    

    Вывод

    • Код фигуры — это один байт (число от 0 до 255), удобный для хранения в массиве char.
    • Символ юникода — это не один байт, а последовательность байт в UTF-8, которую можно хранить как строку (const char*).

    Таким образом, вы можете обойтись без wchar_t, но выводить символы нужно через %s, а не %c, потому что %c выводит один байт, а юникод-символы — это несколько байт.

  • Я

    Алиса

    Конечно Вот таблица шахматных фигур по цвету и типу, оформленная как таблица 2×8 (цвет × тип фигуры). Все символы приведены в виде UTF-8 последовательностей байт, чтобы их можно было использовать в C без wchar_t.

    Цвет \ ФигураПешка (Pawn)Конь (Knight)Слон (Bishop)Ладья (Rook)Ферзь (Queen)Король (King)
    Белые\xE2\x99\x99 (♙)\xE2\x99\x8E (♘)\xE2\x99\x97 (♗)\xE2\x99\x96 (♖)\xE2\x99\x95 (♕)\xE2\x99\x94 (♔)
    Чёрные\xE2\x99\x9F (♟)\xE2\x99\x9E (♞)\xE2\x99\x9D (♝)\xE2\x99\x9C (♜)\xE2\x99\x9B (♛)\xE2\x99\x9A (♚)

    ⚠️ Примечание: пустые ячейки (—) можно использовать для резерва или оставить как заполнители, если нужно строго 2×8.


    Как использовать в C

    c
    const char* figures[2][6] = {
        // Белые
        {"\xE2\x99\x99", "\xE2\x99\x8E", "\xE2\x99\x97", "\xE2\x99\x96", "\xE2\x99\x95", "\xE2\x99\x94"},
        // Чёрные
        {"\xE2\x99\x9F", "\xE2\x99\x9E", "\xE2\x99\x9D", "\xE2\x99\x9C", "\xE2\x99\x9B", "\xE2\x99\x9A"}
    };
    
    // Пример вывода: белый ферзь
    printf("%s", figures[0][4]); // Выведет ♕
    

    Важно для корректного отображения

    • Убедитесь, что ваша консоль поддерживает UTF-8.
    • Используйте шрифт, содержащий шахматные символы (например, DejaVu Sans Mono, Consolas, Cascadia Code).
    • На Windows можно добавить в начало программы:
      c
      #include <windows.h>
      SetConsoleOutputCP(CP_UTF8);
      

    Теперь вы можете легко обращаться к любой фигуре по цвету (0 — белые, 1 — чёрные) и типу (0–5).

  • Я

    Алиса

    Да, можно менять фон символа в консоли — и это зависит от операционной системы. Ниже я покажу, как это сделать на Windows и на Linux/macOS, потому что способы разные.


    💻 На Windows (через SetConsoleTextAttribute)

    Функция SetConsoleTextAttribute позволяет управлять цветом текста и фона для всех последующих символов.

    Пример: жёлтый текст на синем фоне

    c
    #include <windows.h>
    #include <stdio.h>
    
    int main() {
        HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
    
        // Установить цвет: текст — жёлтый (14), фон — синий (1)
        // Формула: (фон << 4) | текст
        SetConsoleTextAttribute(h, (1 << 4) | 14);
    
        printf(" ♕ "); // Выведется с жёлтым текстом и синим фоном
    
        // Вернуть стандартные цвета
        SetConsoleTextAttribute(h, (0 << 4) | 7); // чёрный фон, светло-серый текст
        return 0;
    }
    

    Цвета для фона и текста (Windows):

    ЦветКод
    Чёрный0
    Синий1
    Зелёный2
    Голубой3
    Красный4
    Пурпурный5
    Жёлтый6
    Белый7
    Светло-серый8
    и т.д. до F15

    🔹 Фон — это старшие 4 бита, текст — младшие 4 бита(фон << 4) | текст.


    🐧 На Linux/macOS (через ANSI-коды)

    Используются escape-последовательности вида \033[bg;fgm, где:

    • bg — цвет фона (40–47 или 100–107),
    • fg — цвет текста (30–37 или 90–97).

    Пример: красный текст на жёлтом фоне

    c
    printf("\033[43;31m ♛ \033[0m"); // ♛ с красным текстом и жёлтым фоном
    

    ANSI-цвета:

    ЦветТекстФон
    Чёрный30 / 9040 / 100
    Красный31 / 9141 / 101
    Зелёный32 / 9242 / 102
    Жёлтый33 / 9343 / 103
    Синий34 / 9444 / 104
    Пурпурный35 / 9545 / 105
    Голубой36 / 9646 / 106
    Белый37 / 9747 / 107

    🔹 \033[0m — сброс к стандартным цветам.


    ✅ Как совместить с шахматными фигурами

    c
    // Windows
    SetConsoleTextAttribute(h, (4 << 4) | 15); // белый текст на красном фоне
    printf(" %s ", "\xE2\x99\x9B"); // ♛
    
    // Linux
    printf("\033[41;37m %s \033[0m", "\xE2\x99\x9B"); // то же самое
    

    Важно

    • На Windows фон будет применяться ко всем последующим символам, пока вы не сбросите цвет.
    • На Linux фон применяется только к тому, что между escape-кодами.
    • Убедитесь, что ваша консоль поддерживает цвета (всё работает в обычных терминалах, но не во всех IDE).

    Теперь вы можете делать красивые цветные шахматы 🎨♟️

  • Я

    Алиса

    Да, позицию курсора в консоли тоже можно менять программно — и это работает как на Windows, так и на Linux/macOS, но разными способами. Ниже покажу оба.


    💻 На Windows: SetConsoleCursorPosition

    Используется функция SetConsoleCursorPosition из windows.h. Она принимает дескриптор консоли и координаты (в символах).

    Пример: установить курсор в позицию (5, 3)

    c
    #include <windows.h>
    #include <stdio.h>
    
    int main() {
        HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
        COORD pos = {5, 3}; // x=5, y=3 (столбец, строка)
    
        SetConsoleCursorPosition(h, pos);
        printf("♔"); // король появится в нужной позиции
    
        return 0;
    }
    

    🔹 Координаты: (0, 0) — левый верхний угол.
    🔹 x — столбец (горизонталь), y — строка (вертикаль).


    🐧 На Linux/macOS: ANSI-коды

    Используется escape-последовательность:
    \033[строка;столбецH или \033[строка;столбецf

    Пример: курсор в позицию (6, 4)

    c
    printf("\033[4;6H"); // строка 4, столбец 6
    printf("♕"); // ферзь появится здесь
    

    🔹 Формат: \033[строка;столбецH — стандартный способ.
    🔹 Нумерация начинается с 1, а не с 0.


    🔁 Как использовать с шахматной доской

    Допустим, вы хотите нарисовать шахматную доску 8×8, где каждая клетка — символ с цветом фона и фигурой.
    Вы можете:

    1. Установить цвет фона (черный/белый) для клетки.
    2. Переместить курсор в нужную позицию.
    3. Вывести символ фигуры или пустой клетки.

    Пример (Windows): вывод фигуры на позицию (x=2, y=5)

    c
    HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
    COORD pos = {2 * 2, 5}; // x умножаем, чтобы клетки не сливались
    SetConsoleCursorPosition(h, pos);
    
    SetConsoleTextAttribute(h, (7 << 4) | 0); // светло-серый фон, чёрный текст
    printf("♟"); // чёрная пешка
    

    Пример (Linux): то же самое

    c
    printf("\033[5;5H");           // строка 5, столбец 5
    printf("\033[47;30m ♟ \033[0m"); // фон белый, текст чёрный
    

    ✅ Совет: симуляция "сетки"

    Чтобы доска выглядела ровно:

    • Увеличьте шаг по x (например, на 2 символа на клетку), чтобы между фигурами был отступ.
    • Используйте фиксированный шрифт (Consolas, DejaVu, Monaco), где все символы одинаковой ширины.

    ⚠️ Важно

    • На Windows: SetConsoleCursorPosition работает только в настоящей консоли, не во всех IDE.
    • На Linux: ANSI-коды поддерживаются почти везде, кроме очень старых терминалов.
    • Если вы выводите цвет и позицию — не забудьте сбрасывать цвета (\033[0m или SetConsoleTextAttribute с обычными цветами), чтобы не испортить весь вывод.

    Теперь вы можете рисовать шахматы точно по координатам и с цветным фоном — как настоящий графический интерфейс, но в консоли 🖼️♟️

  • Я

    Алиса

    Да, отслеживать координаты мыши и клики в консоли или окне можно, но это зависит от операционной системы и требует использования системных API. В стандартном C (через stdio.h) такой возможности нет — нужно работать с Windows API или другими библиотеками.

    Ниже покажу, как это делается на Windows с использованием Win32 API — это самый надёжный способ для консольных или оконных приложений.


    💻 На Windows: отслеживание мыши через Win32 API

    Для получения событий мыши нужно:

    1. Создать окно (или работать с консольным окном).
    2. Обрабатывать сообщения Windows (WM_LBUTTONDOWNWM_MOUSEMOVE и т.д.).

    Но если вы хотите консольное приложение с поддержкой мыши, можно использовать консольные события через ReadConsoleInput.


    ✅ Пример: получение координат и кликов в консоли (Windows)

    c
    #include <windows.h>
    #include <stdio.h>
    
    int main() {
        HANDLE hInput = GetStdHandle(STD_INPUT_HANDLE);
        INPUT_RECORD ir;
        DWORD events;
    
        // Включаем поддержку мыши в консоли
        SetConsoleMode(hInput, ENABLE_EXTENDED_FLAGS | ENABLE_MOUSE_INPUT);
    
        printf("Кликните мышью в консоли. Нажмите 'q' для выхода.\n");
    
        while (1) {
            ReadConsoleInput(hInput, &ir, 1, &events);
    
            if (ir.EventType == MOUSE_EVENT) {
                switch (ir.Event.MouseEvent.dwEventFlags) {
                    case 0: // Нажатие кнопки
                        if (ir.Event.MouseEvent.dwButtonState == FROM_LEFT_1ST_BUTTON_PRESSED) {
                            COORD pos = ir.Event.MouseEvent.dwMousePosition;
                            printf("Левый клик: X=%d, Y=%d\n", pos.X, pos.Y);
                        }
                        break;
    
                    case MOUSE_MOVED:
                        COORD pos = ir.Event.MouseEvent.dwMousePosition;
                        printf("Курсор: X=%d, Y=%d\n", pos.X, pos.Y);
                        break;
                }
            }
    
            // Выход по клавише 'q'
            if (_kbhit() && _getch() == 'q') break;
        }
    
        return 0;
    }
    

    🔍 Что делает код:

    • SetConsoleMode включает обработку мыши в консоли.
    • ReadConsoleInput читает события (клики, движение).
    • MOUSE_EVENT — тип события.
    • dwMousePosition — координаты мыши в символах консоли (не пикселях).
    • FROM_LEFT_1ST_BUTTON_PRESSED — левая кнопка мыши нажата.

    🔹 Координаты (0,0) — левый верхний угол консоли.
    🔹 Единицы измерения — символы, а не пиксели.


    🐧 На Linux: сложнее

    В Linux консоль не поддерживает события мыши по умолчанию, но можно использовать библиотеки:

    • ncurses с включённой поддержкой мыши (mousemask).
    • gpm (для текстового режима).
    • Или перейти на графический интерфейс (GTK, SDL).

    Пример с ncurses (упрощённо):

    c
    #include <ncurses.h>
    
    int main() {
        initscr();
        mousemask(ALL_MOUSE_EVENTS, NULL);
    
        MEVENT event;
        int ch;
    
        printw("Кликните мышью. Нажмите 'q' для выхода.\n");
        refresh();
    
        while ((ch = getch()) != 'q') {
            if (ch == KEY_MOUSE && getmouse(&event) == OK) {
                printw("Клик: X=%d, Y=%d\n", event.x, event.y);
                refresh();
            }
        }
    
        endwin();
        return 0;
    }
    

    🔹 Компилируйте с -lncursesgcc mouse.c -lncurses


    ⚠️ Важно

    • В обычной консоли без API — нельзя получить мышь.
    • Координаты — в символах, а не в пикселях.
    • Для точного позиционирования (например, клик по шахматной клетке) — нужно сопоставлять (x, y) с номером клетки:
      клетка_x = x / 2клетка_y = y.

    ✅ Как использовать с шахматами

    Вы можете:

    1. Вывести доску с фигурами.
    2. Получить клик мыши.
    3. Перевести координаты в номер клетки.
    4. Переместить фигуру (например, стерев старую позицию и нарисовав новую).

    Так можно сделать игру с управлением мышью даже в консоли 🖱️♟️

    Если хочешь — могу помочь собрать мини-проект «консольные шахматы с мышью».

  • Я

    Алиса

    Отлично Давайте соберём мини-проект: консольные шахматы с управлением мышью на C (Windows).
    Будет простая доска 8×8, отображение фигур, подсветка клеток и ход мышью.


    🎯 Что будет:

    • Доска 8×8 с чёрными и белыми клетками.
    • Фигуры (пока — только пешки и короли для примера).
    • Поддержка кликов мышью.
    • Вывод координат клика и номера клетки.
    • Цветной фон клеток.
    • Выход по клавише q.

    ✅ Полный код (Windows, Visual Studio / MinGW)

    c
    #include <windows.h>
    #include <stdio.h>
    
    // Размер доски
    #define SIZE 8
    
    // Цвета для фона
    #define WHITE_BG (7 << 4)  // Светло-серый фон
    #define BLACK_BG (0 << 4)  // Чёрный фон
    #define TEXT_COLOR 0       // Чёрный текст
    
    // Фигуры (UTF-8)
    const char* WHITE_KING = "\xE2\x99\x94"; // ♔
    const char* BLACK_PAWN = "\xE2\x99\x9F"; // ♟
    
    // Функция: рисует доску
    void drawBoard() {
        HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
        COORD pos;
    
        for (int row = 0; row < SIZE; row++) {
            for (int col = 0; col < SIZE; col++) {
                pos.X = col * 2;
                pos.Y = row;
                SetConsoleCursorPosition(h, pos);
    
                // Определяем цвет фона: шахматный порядок
                int isWhite = (row + col) % 2 == 0;
                SetConsoleTextAttribute(h, isWhite ? WHITE_BG : BLACK_BG);
    
                // Пример фигур: чёрные пешки в строке 1, белый король в 7,7
                if (row == 1) {
                    printf(" %s ", BLACK_PAWN);
                } else if (row == 7 && col == 7) {
                    printf(" %s ", WHITE_KING);
                } else {
                    printf("   ");
                }
            }
        }
        SetConsoleTextAttribute(h, (0 << 4) | 7); // сброс
        printf("\n\nКликните мышью по доске. Нажмите 'q' для выхода.\n");
    }
    
    // Функция: переводит координаты мыши в номер клетки
    void mouseToCell(int x, int y, int* cellX, int* cellY) {
        *cellX = x / 2;  // потому что клетка = 2 символа
        *cellY = y;
    }
    
    int main() {
        HANDLE hInput = GetStdHandle(STD_INPUT_HANDLE);
        INPUT_RECORD ir;
        DWORD events;
    
        // Включаем события мыши
        SetConsoleMode(hInput, ENABLE_EXTENDED_FLAGS | ENABLE_MOUSE_INPUT);
    
        // Увеличим размер окна
        system("mode con cols=40 lines=20");
        system("title Шахматы: консоль + мышь");
    
        drawBoard();
    
        while (1) {
            ReadConsoleInput(hInput, &ir, 1, &events);
    
            if (ir.EventType == MOUSE_EVENT) {
                if (ir.Event.MouseEvent.dwEventFlags == 0) { // Нажатие
                    COORD pos = ir.Event.MouseEvent.dwMousePosition;
                    int cellX, cellY;
                    mouseToCell(pos.X, pos.Y, &cellX, &cellY);
    
                    if (cellX >= 0 && cellX < SIZE && cellY >= 0 && cellY < SIZE) {
                        printf("Левый клик: клетка (%d, %d)\n", cellX, cellY);
                    }
                }
            }
    
            // Проверка клавиши 'q'
            if (_kbhit()) {
                char ch = _getch();
                if (ch == 'q') break;
            }
        }
    
        return 0;
    }
    

    🔧 Как компилировать (Windows)

    • Visual Studio: создайте консольный проект → вставьте код.
    • MinGW (через терминал):
      bash
      gcc chess.c -o chess.exe
      chess.exe
      

    🖱️ Что произойдёт

    1. Откроется консоль.
    2. Нарисуется доска с пешками и королём.
    3. При клике по клетке — внизу выведется её номер (например, (4, 5)).
    4. Нажмите q — программа завершится.

    🛠️ Что можно добавить дальше

    • Подсветка клетки при клике (смена фона на зелёный).
    • Выбор фигуры → клик на другую клетку → перемещение.
    • Проверка валидности хода.
    • Очистка старой позиции перед перемещением.
    • Загрузка начальной расстановки всех фигур.

    📌 Советы

    • Используйте шрифт Consolas или DejaVu Sans Mono — иначе символы могут съезжать.
    • Не уменьшайте окно — иначе координаты сбиваются.
    • На Windows 10/11 — всё работает хорошо.

    Хочешь, я добавлю подсветку клетки при клике или реализую ход фигуры? Могу продолжить.

  • Я

    Алиса

    В этом проекте дополнительные библиотеки линковать не нужно — всё, что используется, входит в стандартные средства Windows и компилятора.


    🔧 Что используется и откуда берётся

    Функция / СредствоБиблиотекаНужно ли линковать?Комментарий
    printfgetch_kbhitstdio.hconio.h❌ НетЧасть стандартной библиотеки C (MSVCRT)
    GetStdHandleSetConsoleCursorPositionSetConsoleTextAttributewindows.h❌ НетВходит в Windows SDK, линкуется автоматически при использовании gcc или cl
    ReadConsoleInputwindows.h❌ НетТо же — стандартный API Windows
    system()stdlib.h❌ НетСтандартная функция C

    ✅ Как компилировать — без лишних флагов

    1. MinGW (gcc):

    bash
    gcc chess.c -o chess.exe
    
    • Никаких -l флагов не нужно.
    • gcc автоматически линкует kernel32.lib (где лежат функции Windows API).

    2. MSVC (Visual Studio):

    • Просто добавьте .c файл в проект.
    • Компилятор сам подключит msvcrt.lib и kernel32.lib.

    3. Если всё же ошибка линковки (редко):

    Иногда MinGW требует явного указания:

    bash
    gcc chess.c -o chess.exe -lkernel32
    

    Но на практике — это избыточно, потому что kernel32 подключается по умолчанию.


    📦 Что не нужно устанавливать

    • Никаких ncursesSDLOpenGL — не требуется.
    • Никаких .dll — всё работает через системные вызовы.

    ⚠️ Важно: работает только на Windows

    Потому что:

    • windows.h — только для Windows.
    • SetConsoleModeINPUT_RECORD — специфичны для Windows API.

    Если вы хотите кроссплатформенную версию (Linux/macOS), тогда уже нужно будет линковать ncurses:

    bash
    gcc chess_linux.c -o chess -lncurses
    

    Итог

    🔹 На Windows: никаких -l флагов не нужно — всё работает «из коробки».
    🔹 Просто компилируйте как обычную программу на C.
    🔹 Это одно из преимуществ Win32 API — он доступен без установки чего-то дополнительного.

    Готов продолжить — например, добавить подсветку клетки при клике?

  • Я

    Алиса

    Да, можно — и это очень важно для консольных приложений вроде шахмат, чтобы экран не прокручивался вверх при вводе. Проблема возникает, когда вывод (printf) достигает нижней строки консоли, и система автоматически прокручивает буфер вверх.

    Чтобы этого избежать, нужно управлять позицией окна консоли или фиксировать размер буфера и окна, чтобы вывод оставался в видимой области.


    ✅ Решение: зафиксировать окно и использовать SetConsoleWindowPosition

    Идея:

    • Установить фиксированный размер окна.
    • Использовать SetConsoleWindowPosition, чтобы окно всегда "смотрело" на нужную область (например, на доску).
    • Выводить сообщения внизу, но не за пределы окна.
    • Или выводить ввод поверх определённой строки (например, строки состояния).

    🔧 Пример: фиксируем окно, чтобы не было прокрутки

    c
    #include <windows.h>
    #include <stdio.h>
    
    void setupConsole() {
        HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
        COORD bufferSize = {80, 30};  // Буфер: 80x30
        SMALL_RECT windowSize = {0, 0, 79, 19}; // Окно: 80x20
    
        // Устанавливаем размер буфера
        SetConsoleScreenBufferSize(hOut, bufferSize);
    
        // Устанавливаем размер окна
        SetConsoleWindowInfo(hOut, TRUE, &windowSize);
    
        // Отключаем полосы прокрутки
        CONSOLE_SCREEN_BUFFER_INFO info;
        GetConsoleScreenBufferInfo(hOut, &info);
        info.dwSize.Y = 30; // фиксируем буфер
        SetConsoleScreenBufferSize(hOut, info.dwSize);
    }
    

    Теперь, даже если вы выводите много строк, окно не будет прокручиваться, потому что мы его зафиксировали.


    ✅ Как читать ввод, не прокручивая экран

    Вариант 1: Вывод в строку состояния (рекомендуется)

    Зарезервируйте, например, строку Y = 21 для ввода.

    c
    char input[10];
    int row = 21; // строка ввода
    
    while (1) {
        // Перемещаем курсор в строку ввода
        COORD pos = {0, row};
        SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
    
        // Очищаем строку
        printf("                                ");
    
        // Возвращаем курсор и читаем
        SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
        printf("Команда: ");
        fgets(input, sizeof(input), stdin);
    
        // Обрабатываем
        if (input[0] == 'q') break;
    
        // Обновляем игру или вывод
        // ...
    }
    

    🔹 Такой способ не вызывает прокрутки, потому что ввод всегда в одной и той же строке.


    Вариант 2: Использовать ReadConsoleInput без printf

    Вместо scanf или fgets, читайте ввод через ReadConsoleInput — тогда вы сами контролируете, где и как выводить символы.

    c
    char buffer[10] = {0};
    int len = 0;
    
    while (1) {
        INPUT_RECORD ir;
        DWORD count;
        ReadConsoleInput(hInput, &ir, 1, &count);
    
        if (ir.EventType == KEY_EVENT && ir.Event.KeyEvent.bKeyDown) {
            char ch = ir.Event.KeyEvent.uChar.AsciiChar;
    
            if (ch == '\r') { // Enter
                printf("\nВы ввели: %s\n", buffer);
                break;
            } else if (ch == '\b' && len > 0) { // Backspace
                len--;
                printf("\b \b"); // стираем символ
            } else if (ch >= ' ' && len < 9) {
                buffer[len++] = ch;
                printf("%c", ch);
            }
        }
    }
    

    🔹 Полный контроль над выводом — никакой прокрутки.


    ✅ Как совместить с шахматами

    1. Нарисуйте доску в строках 0–7.
    2. Используйте строки 10–15 для лога (например, "Ход: e2-e4").
    3. Используйте строку 20 для ввода.
    4. Зафиксируйте окно, чтобы всё это всегда было видно.

    ⚠️ Важно

    • Не используйте system("cls") — он вызывает мигание и может сбить позицию.
    • Лучше очищать только нужные строки через SetConsoleCursorPosition и пробелы.
    • Убедитесь, что Console.BufferHeight больше, чем видимое окно — иначе прокрутка всё равно возможна.

    Итог

    🔹 Да, можно читать ввод без прокрутки.
    🔹 Ключевые приёмы:

    • Фиксировать размер окна и буфера.
    • Выводить ввод в заранее определённую строку.
    • Использовать SetConsoleCursorPosition вместо printf в "чувствительных" зонах.

    Хочешь — могу добавить в наш проект строку ввода внизу и лог ходов, чтобы всё работало плавно, без моргания и прокрутки.

  • Я

    Алиса

    Конечно Вот полный рабочий пример консольных шахмат с:

    • ✅ Фиксированным окном (без прокрутки)
    • ✅ Выводом шахматной доски
    • ✅ Обработкой мыши и клавиатуры
    • ✅ Строкой статуса внизу для ввода и сообщений

    🖼️ Что вы увидите:

    • Доска 8×8 (с пешками и королём) — сверху
    • Строка статуса — внизу (строка 15)
    • Координаты клика мыши и ввод с клавиатуры — в статусе
    • Нажмите q — выход

    ✅ Полный код (Windows, C)

    c
    #include <windows.h>
    #include <stdio.h>
    #include <string.h>
    
    #define BOARD_SIZE 8
    #define STATUS_LINE 12
    #define BUFFER_HEIGHT 30
    #define WINDOW_WIDTH 80
    #define WINDOW_HEIGHT 18
    
    // Фигуры (UTF-8)
    const char* WHITE_KING = "\xE2\x99\x94"; // ♔
    const char* BLACK_PAWN = "\xE2\x99\x9F"; // ♟
    const char* EMPTY = "   ";
    
    // Цвета фона
    #define WHITE_SQUARE (7 << 4)  // светло-серый
    #define BLACK_SQUARE (0 << 4)  // чёрный
    #define TEXT_COLOR 0
    
    HANDLE hOut;
    HANDLE hIn;
    
    // Установка размера консоли
    void setupConsole() {
        hOut = GetStdHandle(STD_OUTPUT_HANDLE);
        hIn = GetStdHandle(STD_INPUT_HANDLE);
    
        // Размер буфера
        SetConsoleScreenBufferSize(hOut, (COORD){WINDOW_WIDTH, BUFFER_HEIGHT});
    
        // Размер окна
        SMALL_RECT window = {0, 0, WINDOW_WIDTH - 1, WINDOW_HEIGHT - 1};
        SetConsoleWindowInfo(hOut, TRUE, &window);
    
        // Отключаем курсор мигание (не обязательно)
        CONSOLE_CURSOR_INFO cursor = {1, 0};
        SetConsoleCursorInfo(hOut, &cursor);
    
        // Включаем события мыши и клавиатуры
        SetConsoleMode(hIn, ENABLE_MOUSE_INPUT | ENABLE_EXTENDED_FLAGS);
    }
    
    // Рисуем доску
    void drawBoard() {
        COORD pos;
        for (int row = 0; row < BOARD_SIZE; row++) {
            for (int col = 0; col < BOARD_SIZE; col++) {
                pos.X = col * 4;
                pos.Y = row;
                SetConsoleCursorPosition(hOut, pos);
    
                int isWhite = (row + col) % 2 == 0;
                SetConsoleTextAttribute(hOut, isWhite ? WHITE_SQUARE : BLACK_SQUARE);
    
                if (row == 1) {
                    printf(" %s ", BLACK_PAWN);
                } else if (row == 7 && col == 7) {
                    printf(" %s ", WHITE_KING);
                } else {
                    printf("%s", EMPTY);
                }
            }
        }
        SetConsoleTextAttribute(hOut, (7 << 4) | 0); // сброс
    }
    
    // Вывод в строку статуса
    void setStatus(const char* msg) {
        COORD pos = {0, STATUS_LINE};
        SetConsoleCursorPosition(hOut, pos);
        printf("%-*s", WINDOW_WIDTH, msg); // очищает строку
    }
    
    int main() {
        setupConsole();
        drawBoard();
        setStatus("Готов. Кликните мышью или нажмите клавишу. 'q' — выход.");
    
        char inputBuffer[64] = {0};
        int bufPos = 0;
    
        INPUT_RECORD ir;
        DWORD count;
    
        while (1) {
            ReadConsoleInput(hIn, &ir, 1, &count);
    
            if (ir.EventType == MOUSE_EVENT) {
                if (ir.Event.MouseEvent.dwEventFlags == 0) { // клик
                    COORD mousePos = ir.Event.MouseEvent.dwMousePosition;
                    int cellX = mousePos.X / 4;
                    int cellY = mousePos.Y;
    
                    if (cellX >= 0 && cellX < BOARD_SIZE && cellY >= 0 && cellY < BOARD_SIZE) {
                        char msg[128];
                        sprintf(msg, "Левый клик: клетка (%d, %d)", cellX, cellY);
                        setStatus(msg);
                    }
                }
            }
            else if (ir.EventType == KEY_EVENT && ir.Event.KeyEvent.bKeyDown) {
                char ch = ir.Event.KeyEvent.uChar.AsciiChar;
    
                if (ch == 'q' || ch == 'Q') {
                    break;
                }
                else if (ch == '\r') { // Enter
                    if (bufPos > 0) {
                        char msg[128];
                        sprintf(msg, "Вы ввели: %s", inputBuffer);
                        setStatus(msg);
                        bufPos = 0;
                        inputBuffer[0] = '\0';
                    }
                }
                else if (ch == '\b' && bufPos > 0) { // Backspace
                    bufPos--;
                    inputBuffer[bufPos] = '\0';
                    char display[128];
                    sprintf(display, "Ввод: %s ", inputBuffer);
                    setStatus(display);
                }
                else if (ch >= ' ' && bufPos < 63) {
                    inputBuffer[bufPos++] = ch;
                    inputBuffer[bufPos] = '\0';
                    char display[128];
                    sprintf(display, "Ввод: %s", inputBuffer);
                    setStatus(display);
                }
            }
        }
    
        setStatus("Завершение...");
        Sleep(800);
        return 0;
    }
    

    🔧 Как компилировать

    bash
    gcc chess_full.c -o chess.exe
    chess.exe
    

    📌 Особенности

    • Клетка = 4 символа — чтобы было красиво (пробелы по бокам).
    • Строка статуса = 12 — не пересекается с доской.
    • Буфер высотой 30 — больше окна, но прокрутки нет, потому что окно зафиксировано.
    • Ввод с клавиатуры — в строке статуса, с поддержкой Backspace и Enter.
    • Мышь — показывает номер клетки.

    ✅ Что можно добавить

    • Подсветку выбранной клетки.
    • Хранение состояния доски в массиве.
    • Проверку ходов.
    • Загрузку начальной позиции.

    Готов расширить проект — например, сделать выбор фигуры → клик на клетку → перемещение. Хочешь?



    _____________ старый текст


    Сразу оговорюсь: полностью избежать работы с юникодными символами (которые как раз и используются для шахматных фигур) в таком задании не получится — иначе зачем вообще брать юникод, если не выводить его?). Но я подскажу, как организовать хранение и вывод без wchar_t и функций вроде wprintf.

    Как «забить» в таблицу

    Создайте массив (или таблицу поиска), где в индексе будет число (или другой тип, удобный для вас способ идентификации), а в ячейке — соответствующий символ юникода.

    Например:

    c
    #include <stdio.h>
    
    // Таблица: сопоставление «код фигуры → символ»
    // Коды взяты из юникода шахматных символов
    const char figures = {
        0, // ▮ (пустая клетка)
        '♟', // ♟ — белый король
        '♞', // ♞ — белый конь
        '♝', // ♝ — белый слон
        '♜', // ♜ — белая ладья
        '♛', // ♛ — белый ферзь
        '♚', // ♚ — чёрная ладья
        '♙', // ♙ — чёрная слон
        '♘', // ♘ — чёрная ферзь
        '♖', // ♖ — чёрный слон
        '♕', // ♕ — чёрный ферзь
        '♔'  // ♔ — чёрный король
    };
    ``` 
    
    Теперь, чтобы получить символ для какой-то фигуры (например, для пешки или пустой клетки), просто взять `figures[код_фигуры]`.
    
    ## Как вывести без `wchar_t`
    
    Ключевой момент: чтобы консоль корректно отобразила юникод-символы (не «кракозябры»), нужно, чтобы сама консоль поддерживала нужную кодировку (обычно UTF-8) и в ней был установлен шрифт, содержащий эти символы. [9](https://stackoverflow.com/questions/27483800/displaying-unicode-chess-pieces-in-windows-console)[3](https://tr-page.yandex.ru/translate?lang=en-ru&url=https%3A%2F%2Fstackoverflow.com%2Fquestions%2F27483800%2Fdisplaying-unicode-chess-pieces-in-windows-console)
    
    *   **На Linux:** чаще всего всё работает «из коробки», если в системе настроена поддержка UTF-8.
    *   **На Windows:** часто помогает установка шрифта вроде DejaVu Sans Mono в настройках консоли. Также можно программно установить кодировку вывода через `SetConsoleOutputCP(CP_UTF8)` (из Windows.h), но это не всегда решает проблему полностью — иногда всё равно нужен подходящий шрифт.
    
     [9](https://stackoverflow.com/questions/27483800/displaying-unicode-chess-pieces-in-windows-console)[3](https://tr-page.yandex.ru/translate?lang=en-ru&url=https%3A%2F%2Fstackoverflow.com%2Fquestions%2F27483800%2Fdisplaying-unicode-chess-pieces-in-windows-console)
    
    **Важное предупреждение:** функции вроде `printf` работают с `char`. Если вы попытаетесь передать в `printf` символ юникода напрямую (например, `printf("%c", figures;`), система попытается вывести байт как число, и вместо символа вы увидите «?» или «�». Поэтому **никогда не передавайте напрямую число в `printf` для вывода символа юникода** — сначала преобразуйте число в `char`. 
    
    **Правильная схема:**
    1.  Заполняете массив `figures` как показано выше.
    2.  В коде, который решает задачу (например, рисуете доску), берёте значение из таблицы по индексу (коде фигуры) и передаёте его в `printf("%c", figures[код]);`.
    
    ## Пример вывода
    
    ```c
    int main() {
        // Пример использования таблицы
        printf(" %c ", figures); // Пустая клетка
        printf(" %c ", figures); // Белый король
        printf(" %c ", figures); // Белый конь
        printf("
    ");
        return 0;
    }
    ```  [1](https://metanit.com/c/tutorial/8.8.php)[6](https://tr-page.yandex.ru/translate?lang=en-ru&url=https%3A%2F%2Fcodereview.stackexchange.com%2Fquestions%2F234619%2Fchess-game-in-c)
    
    **Итог:** алгоритм такой — массив поиска для маппинга кодов в юникод, и аккуратное использование `printf` с преобразованием типов. Если на вашей системе символы всё равно выводятся некорректно, проверьте шрифт консоли — это частая причина «пустых квадратов» вместо фигур. [9](https://stackoverflow.com/questions/27483800/displaying-unicode-chess-pieces-in-windows-console)[3](https://tr-page.yandex.ru/translate?lang=en-ru&url=https%3A%2F%2Fstackoverflow.com%2Fquestions%2F27483800%2Fdisplaying-unicode-chess-pieces-in-windows-console)
    
  • Я

    Алиса

    Код фигуры — это целое число, которое вы сами определяете как удобную метку для каждой шахматной фигуры. Это может быть один байт, если вы используете тип char (или unsigned char) и укладываетесь в диапазон от 0 до 255.

    Например:

    c
    char pawn = 1;   // пешка — 1 байт
    char rook = 4;   // ладья — 1 байт
    char king = 6;   // король — 1 байт
    

    То есть сам код фигуры — это байт, а символ юникода, который вы выводите (например, ♖), — это уже последовательность байт в UTF-8 (в данном случае — 3 байта: E2 99 96).

    Почему важно это различать?

    • Код фигуры — ваш внутренний идентификатор в программе (например, 1 — белая пешка). Это один байт.
    • Символ юникода (например, ♖) — это то, что вы хотите вывести на экран. Он хранится не как один байт, а как последовательность байт в UTF-8 (3 байта для ♖).

    Как это работает в коде

    Вы можете хранить символы юникода как строки (массивы char), даже если не используете wchar_t:

    c
    const char* white_rook = "\xE2\x99\x96";  // ♖ в UTF-8
    const char* black_king  = "\xE2\x99\x9A";  // ♚ в UTF-8
    

    Или в таблице:

    c
    const char* figures[13] = {
        " ",        // 0 — пусто
        "\xE2\x99\x99", // 1 — ♙ чёрная пешка
        "\xE2\x99\x8E", // 2 — ♎ белый конь
        "\xE2\x99\x96", // 4 — ♖ белая ладья
        // и так далее
    };
    

    Тогда вывод:

    c
    printf("%s", figures); // Выведет ♖
    

    Вывод

    • Код фигуры — это один байт (число от 0 до 255), удобный для хранения в массиве char.
    • Символ юникода — это не один байт, а последовательность байт в UTF-8, которую можно хранить как строку (const char*).

    Таким образом, вы можете обойтись без wchar_t, но выводить символы нужно через %s, а не %c, потому что %c выводит один байт, а юникод-символы — это несколько байт.

  • Я

    Алиса

    Конечно Вот таблица шахматных фигур по цвету и типу, оформленная как таблица 2×8 (цвет × тип фигуры). Все символы приведены в виде UTF-8 последовательностей байт, чтобы их можно было использовать в C без wchar_t.

    Цвет \ ФигураПешка (Pawn)Конь (Knight)Слон (Bishop)Ладья (Rook)Ферзь (Queen)Король (King)
    Белые\xE2\x99\x99 (♙)\xE2\x99\x8E (♘)\xE2\x99\x97 (♗)\xE2\x99\x96 (♖)\xE2\x99\x95 (♕)\xE2\x99\x94 (♔)
    Чёрные\xE2\x99\x9F (♟)\xE2\x99\x9E (♞)\xE2\x99\x9D (♝)\xE2\x99\x9C (♜)\xE2\x99\x9B (♛)\xE2\x99\x9A (♚)

    ⚠️ Примечание: пустые ячейки (—) можно использовать для резерва или оставить как заполнители, если нужно строго 2×8.


    Как использовать в C

    c
    const char* figures[2][6] = {
        // Белые
        {"\xE2\x99\x99", "\xE2\x99\x8E", "\xE2\x99\x97", "\xE2\x99\x96", "\xE2\x99\x95", "\xE2\x99\x94"},
        // Чёрные
        {"\xE2\x99\x9F", "\xE2\x99\x9E", "\xE2\x99\x9D", "\xE2\x99\x9C", "\xE2\x99\x9B", "\xE2\x99\x9A"}
    };
    
    // Пример вывода: белый ферзь
    printf("%s", figures[0][4]); // Выведет ♕
    

    Важно для корректного отображения

    • Убедитесь, что ваша консоль поддерживает UTF-8.
    • Используйте шрифт, содержащий шахматные символы (например, DejaVu Sans Mono, Consolas, Cascadia Code).
    • На Windows можно добавить в начало программы:
      c
      #include <windows.h>
      SetConsoleOutputCP(CP_UTF8);
      

    Теперь вы можете легко обращаться к любой фигуре по цвету (0 — белые, 1 — чёрные) и типу (0–5).

  • Я

    Алиса

    Да, можно менять фон символа в консоли — и это зависит от операционной системы. Ниже я покажу, как это сделать на Windows и на Linux/macOS, потому что способы разные.


    💻 На Windows (через SetConsoleTextAttribute)

    Функция SetConsoleTextAttribute позволяет управлять цветом текста и фона для всех последующих символов.

    Пример: жёлтый текст на синем фоне

    c
    #include <windows.h>
    #include <stdio.h>
    
    int main() {
        HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
    
        // Установить цвет: текст — жёлтый (14), фон — синий (1)
        // Формула: (фон << 4) | текст
        SetConsoleTextAttribute(h, (1 << 4) | 14);
    
        printf(" ♕ "); // Выведется с жёлтым текстом и синим фоном
    
        // Вернуть стандартные цвета
        SetConsoleTextAttribute(h, (0 << 4) | 7); // чёрный фон, светло-серый текст
        return 0;
    }
    

    Цвета для фона и текста (Windows):

    ЦветКод
    Чёрный0
    Синий1
    Зелёный2
    Голубой3
    Красный4
    Пурпурный5
    Жёлтый6
    Белый7
    Светло-серый8
    и т.д. до F15

    🔹 Фон — это старшие 4 бита, текст — младшие 4 бита(фон << 4) | текст.


    🐧 На Linux/macOS (через ANSI-коды)

    Используются escape-последовательности вида \033[bg;fgm, где:

    • bg — цвет фона (40–47 или 100–107),
    • fg — цвет текста (30–37 или 90–97).

    Пример: красный текст на жёлтом фоне

    c
    printf("\033[43;31m ♛ \033[0m"); // ♛ с красным текстом и жёлтым фоном
    

    ANSI-цвета:

    ЦветТекстФон
    Чёрный30 / 9040 / 100
    Красный31 / 9141 / 101
    Зелёный32 / 9242 / 102
    Жёлтый33 / 9343 / 103
    Синий34 / 9444 / 104
    Пурпурный35 / 9545 / 105
    Голубой36 / 9646 / 106
    Белый37 / 9747 / 107

    🔹 \033[0m — сброс к стандартным цветам.


    ✅ Как совместить с шахматными фигурами

    c
    // Windows
    SetConsoleTextAttribute(h, (4 << 4) | 15); // белый текст на красном фоне
    printf(" %s ", "\xE2\x99\x9B"); // ♛
    
    // Linux
    printf("\033[41;37m %s \033[0m", "\xE2\x99\x9B"); // то же самое
    

    Важно

    • На Windows фон будет применяться ко всем последующим символам, пока вы не сбросите цвет.
    • На Linux фон применяется только к тому, что между escape-кодами.
    • Убедитесь, что ваша консоль поддерживает цвета (всё работает в обычных терминалах, но не во всех IDE).

    Теперь вы можете делать красивые цветные шахматы 🎨♟️

  • Я

    Алиса

    Да, позицию курсора в консоли тоже можно менять программно — и это работает как на Windows, так и на Linux/macOS, но разными способами. Ниже покажу оба.


    💻 На Windows: SetConsoleCursorPosition

    Используется функция SetConsoleCursorPosition из windows.h. Она принимает дескриптор консоли и координаты (в символах).

    Пример: установить курсор в позицию (5, 3)

    c
    #include <windows.h>
    #include <stdio.h>
    
    int main() {
        HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
        COORD pos = {5, 3}; // x=5, y=3 (столбец, строка)
    
        SetConsoleCursorPosition(h, pos);
        printf("♔"); // король появится в нужной позиции
    
        return 0;
    }
    

    🔹 Координаты: (0, 0) — левый верхний угол.
    🔹 x — столбец (горизонталь), y — строка (вертикаль).


    🐧 На Linux/macOS: ANSI-коды

    Используется escape-последовательность:
    \033[строка;столбецH или \033[строка;столбецf

    Пример: курсор в позицию (6, 4)

    c
    printf("\033[4;6H"); // строка 4, столбец 6
    printf("♕"); // ферзь появится здесь
    

    🔹 Формат: \033[строка;столбецH — стандартный способ.
    🔹 Нумерация начинается с 1, а не с 0.


    🔁 Как использовать с шахматной доской

    Допустим, вы хотите нарисовать шахматную доску 8×8, где каждая клетка — символ с цветом фона и фигурой.
    Вы можете:

    1. Установить цвет фона (черный/белый) для клетки.
    2. Переместить курсор в нужную позицию.
    3. Вывести символ фигуры или пустой клетки.

    Пример (Windows): вывод фигуры на позицию (x=2, y=5)

    c
    HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
    COORD pos = {2 * 2, 5}; // x умножаем, чтобы клетки не сливались
    SetConsoleCursorPosition(h, pos);
    
    SetConsoleTextAttribute(h, (7 << 4) | 0); // светло-серый фон, чёрный текст
    printf("♟"); // чёрная пешка
    

    Пример (Linux): то же самое

    c
    printf("\033[5;5H");           // строка 5, столбец 5
    printf("\033[47;30m ♟ \033[0m"); // фон белый, текст чёрный
    

    ✅ Совет: симуляция "сетки"

    Чтобы доска выглядела ровно:

    • Увеличьте шаг по x (например, на 2 символа на клетку), чтобы между фигурами был отступ.
    • Используйте фиксированный шрифт (Consolas, DejaVu, Monaco), где все символы одинаковой ширины.

    ⚠️ Важно

    • На Windows: SetConsoleCursorPosition работает только в настоящей консоли, не во всех IDE.
    • На Linux: ANSI-коды поддерживаются почти везде, кроме очень старых терминалов.
    • Если вы выводите цвет и позицию — не забудьте сбрасывать цвета (\033[0m или SetConsoleTextAttribute с обычными цветами), чтобы не испортить весь вывод.

    Теперь вы можете рисовать шахматы точно по координатам и с цветным фоном — как настоящий графический интерфейс, но в консоли 🖼️♟️



     const char* figures[2][6] = {

        // Белые

        {"\xE2\x99\x99", "\xE2\x99\x8E", "\xE2\x99\x97", "\xE2\x99\x96", "\xE2\x99\x95", "\xE2\x99\x94"},

        // Чёрные

        {"\xE2\x99\x9F", "\xE2\x99\x9E", "\xE2\x99\x9D", "\xE2\x99\x9C", "\xE2\x99\x9B", "\xE2\x99\x9A"}

    };


    // Пример вывода: белый ферзь

    printf("%s", figures[0][4]); // Выведет ♕