Загрузка данных


#define _CRT_SECURE_NO_WARNINGS
#include "Header.h"

// ========== ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ ==========
void SetCursorPosition(short row, short col) {
    HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
    COORD position = { col, row };
    SetConsoleCursorPosition(hStdOut, position);
}

COORD GetCursorPosition() {
    CONSOLE_SCREEN_BUFFER_INFO csbi;
    GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
    return csbi.dwCursorPosition;
}

void info() {
    cout << "Зажигин А.К. группа 1бИВТн5 вариант 9\n\n";
}

void SetColor(int text, int bg) {
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), (bg << 4) | text);
}

// Вспомогательная функция для вывода double с запятой вместо точки
void PrintDouble(double val) {
    string s = to_string(val);
    // Убираем лишние нули на конце
    s.erase(s.find_last_not_of('0') + 1, string::npos);
    if (s.back() == '.') s.pop_back();
    // Заменяем точку на запятую
    for (char& c : s) if (c == '.') c = ',';
    cout << s;
}

// ========== ФУНКЦИИ ВВОДА С ESC ==========
bool ReadStringWithESC(string& out) {
    out.clear();
    while (true) {
        if (_kbhit()) {
            int ch = _getch();
            if (ch == 27) {
                cout << "\n\n[ESC] Возврат в меню...\n";
                system("pause");
                return false;
            }
            if (ch == 13) {
                cout << '\n';
                return true;
            }
            if (ch == 8) {
                if (!out.empty()) {
                    out.pop_back();
                    cout << "\b \b";
                }
            }
            else if (ch == 0 || ch == 224) (void)_getch();
            else if ((ch >= 32 && ch <= 126) || (ch >= 128 && ch <= 255)) {
                out += static_cast<char>(ch);
                cout << static_cast<char>(ch);
            }
        }
    }
}

bool ReadIntWithESC(int& val) {
    string s;
    COORD errorPos = { 0, 0 };
    bool errorShown = false;

    while (true) {
        if (!ReadStringWithESC(s)) return false;
        if (s.empty()) continue;

        bool valid = true;
        size_t start = 0;
        if (s[0] == '-') {
            if (s.length() == 1) valid = false;
            else start = 1;
        }
        for (size_t i = start; i < s.length(); i++) {
            if (!isdigit(static_cast<unsigned char>(s[i]))) {
                valid = false;
                break;
            }
        }

        if (!valid) {
            if (!errorShown) {
                cout << endl;
                errorPos = GetCursorPosition();
                errorShown = true;
            }
            SetCursorPosition(errorPos.Y, errorPos.X);
            SPACEBACK(50);
            cout << "Ошибка! Введите целое число: ";
            s.clear();
            continue;
        }

        try {
            val = stoi(s);
            return true;
        }
        catch (...) {
            if (!errorShown) {
                cout << endl;
                errorPos = GetCursorPosition();
                errorShown = true;
            }
            SetCursorPosition(errorPos.Y, errorPos.X);
            SPACEBACK(50);
            cout << "Ошибка! Введите целое число: ";
            s.clear();
        }
    }
}

bool ReadDoubleWithESC(double& val) {
    std::string s;
    COORD errorPos = { 0, 0 };
    bool errorShown = false;

    while (true) {
        if (!ReadStringWithESC(s)) return false;
        if (s.empty()) continue;

        try {
            for (char& c : s) if (c == '.') c = ',';
            size_t pos = 0;
            val = std::stod(s, &pos);
            if (pos != s.length()) throw std::invalid_argument("Trailing characters");
            return true;
        }
        catch (...) {
            if (!errorShown) {
                cout << endl;
                errorPos = GetCursorPosition();
                errorShown = true;
            }
            SetCursorPosition(errorPos.Y, errorPos.X);
            SPACEBACK(50);
            cout << "Ошибка! Введите число: ";
            s.clear();
        }
    }
}

