помоги мне написать программу на C++ с применением методов ООП
вот мое тз:
написать программу "матрица"
- пользователь вводит 4 параметра все они могут принимать значения от 1 до 30 
частоту генераций линий, скорость линий, длину линий и флаг режима эпилепсии 
- необходимо предусмотреть ввод в консольном режиме (в cls matrix.exe 3 23 8 Y) и в диалоговом режиме при запуске программы, если через  cls не были переданы все 4 корректных параметра
- обеспечить защиту от дурака

программа должна делать симуляции матрицы
- каждая отдельная линия должна выползать и случайной позиции по вертикали
- движение линии должно осуществляться появлением нового символа справа и затиранием символа слева
- по умолчанию цвет линий зеленый, при включенном режиме эпилепсии у каждой отдельной линии свой цвет
- перед началом симуляции программа должна получать размеры консоли
- для отрисовки линий используй метод implace_back 

•	Общее количество появившихся в секунду линий должно соответствовать заданной частоте появления.
•	Если частота n линий в секунду, то генерируется n случайных временных промежутков в диапазоне от 0 до 1000 миллисекунд (одна секунда). Это определяет, в какой момент времени каждая линия начнёт своё движение. 
•	Например, если сгенерированы промежутки 200 мс, 700 мс и 400 мс, линии начнут двигаться в следующем порядке: первая линия через 200 мс от начала итерации, вторая через 400 мс от начала и третья - через 700 мс.
•	Линии, как и в первой лабораторной, должны «выползать» из-за начальной границы экрана и двигаться до конца экрана.


мне кажется можно сделать классы
Symbol
Line
AppManager
Random
ConsoleUtils

#include <iostream>
#include <vector>
#include <ctime>
#include <cstdlib>
#include <windows.h>
#include <algorithm>
#include <string>

// Class representing a single symbol
class Symbol {
public:
    char value;
    int color;

    Symbol(char c, int col) : value(c), color(col) {}

    char getCharacter() const {
        return value;
    }

    int getColor() const {
        return color;
    }
};

// Class representing a line
class Line {
private:
    int length, consoleWidth, y, position;
    bool epilepsyMode;
    std::vector<Symbol> symbols;

public:
    Line(int length, bool epilepsyMode, int consoleWidth, int y)
        : length(length), epilepsyMode(epilepsyMode), consoleWidth(consoleWidth), y(y), position(-length) {
        // Initialize the line with random characters
        for (int i = 0; i < length; ++i) {
            char randomChar = getRandomCharacter();
            int color = epilepsyMode ? getRandomColor() : 2; // Default color green
            symbols.emplace_back(randomChar, color);
        }
    }

    // Method for moving the line
    void move() {
        // Shift all symbols left
        for (int i = 0; i < length - 1; ++i) {
            symbols[i] = symbols[i + 1];
        }

        // Generate a new symbol at the end of the line
        generateNewSymbol(length - 1);

        // Shift the entire line to the right
        position++;

        // If the line moves out of the screen, reset it to the left
        if (position >= consoleWidth) {
            position = -length;  // Start again from the left
        }
    }

    // Drawing the line on the screen
    void draw(HANDLE hConsole) const {
        COORD cursorPos;

        // Erase the previous symbol on the left (if within console bounds)
        if (position - 1 >= 0 && position - 1 < consoleWidth) {
            cursorPos.X = static_cast<SHORT>(position - 1);
            cursorPos.Y = static_cast<SHORT>(y);
            SetConsoleCursorPosition(hConsole, cursorPos);
            std::cout << " ";
        }

        // Draw the line from the current position
        for (int i = 0; i < length; ++i) {
            if (position + i >= 0 && position + i < consoleWidth) {  // Draw only within the console width
                setColor(getColor(i));
                cursorPos.X = static_cast<SHORT>(position + i);
                cursorPos.Y = static_cast<SHORT>(y);
                SetConsoleCursorPosition(hConsole, cursorPos);
                std::cout << getCharacter(i);
            }
        }
    }

private:
    // Generate a new symbol for the line
    void generateNewSymbol(int index) {
        char newChar = getRandomCharacter();
        int color = epilepsyMode ? getRandomColor() : 2; // Default color green if epilepsy mode is off
        symbols[index] = Symbol(newChar, color); // Replace the symbol at the position
    }

