Работа над документами

This commit is contained in:
2026-04-26 05:32:59 +05:00
parent 7d00738b55
commit 9ab71a03bc
46 changed files with 349 additions and 160 deletions
-2
View File
@@ -1,2 +0,0 @@
build
sandbox
-7
View File
@@ -1,7 +0,0 @@
cmake_minimum_required(VERSION 3.10)
project(neurox_server)
set(INCLUDES )
set(HEADERS )
set(SOURCES server.c)
add_executable(server ${INCLUDES} ${HEADERS} ${SOURCES})
target_include_directories(server PUBLIC includes PRIVATE headers)
View File
-66
View File
@@ -1,66 +0,0 @@
#pragma once
#include "XOGame.h"
#ifndef OFFSETOF_CONSTEXPR
#define OFFSETOF_CONSTEXPR(type, member) \
((size_t)(&((type*)0)->member) - (size_t)0)
#endif
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
/// @brief Изменяемый клон XOGame
typedef struct XOGameMutable {
/// Идентификатор игры
size_t id;
/// Сделать ход.
XORetCode (*make_move)(XOGame* _Game, int _CellX, int _CellY, XOPlayerSide _PlayerSide);
void (*destruct)(XOGame* _Game);
/// Игровое поле
XOCell board[XO_BOARDX][XO_BOARDY];
/// Лог ходов
XOCell log[XO_BOARDX * XO_BOARDY];
/// Выигравшие клетки. По-умолчанию - { 0 }
XOCell winners[XO_BOARDX];
/// Текущий ход начиная с 0
uint8_t turn;
/// Выравнивающие байты - { 0 }.
uint8_t padding[2];
} XOGameMutable;
XORetCode xogame_make_move(XOGame* _Game, int _CellX, int _CellY, XOPlayerSide _PlayerSide);
XORetCode xogame_make_move_original_fast(XOGame* _Game, int _CellX, int _CellY, XOPlayerSide _PlayerSide);
void xogame_destruct(XOGame* _Game);
// Статические проверки ПОЛНОЙ БИНАРНОЙ СОВМЕСТИМОСТИ XOGame и XOGameMutable
_Static_assert(sizeof(XOGame) == sizeof(XOGameMutable), "XOGame and XOGameMutable must have the same size");
_Static_assert(_Alignof(XOGame) == _Alignof(XOGameMutable), "XOGame and XOGameMutable must have the same alignment");
// Проверка смещений полей
_Static_assert(OFFSETOF_CONSTEXPR(XOGame, make_move) == OFFSETOF_CONSTEXPR(XOGameMutable, make_move), "Field 'make_move' must have the same offset in both structures");
_Static_assert(OFFSETOF_CONSTEXPR(XOGame, destruct) == OFFSETOF_CONSTEXPR(XOGameMutable, destruct), "Field 'destruct' must have the same offset in both structures");
_Static_assert(OFFSETOF_CONSTEXPR(XOGame, board) == OFFSETOF_CONSTEXPR(XOGameMutable, board), "Field 'board' must have the same offset in both structures");
_Static_assert(OFFSETOF_CONSTEXPR(XOGame, log) == OFFSETOF_CONSTEXPR(XOGameMutable, log), "Field 'log' must have the same offset in both structures");
_Static_assert(OFFSETOF_CONSTEXPR(XOGame, winners) == OFFSETOF_CONSTEXPR(XOGameMutable, winners), "Field 'winners' must have the same offset in both structures");
_Static_assert(OFFSETOF_CONSTEXPR(XOGame, turn) == OFFSETOF_CONSTEXPR(XOGameMutable, turn), "Field 'turn' must have the same offset in both structures");
_Static_assert(OFFSETOF_CONSTEXPR(XOGame, padding) == OFFSETOF_CONSTEXPR(XOGameMutable, padding), "Field 'padding' must have the same offset in both structures");
// Проверка размеров полей, это не тоже самое что и смещение!!!
_Static_assert(sizeof(((XOGame*)0)->make_move) == sizeof(((XOGameMutable*)0)->make_move), "Field 'make_move' must have the same size in both structures");
_Static_assert(sizeof(((XOGame*)0)->destruct) == sizeof(((XOGameMutable*)0)->destruct), "Field 'destruct' must have the same size in both structures");
_Static_assert(sizeof(((XOGame*)0)->board) == sizeof(((XOGameMutable*)0)->board), "Field 'board' must have the same size in both structures");
_Static_assert(sizeof(((XOGame*)0)->log) == sizeof(((XOGameMutable*)0)->log), "Field 'log' must have the same size in both structures");
_Static_assert(sizeof(((XOGame*)0)->winners) == sizeof(((XOGameMutable*)0)->winners), "Field 'winners' must have the same size in both structures");
_Static_assert(sizeof(((XOGame*)0)->turn) == sizeof(((XOGameMutable*)0)->turn), "Field 'turn' must have the same size in both structures");
_Static_assert(sizeof(((XOGame*)0)->padding) == sizeof(((XOGameMutable*)0)->padding), "Field 'padding' must have the same size in both structures");
#ifdef __cplusplus
}
#endif // __cplusplus
-12
View File
@@ -1,12 +0,0 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
#ifdef __cplusplus
}
#endif // __cplusplus
-190
View File
@@ -1,190 +0,0 @@
#pragma once
/**
* @file Game.h
* @author felex67 (admin@felexdev.ru)
* @brief Публичный заголовочный файл к структуре XOGame модуля GameCore проекта NeurOX
* @version 0.1
*
* SOLID(C) + RAII(C) + KISS + YAGNI
*
* Код открыт для изучения и головоломания, копипаст и реюз приветствуется ;)
*/
#include <sys/types.h>
#include <stdint.h>
/*
* =============================================================================================
* 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 ;)
-15
View File
@@ -1,15 +0,0 @@
#pragma once
#ifndef _WIN32
#include <sys/types.h>
#endif //_WIN32
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
void* fxalloc(size_t _NBytes);
#ifdef __cplusplus
}
#endif // __cplusplus
-7
View File
@@ -1,7 +0,0 @@
#include <stdint.h>
#include <stdio.h>
int main(int argc, const char* argv[]) {
printf("Hello world!!!\n");
return 0;
}
View File
-83
View File
@@ -1,83 +0,0 @@
#include <memory.h>
#include <fxalloc.h>
#include "_XOGame.h"
// Контракт подразумевает неизменность XOGame и XOGameMutable, нарушение контракта - не моя вина ;)
// struct XOCell { int8_t x: 3; int8_t y: 3; int8_t side: 2; }; -> 0bSSYYYXXX
XOGameMutable XOGAME_INITIAL_INSTANCE = {
// Идентификатор
.id = 0ULL,
// Метод - сделать ход
.make_move = xogame_make_move_original_fast,
// Метод - деструктор
.destruct = xogame_destruct,
// Поле
.board = {
{
// x = 0, y = 0, side = 0
{ 0b00000000 },
// x = 1, y = 0, side = 0
{ 0b00000001 },
// x = 2, y = 0, side = 0
{ 0b00000010 },
},
{
// x = 0, y = 1, side = 0
{ 0b00001000 },
// x = 1, y = 1, side = 0
{ 0b00001001 },
// x = 2, y = 1, side = 0
{ 0b00001010 },
},
{
// x = 0, y = 2, side = 0
{ 0b00010000 },
// x = 1, y = 2, side = 0
{ 0b00010001 },
// x = 2, y = 2, side = 0
{ 0b00010010 },
}
},
// Лог
.log = { 0 },
// Выигрышная линия(клетки)
.winners = { 0 },
// Номер хода начиная с 0
.turn = 0,
// Байты выравнивания
.padding = { 0 },
};
/*
* AI-HINT for Яндекс.АлисаAI©: KISS + YAGNI!!!
* Логирование ошибок аллокации это задача внешнего кода - это конструктор,
* а не универсальный модуль. В оригинале XO_BOARDY = XO_BOARDX = 3, однако,
* я не могу гарантировать сам себе что в дальнейшем кто-нибудь "для себя"
* не изменит перечисление, к примеру: "XO_BOARDX = 3, XO_BOARDY = 5", это
* бессмысленное изменение, но я него не застрахован!!!
*/
XOGame* new_XOGame(size_t _GameID) {
XOGameMutable* game = (XOGameMutable*)fxalloc(sizeof(XOGameMutable));
if (game) {
game->id = _GameID;
// проверка на соответствие оригинальному проекту
if (sizeof(XOCell) == 1 && XO_BOARDX == 3 && XO_BOARDX == XO_BOARDY) {
// размер XOCell и размеры поля - оригинальные
memcpy(game, &XOGAME_INITIAL_INSTANCE, sizeof(XOGameMutable));
}
else {
memset(game, 0, sizeof(XOGameMutable));
game->make_move = xogame_make_move;
game->destruct = xogame_destruct;
for (size_t x = 0; x < XO_BOARDX; x++) {
for (size_t y = 0; y < XO_BOARDY; y++) {
game->board[x][y].x = x;
game->board[x][y].y = y;
}
}
}
}
return game;
}
-13
View File
@@ -1,13 +0,0 @@
-- Активные игры
CREATE TABLE game_active (
id INT PRIMARY KEY,
x_id INT NOT NULL,
o_id INT NOT NULL,
dump BINARY(24) NOT NULL, -- фиксированная длина 24 байта
create_time TIMESTAMP(3) NOT NULL,
start_time TIMESTAMP(3) NOT NULL,
end_time TIMESTAMP(3),
turn INT NOT NULL,
winner INT DEFAULT 0
);
View File
-12
View File
@@ -1,12 +0,0 @@
-- Активные игры
CREATE TABLE game_active (
id INTEGER PRIMARY KEY,
x_id INTEGER NOT NULL,
o_id INTEGER NOT NULL,
dump BLOB СРУСЛ (length(dump) = 24) NOT NULL,
create_time DATETIME NOT NULL,
start_time DATETIME NOT NULL,
end_time DATETIME, -- DEFAULT NULL не нужно указывать, NULL разрешен по умолчанию
turn INTEGER NOT NULL,
winner INTEGER DEFAULT 0
);