// ========== ЛАБОРАТОРНАЯ РАБОТА 1 (СТАТИЧЕСКИЙ МАССИВ) ==========
int Lab1_Static() {
    system("cls");
    info();
    SetColor(11, 0);
    cout << "===============================================================================\n";
    cout << "Лабораторная работа №1 (Статический массив)\n";
    cout << "===============================================================================\n";
    SetColor(7, 0);
    cout << "Задача: Задан массив x1, x2, ..., x15 (15 элементов).\n";
    cout << "        Определить номер первого отрицательного xi и номер последнего\n";
    cout << "        отрицательного xi.\n";
    cout << "        Допускается ввод чисел с плавающей точкой и в научном формате (например, 1e5).\n";
    cout << "===============================================================================\n\n";
    SetColor(7, 0);

    const int SIZE = 15;
    double arr[SIZE];
    cout << "Введите 15 чисел:\n";
    COORD coord = GetCursorPosition();

    for (int i = 0; i < SIZE; i++) {
        SetCursorPosition(coord.Y, coord.X);
        SPACEBACK(50);
        cout << "x[" << i + 1 << "] = ";
        if (!ReadDoubleWithESC(arr[i])) return 0;
    }

    cout << "\nВведённые числа: ";
    for (int i = 0; i < SIZE; i++) {
        PrintDouble(arr[i]);
        cout << " ";
    }
    cout << endl;

    int firstNeg = -1;
    for (int i = 0; i < SIZE; i++) {
        if (arr[i] < 0) {
            firstNeg = i + 1;
            break;
        }
    }

    int lastNeg = -1;
    for (int i = SIZE - 1; i >= 0; i--) {
        if (arr[i] < 0) {
            lastNeg = i + 1;
            break;
        }
    }

    if (firstNeg == -1) {
        cout << "\nВ массиве нет отрицательных чисел.\n";
    }
    else {
        cout << "\nНомер первого отрицательного: " << firstNeg << endl;
        cout << "Номер последнего отрицательного: " << lastNeg << endl;
    }

    cout << "\nНажмите любую клавишу для возврата в меню...";
    (void)_getch();
    return 0;
}

// ========== ЛАБОРАТОРНАЯ РАБОТА 2 (ДИНАМИЧЕСКИЙ МАССИВ) ==========
int Lab2_Dynamic() {
    system("cls");
    info();
    SetColor(11, 0);
    cout << "===============================================================================\n";
    cout << "Лабораторная работа №2 (Динамический массив)\n";
    cout << "===============================================================================\n";
    SetColor(7, 0);
    cout << "Задача: Задан массив x1, x2, ..., xN (размер N вводит пользователь).\n";
    cout << "        Определить номер первого отрицательного xi и номер последнего\n";
    cout << "        отрицательного xi.\n";
    cout << "        Допускается ввод чисел с плавающей точкой и в научном формате.\n";
    cout << "===============================================================================\n\n";
    SetColor(7, 0);

    int N;
    cout << "Введите количество элементов массива N: ";
    if (!ReadIntWithESC(N) || N <= 0) return 0;

    double* arr = new double[N];
    cout << "Введите " << N << " чисел:\n";
    COORD coord = GetCursorPosition();
    for (int i = 0; i < N; i++) {
        SetCursorPosition(coord.Y, coord.X);
        SPACEBACK(50);
        cout << "x[" << i + 1 << "] = ";
        if (!ReadDoubleWithESC(arr[i])) { delete[] arr; return 0; }
    }

    cout << "\nВведённые числа: ";
    for (int i = 0; i < N; i++) {
        PrintDouble(arr[i]);
        cout << " ";
    }
    cout << endl;

    int firstNeg = -1;
    for (int i = 0; i < N; i++) {
        if (arr[i] < 0) {
            firstNeg = i + 1;
            break;
        }
    }

    int lastNeg = -1;
    for (int i = N - 1; i >= 0; i--) {
        if (arr[i] < 0) {
            lastNeg = i + 1;
            break;
        }
    }

    if (firstNeg == -1) {
        cout << "\nВ массиве нет отрицательных чисел.\n";
    }
    else {
        cout << "\nНомер первого отрицательного: " << firstNeg << endl;
        cout << "Номер последнего отрицательного: " << lastNeg << endl;
    }

    delete[] arr;
    cout << "\nНажмите любую клавишу для возврата в меню...";
    (void)_getch();
    return 0;
}

