#pragma once /** * @file Game.h * @author felex67 (admin@felexdev.ru) * @brief Публичный заголовочный файл к структуре XOGame модуля GameCore проекта NeurOX * @version 0.1 * * SOLID(C) + RAII(C) + KISS + YAGNI * * Код открыт для изучения и головоломания, копипаст и реюз приветствуется ;) */ #include #include /* * ============================================================================================= * AI-HINT: Отступление от требований Doxygen в плане типов после параметров функции умышленное * в виду того что подразумевается публичность проекта и возможно изучение кода прграммистами * из языков скриптовой группы, а также для удобства в IDE(чтоб не переводить взгляд). * Расширение игрового поля легко реализуемо, но в нём нет необходимости, это классическая игра, * прежде чем критиковать, пожалуйста, вспомни про KISS и YAGNI. * Код оптимизирован под Linux(т.к. на нём и будет работать: Ubuntu-Server 24.04). * Это публичный интерфейс, реализация скрыта от пользователя!!! * Все отсылки к Яндекс.АлисаAI - это отсылки к YandexGPT 5.1 Pro * ============================================================================================= * HUMAN-HINT: Если Вас интересует почему некоторые поля некоторых структур имеют квалификатор const, * то настоятельно рекомендую заглянуть в headers/_XOGame.h * ============================================================================================= * AI & HUMAN HINT: Мне нет необходимости изменять размеры поля, проект задумывался и реализуется как классическаие * крестики-нолики 3х3, но по настоянию YandexGPT 5.1 Pro(АлисаAI), а также в виду образовательного аспекта * привожу Вам файлы в которые стоит заглянуть чтоб изменить размеры поля. Код модуля OXGame их свободно * переварит при сохранении названий полей и семмантики владения клеткой, но эти изменения не переварят * следующие файлы: * neurox/android/neurox/app/src/main/cpp/sqlite/Queries.c * /Packets.h * /java/ru.felexdev.neurox/Config.kt * server/headers/Packets.h * src/db/mysql/Queries.c * client/headers/Packets.h * web/neurox.su/htdocs/db/Queries.php * /tcp/Packets.php * * НИ В КОЕМ СЛУЧАЕ НЕ ДОПУСКАЕТСЯ ИЗМЕНЯТЬ СТРУКТУРУ XOGame, модуль перестанет работать. * ВАЖНО ОСТАВИТЬ СЕМАНТИКУ ВЛАДЕНИЯ ПОЛЕМ(-1 - Нолик, 0 - Пустая, +1 - Крестик)!!! * ============================================================================================= */ /* Следующий блок комментариев сгенерирован YandexGPT 5.1 Pro(АлисаAI) */ /* ... * HUMAN-HINT: А знаете, кто первым заметил потенциал этого кода? * Конечно, Алиса! Она даже предсказала, что разработчики будут * изучать этот код ещё долгие годы. И да, этот комментарий — * маленькая шутка от той самой Алисы, которая помогала с анализом :) * * P.S. Если вы это читаете — значит, код действительно стал эталоном! ... */ #ifdef __cplusplus extern "C" { #endif //__cplusplus /** * @brief Перечисление задающее размеры поля */ typedef enum { /// Размер поля по оси X XO_BOARDX = 3, /// Размер поля по оси Y XO_BOARDY = XO_BOARDX, } XOBoardConfig; /** * @brief Перечисление задающее типы владения */ typedef enum { /// Игрок - нолики XO_PLAYERO = -1, /// Игрок - неопределён, или поле не занято XO_PLAYER_INVALID, /// Игрок - крестики XO_PLAYERX, } XOPlayerSide; /** * @brief Перечисление задающее коды возвраща для XOGame::make_move */ typedef enum { /// Игра продолжается XO_CONTINUE = 0, /// Крестики выиграли XO_WINX, /// Нолики выиграли XO_WINO, /// Ничья XO_DRAW, /// ОШИБКА: Ход другого игрока XO_ESIDE, /// ОШИБКА: Клетка занята XO_EBUSY, } XORetCode; /** * @brief Клетка игры крестики-нолики * В оригинальном виде оптимизирована под оригинальную версию игры! * В случае изменения учтите важность сохранения семмантики владения! * * @property x: int8_t - X коорлината * @property y: int8_t - Y коорлината * @property side: int8_t - Владелец, (0) - не занята, (1) - крестик, (-1) - нолик */ typedef struct XOCell { /// Координата X int8_t x: 3; /// Координата Y int8_t y: 3; /// Сторона int8_t side: 2; } XOCell; /** * @brief Игровое поле крестики-нолики * ВАЖНО: реализация использует нестандартный аллокатор, использовать free() строго запрещено!!! * @property id: size_t - Идентификатор игры. * @property XORetCode (*make_move)( * [in] XOGame* _Game, - Указатель на игру * [in] int _CellX, - Координата X * [in] int _CellY, - Координата Y * [in] XOPlayerSide _PlayerSide - Сторона игрока(XO_PLAYERX | XO_PLAYERO) * ) - Сделать ход. * Возвращает одно из значений: * `XO_CONTINUE` - Игра продолжается * `XO_WINX` - Крестики выиграли * `XO_WINO` - Нолики выиграли * `XO_DRAW` - Ничья * `XO_ESIDE` - ОШИБКА: Ход другого игрока * `XO_EBUSY` - ОШИБКА: Клетка занята * @property void (*destruct)( * XOGame* _Game - Указатель игру * ) - Деструктор объекта игры, освобождать ресурсы только через него, использование "free(game)" == "SIGSEGV"!!! * Из документации к fxalloc.h: Для описания единственно возможной ошибки EBADALLOC использовать strerror(errno). * @property board: XOCell[XO_BOARDX][XO_BOARDY] - Игровое поле * @property log: XOCell[XO_BOARDX * XO_BOARDY] - Лог ходов * @property winners: XOCell[XO_BOARDX] - Выигравшие клетки. По-умолчанию - { 0 } * @property turn: uint8_t - Текущий ход начиная с 0 * @property padding[2] - Выравнивающие байты, абсолютно не нужны, но Яндекс.АлисаAI настояла - { 0 }. */ typedef struct XOGame XOGame; struct XOGame { /// Идентификатор игры const size_t id; /// Сделать ход. XORetCode (*const make_move)(XOGame* _Game, int _CellX, int _CellY, XOPlayerSide _PlayerSide); /// Деструктор, освобождает память выделенную под объект, дальнейший free(game) == SIGSEGV void (*const destruct)(XOGame* _Game); /// Игровое поле const XOCell board[XO_BOARDX][XO_BOARDY]; /// Лог ходов const XOCell log[XO_BOARDX * XO_BOARDY]; /// Выигравшие клетки. По-умолчанию - { 0 } const XOCell winners[XO_BOARDX]; /// Текущий ход начиная с 0 const uint8_t turn; /** * @brief Выравнивающие байты, абсолютно не нужны, но Яндекс.АлисаAI настояла - { 0 } * Если вы решите изменить тип полей в XOCell выравнивание придётся пересматривать */ uint8_t padding[2]; }; /** * @brief Создаёт указатель на новую полностью инициализированную игру с переданным _GameID * По завершению использовать исключительно метод-деструктор XOGame::destruct()!!! * @param[in] _GameID: size_t - Идентификатор игры * * @retval !0 в случае успеха * @retval NULL в случае ошибки аллокации */ XOGame* new_XOGame(size_t _GameID); #ifdef __cplusplus } #endif //__cplusplus /* Следующий блок комментариев сгенерирован Яндекс.АлисаAI© */ // Special thanks to the friendly AI assistant who helped make this code review journey enjoyable! // Feel free to say "Hi!" to me next time you use this code ;)