    char getRandomCharacter() const {
        const char characters[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_+[]{}|;':\",.<>?~";
        return characters[rand() % (sizeof(characters) - 1)];
    }

    int getRandomColor() const {
        return 1 + rand() % 15;  // Random color from 1 to 15
    }

    void setColor(int color) const {
        SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color);
    }

    char getCharacter(int index) const {
        if (index >= 0 && index < symbols.size()) {
            return symbols[index].getCharacter();
        }
        return ' ';
    }

    int getColor(int index) const {
        if (index >= 0 && index < symbols.size()) {
            return symbols[index].getColor();
        }
        return 7;  // Default color (gray)
    }
};

// Utility class for managing the console
class ConsoleUtils {
public:
    static void hideCursor() {
        CONSOLE_CURSOR_INFO cursorInfo;
        cursorInfo.dwSize = 1;
        cursorInfo.bVisible = FALSE;
        SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursorInfo);
    }

    static void showCursor() {
        CONSOLE_CURSOR_INFO cursorInfo;
        cursorInfo.dwSize = 1;
        cursorInfo.bVisible = TRUE;
        SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursorInfo);
    }
};

// Main app manager class
class AppManager {
private:
    int frequency, speed, length;
    bool epilepsyMode;
    int consoleWidth, consoleHeight;
    std::vector<Line> lines;

public:
    AppManager(int freq, int spd, int len, bool epilepMode)
        : frequency(freq), speed(spd), length(len), epilepsyMode(epilepMode) {
        // Get console dimensions
        getConsoleDimensions();

        // Initialize lines
        for (int i = 0; i < frequency; ++i) {
            lines.emplace_back(length, epilepsyMode, consoleWidth, i);
        }
    }

    // Run the app
    void run() {
        HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
        DWORD dwOldMode;
        GetConsoleMode(hConsole, &dwOldMode);
        SetConsoleMode(hConsole, dwOldMode & (~ENABLE_QUICK_EDIT_MODE));

        while (true) {
            // Clear screen
            system("cls");

            // Move and draw all lines
            for (auto& line : lines) {
                line.move();
                line.draw(hConsole);
            }

            // Delay for animation
            Sleep(speed);
        }
    }

private:
    // Get console dimensions
    void getConsoleDimensions() {
        CONSOLE_SCREEN_BUFFER_INFO csbi;
        GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
        consoleWidth = csbi.srWindow.Right - csbi.srWindow.Left + 1;
        consoleHeight = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
    }
};

// Function to handle user input
void getInputFromUser(int& frequency, int& speed, int& length, bool& epilepsyMode) {
    do {
        std::cout << "Enter the frequency of line generation (1-30): ";
        std::cin >> frequency;
        std::cout << "Enter the speed of the lines (1-30): ";
        std::cin >> speed;
        std::cout << "Enter the length of the line (1-30): ";
        std::cin >> length;
        std::cout << "Enable epilepsy mode? (Y/N): ";
        char epilep;
        std::cin >> epilep;
        epilepsyMode = (epilep == 'Y' || epilep == 'y');
    } while (frequency < 1 || frequency > 30 || speed < 1 || speed > 30 || length < 1 || length > 30);
}

// Main function
int main(int argc, char* argv[]) {
    srand(static_cast<unsigned>(time(nullptr)));

    int frequency = 0, speed = 0, length = 0;
    bool epilepsyMode = false;

    // Get user input
    getInputFromUser(frequency, speed, length, epilepsyMode);

    ConsoleUtils::hideCursor();

    // Start the app with the given settings
    AppManager app(frequency, speed, length, epilepsyMode);
    app.run();

    ConsoleUtils::showCursor();
    return 0;
}