// ========== ЛАБОРАТОРНАЯ РАБОТА 3 (ФАЙЛОВЫЙ ВВОД) ==========
int Lab3_File() {
    system("cls");
    info();
    SetColor(11, 0);
    cout << "===============================================================================\n";
    cout << "Лабораторная работа №3 (Файловый ввод)\n";
    cout << "===============================================================================\n";
    SetColor(7, 0);
    cout << "Задача: Прочитать из файла массив чисел. Определить номер первого\n";
    cout << "        отрицательного элемента и номер последнего отрицательного.\n";
    cout << "        Допустимы целые, вещественные числа и научная нотация.\n";
    cout << "===============================================================================\n\n";
    SetColor(7, 0);

    string path;
    cout << "Введите название файла (например, data.txt). Для выхода введите \"*\": ";
    cin.clear();
    cin.ignore(cin.rdbuf()->in_avail());
    getline(cin, path);
    if (path == "*") return 0;

    ifstream fs(path);
    if (!fs.is_open()) {
        cout << "\nОшибка открытия файла \"" << path << "\"\n";
        cerr << "Детали ошибки: " << strerror(errno) << " (код " << errno << ")" << endl;
        system("pause");
        return 1;
    }
    cout << "Файл открыт.\n\n";

    string token;
    int count = 0;
    streampos errorPos = 0;
    bool error = false;
    string badToken;

    while (fs >> token) {
        count++;
        size_t pos = 0;
        string tmp = token;
        replace(tmp.begin(), tmp.end(), '.', ',');
        try {
            stod(tmp, &pos);
            if (pos != tmp.length()) throw invalid_argument("garbage");
        }
        catch (...) {
            errorPos = fs.tellg();
            if (errorPos >= static_cast<streamoff>(token.length()))
                errorPos -= token.length();
            else
                errorPos = 0;
            badToken = token;
            error = true;
            break;
        }
    }

    if (count == 0 && !error) {
        cout << "Файл пуст.\n";
        system("pause");
        return 1;
    }

    if (error) {
        cout << "Ошибка: некорректные данные в файле.\n";
        cout << "Номер элемента с ошибкой: " << count << endl;
        cout << "Позиция ошибки (байт): " << static_cast<int>(errorPos) << endl;
        cout << "Ошибочная лексема: \"" << badToken << "\"\n";
        system("pause");
        return 1;
    }

    if (count != 15) {
        cout << "Внимание: в файле " << count << " элементов (ожидалось 15).\n";
    }

    double* arr = new (nothrow) double[count];
    if (!arr) {
        cout << "Ошибка выделения памяти.\n";
        system("pause");
        return 1;
    }

    fs.close();
    fs.open(path);
    for (int i = 0; i < count; i++) {
        fs >> token;
        replace(token.begin(), token.end(), '.', ',');
        arr[i] = stod(token);
    }
    fs.close();

    cout << "\nПрочитанные числа:\n";
    for (int i = 0; i < count; i++) {
        cout << "x[" << i + 1 << "] = ";
        PrintDouble(arr[i]);
        cout << endl;
    }

    int firstNeg = -1, lastNeg = -1;
    for (int i = 0; i < count; i++) {
        if (arr[i] < 0) {
            if (firstNeg == -1) firstNeg = i + 1;
            lastNeg = i + 1;
        }
    }

    cout << "\nРезультат:\n";
    if (firstNeg == -1) {
        cout << "Отрицательные элементы отсутствуют.\n";
    }
    else {
        cout << "Номер первого отрицательного: " << firstNeg << endl;
        cout << "Номер последнего отрицательного: " << lastNeg << endl;
    }

    delete[] arr;
    cout << "\nНажмите любую клавишу...";
    (void)_getch();
    return 0;
}

// ========== ЛАБИРИНТ ==========
int Labirint() {
    system("cls");
    info();
    SetColor(11, 0);
    cout << "===============================================================================\n";
    cout << "Игра: Лабиринт 32x32\n";
    cout << "===============================================================================\n";
    SetColor(7, 0);
    cout << "Задача: Пройти лабиринт от старта (верхний левый угол) до выхода (отмечен 'ВХ').\n";
    cout << "        Стены отображаются чёрным цветом, проходы - белым.\n";
    cout << "        Игрок (жук) отображается красным квадратом.\n";
    cout << "===============================================================================\n";
    cout << "Управление:\n";
    cout << "        Стрелки - движение по лабиринту.\n";
    cout << "        F5 - показать/скрыть кратчайший путь до выхода (зелёный цвет).\n";
    cout << "===============================================================================\n\n";
    SetColor(7, 0);

    unsigned int map[32] = {
        0b10111111111111111111111111111111,
        0b10000000000000000000000000000001,
        0b10111111111111111111111111111101,
        0b10000000100000000000001000000001,
        0b10111110101111111111110101111101,
        0b10000010100000000000000101000001,
        0b10111010101110111011101010111011,
        0b10001000100010001000100010001001,
        0b11101011111011101110111110101111,
        0b10001000001000100010000000100001,
        0b10111011101110111011101110111011,
        0b10000010000000100000000001000001,
        0b11111110111111101111111101111111,
        0b10000000100000000000001000000001,
        0b10111111101111111111110111111101,
        0b10000000001000000000000000000001,
        0b11101111111011101110111111101111,
        0b10001000001000100010000000100001,
        0b10111011101110111011101110111011,
        0b10000010000000100000000001000001,
        0b11111110111111101111111101111111,
        0b10000000100000000000001000000001,
        0b10111111101111111111110111111101,
        0b10000000001000000000000000000001,
        0b11101111111011101110111111101111,
        0b10001000001000100010000000100001,
        0b10111011101110111011101110111011,
        0b10000010000000100000000001000001,
        0b11111110111111101111111101111111,
        0b10000000100000000000001000000011,
        0b10111111111111111111111111111111,
        0b10111111111111111111111111111111
    };

    HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
    const int WHITE = 15 << 4;
    const int BLACK = 0;
    const int RED = BACKGROUND_RED | BACKGROUND_INTENSITY;
    const int GREEN = BACKGROUND_GREEN | BACKGROUND_INTENSITY;

    int bugR = 0, bugC = 1;
    int exitR = 31, exitC = 1;

    auto isWall = [&](int r, int c) { return (map[r] >> (31 - c)) & 1; };
    if (isWall(exitR, exitC)) { exitR = 31; exitC = 30; }

    COORD topLeft;
    unsigned int path[32] = { 0 };
    bool pathShown = false;
    bool gameOver = false;
    bool wasActive = true;

    auto redraw = [&]() {
        topLeft = GetCursorPosition();
        for (int r = 0; r < 32; r++) {
            for (int c = 0; c < 32; c++) {
                SetConsoleTextAttribute(h, isWall(r, c) ? BLACK : WHITE);
                cout << "  ";
            }
            cout << endl;
        }
        SetCursorPosition(topLeft.Y + exitR, topLeft.X + exitC * 2);
        SetConsoleTextAttribute(h, WHITE | 10);
        cout << "ВХ";
        SetConsoleTextAttribute(h, 7);
        if (pathShown) {
            for (int r = 0; r < 32; r++) {
                for (int c = 0; c < 32; c++) {
                    if (path[r] & (1 << (31 - c))) {
                        SetConsoleTextAttribute(h, GREEN);
                        SetCursorPosition(topLeft.Y + r, topLeft.X + c * 2);
                        cout << "  ";
                    }
                }
            }
        }
        SetCursorPosition(topLeft.Y + bugR, topLeft.X + bugC * 2);
        SetConsoleTextAttribute(h, RED);
        cout << "  ";
        SetConsoleTextAttribute(h, 7);
    };

    topLeft = GetCursorPosition();
    for (int r = 0; r < 32; r++) {
        for (int c = 0; c < 32; c++) {
            SetConsoleTextAttribute(h, isWall(r, c) ? BLACK : WHITE);
            cout << "  ";
        }
        cout << endl;
    }
    SetCursorPosition(topLeft.Y + exitR, topLeft.X + exitC * 2);
    SetConsoleTextAttribute(h, WHITE | 10);
    cout << "ВХ";
    SetConsoleTextAttribute(h, 7);
    SetCursorPosition(topLeft.Y + bugR, topLeft.X + bugC * 2);
    SetConsoleTextAttribute(h, RED);
    cout << "  ";
    SetConsoleTextAttribute(h, 7);

    while (!gameOver) {
        if (GetConsoleWindow() != GetForegroundWindow()) {
            wasActive = false;
            Sleep(100);
            continue;
        }
        if (!wasActive && GetConsoleWindow() == GetForegroundWindow()) {
            redraw();
            wasActive = true;
        }
        if (!_kbhit()) {
            Sleep(10);
            continue;
        }
        unsigned char key = _getch();
        if (key == 27) return 0;
        if (key == 0) {
            key = _getch();
            if (key == 63) {
                if (!pathShown) {
                    memset(path, 0, sizeof(path));
                    int visited[32][32] = { 0 };
                    int prevR[32][32], prevC[32][32];
                    for (int i = 0; i < 32; i++)
                        for (int j = 0; j < 32; j++)
                            prevR[i][j] = prevC[i][j] = -1;
                    queue<pair<int, int>> q;
                    q.push({ bugR, bugC });
                    visited[bugR][bugC] = 1;
                    bool found = false;
                    while (!q.empty() && !found) {
                        pair<int, int> cur = q.front(); q.pop();
                        int r = cur.first, c = cur.second;
                        int dr[] = { 1,0,-1,0 }, dc[] = { 0,1,0,-1 };
                        for (int i = 0; i < 4; i++) {
                            int nr = r + dr[i], nc = c + dc[i];
                            if (nr >= 0 && nr < 32 && nc >= 0 && nc < 32 && !isWall(nr, nc) && !visited[nr][nc]) {
                                visited[nr][nc] = 1;
                                prevR[nr][nc] = r;
                                prevC[nr][nc] = c;
                                if (nr == exitR && nc == exitC) { found = true; break; }
                                q.push({ nr, nc });
                            }
                        }
                    }
                    if (found) {
                        int r = exitR, c = exitC;
                        while (!(r == bugR && c == bugC)) {
                            path[r] |= 1 << (31 - c);
                            SetConsoleTextAttribute(h, GREEN);
                            SetCursorPosition(topLeft.Y + r, topLeft.X + c * 2);
                            cout << "  ";
                            int pr = prevR[r][c], pc = prevC[r][c];
                            r = pr; c = pc;
                        }
                        path[bugR] |= 1 << (31 - bugC);
                        SetConsoleTextAttribute(h, GREEN);
                        SetCursorPosition(topLeft.Y + bugR, topLeft.X + bugC * 2);
                        cout << "  ";
                    }
                    SetConsoleTextAttribute(h, RED);
                    SetCursorPosition(topLeft.Y + bugR, topLeft.X + bugC * 2);
                    cout << "  ";
                    SetConsoleTextAttribute(h, 7);
                    SetCursorPosition(topLeft.Y + 33, 0);
                    SetConsoleTextAttribute(h, BLACK | 14);
                    cout << (found ? "ПУТЬ НАЙДЕН!          " : "ПУТИ НЕТ.              ");
                    SetConsoleTextAttribute(h, 7);
                    pathShown = found;
                }
                else {
                    for (int r = 0; r < 32; r++)
                        for (int c = 0; c < 32; c++)
                            if (path[r] & (1 << (31 - c))) {
                                SetConsoleTextAttribute(h, WHITE);
                                SetCursorPosition(topLeft.Y + r, topLeft.X + c * 2);
                                cout << "  ";
                            }
                    memset(path, 0, sizeof(path));
                    pathShown = false;
                    SetConsoleTextAttribute(h, RED);
                    SetCursorPosition(topLeft.Y + bugR, topLeft.X + bugC * 2);
                    cout << "  ";
                    SetConsoleTextAttribute(h, 7);
                }
                continue;
            }
        }
        if (key == 224) {
            key = _getch();
            int newR = bugR, newC = bugC;
            switch (key) {
            case 75: newC--; break;
            case 77: newC++; break;
            case 72: newR--; break;
            case 80: newR++; break;
            default: continue;
            }
            if (newR < 0 || newR >= 32 || newC < 0 || newC >= 32 || isWall(newR, newC)) {
                Beep(750, 300);
                continue;
            }
            SetCursorPosition(topLeft.Y + bugR, topLeft.X + bugC * 2);
            if (pathShown && (path[bugR] & (1 << (31 - bugC))))
                SetConsoleTextAttribute(h, GREEN);
            else
                SetConsoleTextAttribute(h, WHITE);
            cout << "  ";
            bugR = newR; bugC = newC;
            SetCursorPosition(topLeft.Y + bugR, topLeft.X + bugC * 2);
            SetConsoleTextAttribute(h, RED);
            cout << "  ";
            if (bugR == exitR && bugC == exitC) {
                SetConsoleTextAttribute(h, BLACK | 14);
                SetCursorPosition(topLeft.Y + 33, 0);
                cout << "ПОЗДРАВЛЯЕМ! ВЫ ВЫШЛИ!";
                Beep(1000, 500);
                gameOver = true;
            }
            SetConsoleTextAttribute(h, 7);
        }
    }
    cout << "\n\nНажмите любую клавишу для возврата в меню...";
    (void)_getch();
    return 0;
}

// ========== МАСКА ==========
int MASKA() {
    system("cls");
    info();
    SetColor(11, 0);
    cout << "===============================================================================\n";
    cout << "Задание: Маска\n";
    cout << "===============================================================================\n";
    SetColor(7, 0);
    cout << "Задача: Задан массив y[1], y[2], ..., y[20].\n";
    cout << "        Определить, какие значения массива соответствуют маске (01010100).\n";
    cout << "===============================================================================\n\n";
    SetColor(7, 0);

    random_device rd;
    mt19937 gen(rd());
    uniform_int_distribution<int> dist(600, 3000);

    int mas[20];
    unsigned short maska = 0x54;

    cout << "Сгенерированные числа:\n";
    for (int i = 0; i < 20; i++) {
        mas[i] = dist(gen);
        cout << "y[" << i + 1 << "] = " << setw(4) << mas[i];
        if ((i + 1) % 5 == 0) cout << endl;
        else cout << "   ";
    }

    cout << "\n\nЧисла, соответствующие маске 0x54 (01010100):\n";
    cout << "------------------------------------------------------------------------------\n";
    bool found = false;
    for (int i = 0; i < 20; i++) {
        if ((mas[i] & maska) == maska) {
            cout << "y[" << i + 1 << "] = " << mas[i]
                << " (dec), 0x" << hex << mas[i] << dec << " (hex), ob"
                << bitset<16>(mas[i]) << " (bin)" << endl;
            found = true;
        }
    }
    if (!found) cout << "Нет чисел, соответствующих маске 0x54.\n";

    cout << "\nНажмите любую клавишу...";
    (void)_getch();
    return 0;
}

// ========== МАКРОСЫ ==========
int Macros() {
    system("cls");
    info();
    ENDL;
    cout << "В данном задании представлено использование макросов, выделяющих старшие и младшие биты числа, а также меняющих старшие и младшие биты местами. Ниже представлены четыре переменные с разными размерами. Их значения даны через \"/\" (сначала значение в десятичной системе счисления, потом в шестнадцатеричной). После этого идет размер переменной и использование на ней макросов:" << endl;
    ENDL;

    const unsigned char B = 230;
    const unsigned short Sh = 15678;
    const unsigned int I = 564872844;
    const unsigned long long LL = 9903331736939477691ULL;

    ENDL;
    cout << "byte: " << dec << static_cast<int>(B) << " / " << hex << static_cast<int>(B) << endl;
    cout << "--"; cout << "Размер byte: " << sizeof(B) << "байт" << endl;
    cout << "Старшие биты: " << hex << Hi(B) << "\n";
    cout << "Младшие биты: " << hex << Lo(B) << "\n";
    cout << "Старшие и младшие биты, поменянные местами: " << hex << Swap(B) << endl;

    ENDL;
    cout << "short: " << dec << Sh << " / " << hex << Sh << endl;
    cout << "--"; cout << "Размер short: " << sizeof(Sh) << "байта" << endl;
    cout << "Старшие биты: " << hex << Hi(Sh) << "\n";
    cout << "Младшие биты: " << hex << Lo(Sh) << "\n";
    cout << "Старшие и младшие биты, поменянные местами: " << hex << Swap(Sh) << endl;

    ENDL;
    cout << "integer: " << dec << I << " / " << hex << I << endl;
    cout << "--"; cout << "Размер integer: " << sizeof(I) << "байта" << endl;
    cout << "Старшие биты: " << hex << Hi(I) << "\n";
    cout << "Младшие биты: " << hex << Lo(I) << "\n";
    cout << "Старшие и младшие биты, поменянные местами: " << hex << Swap(I) << endl;

    ENDL;
    cout << "long long: " << dec << LL << " / " << hex << LL << endl;
    cout << "--"; cout << "Размер long long: " << sizeof(LL) << "байт" << endl;
    cout << "Старшие биты: " << hex << Hi(LL) << "\n";
    cout << "Младшие биты: " << hex << Lo(LL) << "\n";
    cout << "Старшие и младшие биты, поменянные местами: " << hex << Swap(LL) << endl;

    ENDL;
    system("pause");
    return 0;
}

// ========== ШИФРОВАНИЕ ==========
static void Incryption_byte(int len, unsigned char ch, char* txt) {
    unsigned char* p = reinterpret_cast<unsigned char*>(txt);
    for (int i = 0; i < len; i++) {
        p[i] <<= 1;
        if (i < len - 1) {
            p[i] |= (p[i + 1] & 0x80) >> 7;
        }
    }
    p[len - 1] |= (ch >> 7);
    SetColor(10, 0);
    cout << "\n[ГОТОВО] Текст зашифрован побитовым сдвигом.\n";
    SetColor(7, 0);
    cout << "Нажмите любую клавишу...";
    (void)_getch();
}

static void Decryption_byte(int len, unsigned char& ch, char* txt) {
    unsigned char* p = reinterpret_cast<unsigned char*>(txt);
    ch = p[len - 1] & 0x01;
    for (int i = len - 1; i >= 0; i--) {
        p[i] &= 0xFE;
        p[i] >>= 1;
        if (i > 0) {
            p[i] |= (p[i - 1] & 0x01) << 7;
        }
    }
    p[0] |= ch << 7;
    SetColor(10, 0);
    cout << "\n[ГОТОВО] Текст расшифрован побитовым сдвигом.\n";
    SetColor(7, 0);
    cout << "Нажмите любую клавишу...";
    (void)_getch();
}

static void Dynamic_Encrypt(int len, unsigned char ch, char* txt) {
    unsigned char* p = reinterpret_cast<unsigned char*>(txt);
    for (int i = 0; i < len; i++) {
        p[i] = (p[i] + i) % 256;
    }
    SetColor(10, 0);
    cout << "\n[ГОТОВО] Текст зашифрован динамическим сдвигом.\n";
    SetColor(7, 0);
    cout << "Нажмите любую клавишу...";
    (void)_getch();
}

static void Dynamic_Decrypt(int len, unsigned char ch, char* txt) {
    unsigned char* p = reinterpret_cast<unsigned char*>(txt);
    for (int i = 0; i < len; i++) {
        p[i] = (p[i] - i + 256) % 256;
    }
    SetColor(10, 0);
    cout << "\n[ГОТОВО] Текст расшифрован динамическим сдвигом.\n";
    SetColor(7, 0);
    cout << "Нажмите любую клавишу...";
    (void)_getch();
}

static bool Caesar_Encrypt(int len, unsigned char ch, char* txt, int N) {
    if (N == 0) {
        cout << "\nСдвиг равен 0, текст не изменился.\n";
        return false;
    }
    const char* en_up = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    const char* en_lo = "abcdefghijklmnopqrstuvwxyz";
    const char* ru_up = "\xC0\xC1\xC2\xC3\xC4\xC5\xA8\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF";
    const char* ru_lo = "\xE0\xE1\xE2\xE3\xE4\xE5\xB8\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF";

    for (int i = 0; i < len; i++) {
        unsigned char c = static_cast<unsigned char>(txt[i]);
        const char* alpha = nullptr;
        int size = 0;
        const char* pos = nullptr;
        if ((pos = strchr(en_up, c))) { alpha = en_up; size = 26; }
        else if ((pos = strchr(en_lo, c))) { alpha = en_lo; size = 26; }
        else if ((pos = strchr(ru_up, c))) { alpha = ru_up; size = 33; }
        else if ((pos = strchr(ru_lo, c))) { alpha = ru_lo; size = 33; }
        else continue;
        int idx = static_cast<int>(pos - alpha);
        int normN = ((N % size) + size) % size;
        txt[i] = alpha[(idx + normN) % size];
    }
    SetColor(10, 0);
    cout << "\n[ГОТОВО] Текст зашифрован методом Цезаря (сдвиг " << N << ").\n";
    SetColor(7, 0);
    cout << "Нажмите любую клавишу...";
    (void)_getch();
    return true;
}

static bool Caesar_Decrypt(int len, unsigned char ch, char* txt, int N) {
    if (N == 0) {
        cout << "\nСдвиг равен 0, текст не изменился.\n";
        return false;
    }
    const char* en_up = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    const char* en_lo = "abcdefghijklmnopqrstuvwxyz";
    const char* ru_up = "\xC0\xC1\xC2\xC3\xC4\xC5\xA8\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF";
    const char* ru_lo = "\xE0\xE1\xE2\xE3\xE4\xE5\xB8\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF";

    for (int i = 0; i < len; i++) {
        unsigned char c = static_cast<unsigned char>(txt[i]);
        const char* alpha = nullptr;
        int size = 0;
        const char* pos = nullptr;
        if ((pos = strchr(en_up, c))) { alpha = en_up; size = 26; }
        else if ((pos = strchr(en_lo, c))) { alpha = en_lo; size = 26; }
        else if ((pos = strchr(ru_up, c))) { alpha = ru_up; size = 33; }
        else if ((pos = strchr(ru_lo, c))) { alpha = ru_lo; size = 33; }
        else continue;
        int idx = static_cast<int>(pos - alpha);
        int normN = ((N % size) + size) % size;
        txt[i] = alpha[(idx - normN + size) % size];
    }
    SetColor(10, 0);
    cout << "\n[ГОТОВО] Текст расшифрован методом Цезаря (сдвиг " << N << ").\n";
    SetColor(7, 0);
    cout << "Нажмите любую клавишу...";
    (void)_getch();
    return true;
}

int CIPHER() {
    system("cls");
    info();
    SetColor(11, 0);
    cout << "=================== ШИФРОВАНИЕ ТЕКСТА ===================\n";
    SetColor(7, 0);
    cout << "Методы: Цезарь, побитовый сдвиг, динамический сдвиг.\n\n";

    string input;
    cout << "Введите текст (не более 24 символов): ";
    if (!ReadStringWithESC(input)) return 0;

    int len = static_cast<int>(input.length());
    if (len == 0) {
        cout << "Текст пуст!\n";
        system("pause");
        return 1;
    }
    if (len > 24) {
        cout << "Текст слишком длинный, обрезаем до 24 символов.\n";
        input = input.substr(0, 24);
        len = 24;
    }

    char* txt = new char[len + 1];
    memcpy(txt, input.c_str(), len + 1);
    unsigned char ch = static_cast<unsigned char>(txt[0]) & 0x80;

    char choice;
    do {
        system("cls");
        SetColor(15, 0);
        cout << "========== ТЕКУЩИЙ ТЕКСТ ==========\n";
        SetColor(7, 0);
        for (int i = 0; i < len; i++) {
            cout << bitset<8>(static_cast<unsigned char>(txt[i])) << " ";
        }
        cout << "\n";
        SetColor(14, 0);
        cout << "Текст: " << txt << "\n";
        SetColor(7, 0);
        cout << "===================================\n\n";

        SetColor(11, 0); cout << "1. Шифр Цезаря\n";
        SetColor(10, 0); cout << "2. Дешифр Цезаря\n";
        SetColor(11, 0); cout << "3. Побитовый шифр\n";
        SetColor(10, 0); cout << "4. Побитовый дешифр\n";
        SetColor(11, 0); cout << "5. Динамический шифр\n";
        SetColor(10, 0); cout << "6. Динамический дешифр\n";
        SetColor(12, 0); cout << "0. Выход в меню\n";
        SetColor(7, 0);
        cout << "-----------------------------------\n";
        cout << "Выберите действие: ";

        choice = _getch();
        cout << choice << endl;

        switch (choice) {
        case '1': {
            int key;
            cout << "Введите ключ (сдвиг): ";
            if (ReadIntWithESC(key))
                Caesar_Encrypt(len, ch, txt, key);
            break;
        }
        case '2': {
            int key;
            cout << "Введите ключ (сдвиг): ";
            if (ReadIntWithESC(key))
                Caesar_Decrypt(len, ch, txt, key);
            break;
        }
        case '3':
            Incryption_byte(len, ch, txt);
            break;
        case '4':
            Decryption_byte(len, ch, txt);
            break;
        case '5':
            Dynamic_Encrypt(len, ch, txt);
            break;
        case '6':
            Dynamic_Decrypt(len, ch, txt);
            break;
        case '0': break;
        default:
            SetColor(12, 0);
            cout << "\nНеверный выбор. Нажмите любую клавишу...";
            SetColor(7, 0);
            (void)_getch();
        }
    } while (choice != '0' && choice != 27);

    delete[] txt;
    return 0;
}

// ========== ГЛАВНОЕ МЕНЮ ==========
int main() {
    SetConsoleTitle(L"Лабораторная работа");
    setlocale(LC_ALL, "rus");
    SetConsoleCP(1251);
    SetConsoleOutputCP(1251);
    srand(static_cast<unsigned>(time(NULL)));
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    unsigned char ch = 0;
    do {
        system("cls");
        info();
        SetColor(11, 0);
        cout << "===============================================================================\n";
        cout << "                             МЕНЮ ПРОГРАММЫ                                    \n";
        cout << "===============================================================================\n";
        SetColor(7, 0);
        cout << " 1 - Лабораторная работа №1 (Массив x1..x15)\n";
        cout << " 2 - Лабораторная работа №2 (Массив x1..xN)\n";
        cout << " 3 - Лабораторная работа №3 (Файловый ввод)\n";
        cout << " 4 - Игра: Лабиринт 32x32\n";
        cout << " 5 - Задание: Маска (числа 600..3000, поиск по 0x54)\n";
        cout << " 6 - Задание: Макросы Hi, Lo, Swap\n";
        cout << " 7 - Задание: Шифрование (3 метода)\n";
        SetColor(12, 0);
        cout << " ESC - выход из программы\n";
        SetColor(7, 0);
        cout << "===============================================================================\n";
        cout << "Выберите пункт: ";
        ch = _getch();
        cout << ch << endl;

        switch (ch) {
        case '1': Lab1_Static(); break;
        case '2': Lab2_Dynamic(); break;
        case '3': Lab3_File(); break;
        case '4': Labirint(); break;
        case '5': MASKA(); break;
        case '6': Macros(); break;
        case '7': CIPHER(); break;
        case 27: break;
        default: SetColor(12, 0); cout << "Неверный выбор! Нажмите любую клавишу...\n"; SetColor(7, 0); (void)_getch(); break;
        }
    } while (ch != 27);
    return 0;
}