\documentclass[a4paper, final]{article}
%\usepackage{literat} % Нормальные шрифты
\usepackage[14pt]{extsizes} % для того чтобы задать нестандартный 14-ый размер шрифта
\usepackage[T2A]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[russian]{babel}
\usepackage{amsmath}
\usepackage[left=25mm, top=20mm, right=20mm, bottom=20mm, footskip=10mm]{geometry}
\usepackage{ragged2e} %для растягивания по ширине
\usepackage{setspace} %для межстрочного интервала
\usepackage{moreverb} %для работы с листингами
\usepackage{indentfirst} % для абзацного отступа
\usepackage{moreverb} %для печати в листинге исходного кода программ
\usepackage{graphicx}

\usepackage{array}
\usepackage{multirow}

\renewcommand\verbatimtabsize{4\relax}
\renewcommand\listingoffset{0.2em} %отступ от номеров строк в листинге
\renewcommand{\arraystretch}{1.4} % изменяю высоту строки в таблице
\usepackage[font=small, singlelinecheck=false, justification=centering, format=plain, labelsep=period]{caption} %для настройки заголовка таблицы
\usepackage{listings} %листинги
\usepackage{xcolor} % цвета
\usepackage{hyperref}% для гиперссылок
\usepackage{enumitem} %для перечислений
\newtheorem{theorem}{Теорема} % Создание нового окружения для теорем
\setlist[enumerate,itemize]{leftmargin=1.2cm} %отступ в перечислениях

\hypersetup{colorlinks,
    allcolors=[RGB]{010 090 200}} %красивые гиперссылки (не красные)

% подгружаемые языки — подробнее в документации listings (это всё для листингов)
\lstloadlanguages{ C++}
% включаем кириллицу и добавляем кое−какие опции
\lstset{tabsize=2,
    breaklines,
    basicstyle=\footnotesize,
    columns=fullflexible,
    flexiblecolumns,
    numbers=left,
    numberstyle={\footnotesize},
    keywordstyle=\color{blue},
    inputencoding=cp1251,
    extendedchars=true
}
\lstdefinelanguage{MyC}{
    language=C++,
%    ndkeywordstyle=\color{darkgray}\bfseries,
%    identifierstyle=\color{black},
%    morecomment=[n]{/**}{*/},
%    commentstyle=\color{blue}\ttfamily,
%    stringstyle=\color{red}\ttfamily,
%    morestring=[b]",
%    showstringspaces=false,
%    morecomment=[l][\color{gray}]{//},
    keepspaces=true,
    escapechar=\%,
    texcl=true
}

\textheight=24cm % высота текста
\textwidth=16cm % ширина текста
\oddsidemargin=0pt % отступ от левого края
\topmargin=-1.5cm % отступ от верхнего края
\parindent=24pt % абзацный отступ
\parskip=5pt % интервал между абзацами
\tolerance=2000 % терпимость к "жидким" строкам
\flushbottom % выравнивание высоты страниц


% Настройка листингов
\lstset{
    language=C++,
    extendedchars=\true,
    inputencoding=utf8,
    keepspaces=true,
    % captionpos=b,
}

\begin{document} % начало документа
    
    % НАЧАЛО ТИТУЛЬНОГО ЛИСТА
    \begin{center}
        \hfill \break
        \hfill \break
        \normalsize{МИНИСТЕРСТВО НАУКИ И ВЫСШЕГО ОБРАЗОВАНИЯ РОССИЙСКОЙ ФЕДЕРАЦИИ\\
            федеральное государственное автономное образовательное учреждение высшего образования «Санкт-Петербургский политехнический университет Петра Великого»\\[10pt]}
        \normalsize{Институт компьютерных наук и кибербезопасности}\\[10pt] 
        \normalsize{Высшая школа технологий искусственного интеллекта}\\[10pt] 
        \normalsize{Направление: 02.03.01 <<Математика и компьютерные науки>>}\\
        
        \hfill \break
        \hfill \break
        \hfill \break
        \hfill \break
        \large{Отчет по лабораторной работе №1}\\
        \large{<<Реализация двумерного клеточного автомата>>}\\
        \large{по дисциплине <<Теория алгоритмов>>}\\
        \large{Вариант 25}\\
        
        \hfill \break
        \hfill \break
    \end{center}
    
    \small{ 
        \begin{tabular}{lrrl}
            \!\!\!Студент, & \hspace{2cm} & & \\
            \!\!\!группы 5130201/20102 & \hspace{2cm} & \underline{\hspace{3cm}} &Тищенко А. А. \\\\
            \!\!\!Преподаватель & \hspace{2cm} &  \underline{\hspace{3cm}} &  Востров А. В. \\\\
            &&\hspace{4cm}
        \end{tabular}
        \begin{flushright}
            <<\underline{\hspace{1cm}}>>\underline{\hspace{2.5cm}} 2024г.
        \end{flushright}
    }
    
    \hfill \break
    % \hfill \break
    \begin{center} \small{Санкт-Петербург, 2024} \end{center}
    \thispagestyle{empty} % выключаем отображение номера для этой страницы
    
    % КОНЕЦ ТИТУЛЬНОГО ЛИСТА
    \newpage
    
    \tableofcontents
    
    \newpage
    
    \section*{Введение}
    \addcontentsline{toc}{section}{Введение}
    Лабораторная работа заключалась в следующем:

    \begin{itemize}
        \item Реализовать двумерный клеточный автомат с окрестностью фон Неймана в соответствии с полученным номером (№109063350), который задаёт функцию перехода автомата.
        \item Предложить самостоятельно граничные условия (тороидальные, нулевые, единичные).
        \item Обеспечить возможность пользователю задавать ширину поля и количество итераций.
        \item Учесть возможность ввода различных начальных условий (как вручную, так и случайным образом) по выбору пользователя.
        \item Реализовать автомат в консольном или графическом интерфейсе.
        \item Проанализировать поведение клеточного автомата, выявить паттерны, оценить "сходимость" и другие характеристики в отчете.
    \end{itemize}

    \newpage
    
    \section {Математическое описание}


    \newpage
\section{Особенности реализации}
\subsection{Класс CellularAutomaton}
В листинге~\ref{lst:CellularAutomaton} представлен код объявления класса \texttt{CellularAutomaton}.

Класс содержит следующие атрибуты:
\begin{itemize}
    \item \texttt{static const unsigned int m\_functionValues} -- хранит число, соответствующее номеру варианта лабораторной работы, его битовое представление соответствует функции переходов двумерного клеточного автомата;
    \item \texttt{int m\_fieldWidth} -- ширина поля клеточного автомата;
    \item \texttt{int m\_fieldHeight} -- высота поля клеточного автомата;
    \item \texttt{std::vector<std::vector<int> > m\_field} -- двумерный вектор, представляющий текущее состояние клеточного автомата;
    \item \texttt{std::vector<std::vector<int> > m\_fieldNextState} -- двумерный вектор для хранения следующего состояния клеточного автомата;
    \item \texttt{BoundaryCondition m\_boundaryCondition} -- граничные условия, задаются значением из перечисления \texttt{BoundaryCondition}.
\end{itemize}

Перечисление \texttt{BoundaryCondition} имеет три возможных значения:
\begin{itemize}
    \item \texttt{BOUNDARY\_ONES} -- единичные граничные условия;
    \item \texttt{BOUNDARY\_ZEROS} -- нулевые граничные условия;
    \item \texttt{BOUNDARY\_TOROIDAL} -- тороидальные граничные условия.
\end{itemize}

Методы класса описываются в последующих разделах.

\begin{lstlisting}[caption={Код объявления класса CellularAutomaton.}, label={lst:CellularAutomaton}]
enum BoundaryCondition {
    BOUNDARY_ONES,
    BOUNDARY_ZEROS,
    BOUNDARY_TOROIDAL
};

class CellularAutomaton
{
    static const unsigned int m_functionValues = 25 * 11 * 2003 * 18 * 11;

    int m_fieldWidth, m_fieldHeight;
    std::vector<std::vector<int>> m_field;
    std::vector<std::vector<int>> m_fieldNextState;
    BoundaryCondition m_boundaryCondition;

    void initializeRandom();
    void initializeManual();

    int getCellState(int x, int y) const;
    int getNeighborhoodIndex(int x, int y) const;
public:
    CellularAutomaton(int width, int height, bool fillWithRandom, BoundaryCondition boundaryCondition);
    
    void update();
    void displayField() const;
};   
\end{lstlisting}

\subsubsection{Конструктор CellularAutomaton}

Конструктор класса CellularAutomaton, код которого представлен в листиге~\ref{lst:CellularAutomatonConstructor}, принимает следующие параметры:
\begin{itemize}
    \item \texttt{int width} -- ширина поля клеточного автомата;
    \item \texttt{int height} -- высота поля клеточного автомата;
    \item \texttt{bool fillWithRandom} -- флаг, определяющий, инициализировать ли поле случайными значениями;
    \item \texttt{BoundaryCondition boundaryCondition} -- условие на границе поля.
\end{itemize}

Конструктор создает объект \texttt{CellularAutomaton} с заданными размерами и граничными условиями. Если \texttt{fillWithRandom} равно \texttt{true}, то поле инициализируется случайным образом с помощью метода \texttt{initializeRandom}, иначе пользователь может вручную ввести начальное состояние с помощью метода \texttt{initializeManual}.

\begin{lstlisting}[caption={Код конструктора CellularAutomaton.}, label={lst:CellularAutomatonConstructor}]
CellularAutomaton::CellularAutomaton(int width, int height, bool fillWithRandom, BoundaryCondition boundaryCondition)
    : m_fieldWidth(width), m_fieldHeight(height), m_boundaryCondition(boundaryCondition)
{
    m_field.resize(m_fieldHeight, std::vector<int>(m_fieldWidth, 0));
    m_fieldNextState.resize(m_fieldHeight, std::vector<int>(m_fieldWidth, 0));

    if (fillWithRandom) initializeRandom();
    else initializeManual();
}
\end{lstlisting}

\subsubsection{Метод initializeRandom}
В листинге~\ref{lst:initializeRandom} представлен код метода \texttt{initializeRandom}. Метод явно ничего не принимает и не возвращает, а работает только с атрибутами класса \texttt{CellularAutomaton}. В результате его работы атрибут \texttt{m\_field} заполняется нулями и единицами случайным образом, для этого используется равномерное распределение.

\begin{lstlisting}[caption={Код метода initializeRandom.}, label={lst:initializeRandom}]
void CellularAutomaton::initializeRandom()
{
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<> dis(0, 1);

    for (int y = 0; y < m_fieldHeight; ++y)
    {
        for (int x = 0; x < m_fieldWidth; ++x)
        {
            m_field[y][x] = dis(gen);
        }
    }
}
\end{lstlisting}    

\subsubsection{Метод initializeManual}
В листинге~\ref{lst:initializeManual} представлен код метода \texttt{initializeManual}. Метод не принимает аргументов и ничего не возвращает. Он позволяет пользователю вручную ввести начальное состояние поля клеточного автомата. Для каждой клетки запрашивается значение 0 или 1, которые сохраняются в атрибуте \texttt{m\_field}.

\begin{lstlisting}[caption={Код метода initializeManual.}, label={lst:initializeManual}]
void CellularAutomaton::initializeManual()
{
    std::cout << "Введите начальное состояние поля (" << m_fieldWidth << " x " << m_fieldHeight << ").\n";
    std::cout << "Введите 0 или 1 для каждой клетки.\n";

    for (int y = 0; y < m_fieldHeight; ++y)
    {
        for (int x = 0; x < m_fieldWidth; ++x)
        {
            std::cout << "Клетка (" << x << ", " << y << "): ";
            int cellValue = inputNumber(0, 1);

            m_field[y][x] = cellValue;
        }
    }
}
\end{lstlisting}
    
\subsubsection{Метод getCellState}
В листинге~\ref{lst:getCellState} представлен код метода \texttt{getCellState}. Метод принимает на вход координаты клетки \texttt{int x} и \texttt{int y}. Возвращает \texttt{int} -- состояние клетки по указанным координатам. Если координаты выходят за пределы поля, то поведение определяется граничными условиями, заданными атрибутом \texttt{m\_boundaryCondition}. 

\begin{lstlisting}[caption={Код метода getCellState.}, label={lst:getCellState}]
int CellularAutomaton::getCellState(int x, int y) const
{
    if (x < 0 || x >= m_fieldWidth || y < 0 || y >= m_fieldHeight)
    {
        switch (m_boundaryCondition)
        {
        case BOUNDARY_ONES:
            return 1;
        case BOUNDARY_ZEROS:
            return 0;
        case BOUNDARY_TOROIDAL:
            x = (x + m_fieldWidth) % m_fieldWidth;
            y = (y + m_fieldHeight) % m_fieldHeight;
            return m_field[y][x];
        default:
            return 0;
        }
    }
    return m_field[y][x];
}
\end{lstlisting}

\subsubsection{Метод getNeighborhoodIndex}
В листинге~\ref{lst:getNeighborhoodIndex} представлен код метода \texttt{getNeighborhoodIndex}. Метод принимает на вход координаты клетки \texttt{int x} и \texttt{int y}. Возвращает \texttt{int} -- индекс конфигурации окрестности фон Неймана клетки. Индекс вычисляется на основе состояний центральной клетки и её четырёх соседей (сверху, снизу, слева и справа), где каждый сосед соответствует одному биту в индексе. Этот индекс используется для определения следующего состояния клетки по функции переходов в методе \texttt{update}.

\begin{lstlisting}[caption={Код метода getNeighborhoodIndex.}, label={lst:getNeighborhoodIndex}]
int CellularAutomaton::getNeighborhoodIndex(int x, int y) const
{
    int s0 = getCellState(x, y);
    int s1 = getCellState(x, y - 1);
    int s2 = getCellState(x, y + 1);
    int s3 = getCellState(x - 1, y);
    int s4 = getCellState(x + 1, y);

    int index = (s0 << 4) | (s1 << 3) | (s2 << 2) | (s3 << 1) | s4;

    return index;
}
\end{lstlisting}

\subsubsection{Метод update}
В листинге~\ref{lst:update} представлен код метода \texttt{update}. Метод не принимает аргументов и ничего не возвращает. Он обновляет состояние клеточного автомата на следующий временной шаг. Для каждой клетки вычисляется новое состояние на основе текущего состояния и функции переходов, значения которой хранятся в битах числа \texttt{m\_functionValues}. После вычисления новое состояние сохраняется в \texttt{m\_fieldNextState}, а затем происходит обмен содержимого \texttt{m\_field} и \texttt{m\_fieldNextState}.

\begin{lstlisting}[caption={Код метода update.}, label={lst:update}]
void CellularAutomaton::update()
{
    for (int y = 0; y < m_fieldHeight; ++y)
    {
        for (int x = 0; x < m_fieldWidth; ++x)
        {
            int neighborhood = getNeighborhoodIndex(x, y);
            m_fieldNextState[y][x] = (m_functionValues >> neighborhood) & 1;
        }
    }

    m_field.swap(m_fieldNextState);
}
\end{lstlisting}

\subsubsection{Метод displayField}
В листинге~\ref{lst:displayField} представлен код метода \texttt{displayField}. Метод не принимает аргументов и ничего не возвращает. Он выводит текущее состояние поля клеточного автомата в консоль, отображая каждую клетку как '0' или '1'.

\begin{lstlisting}[caption={Код метода displayField.}, label={lst:displayField}]
void CellularAutomaton::displayField() const
{
    for (const auto& row : m_field)
    {
        for (const auto& cell : row)
        {
            std::cout << (cell ? '1' : '0') << ' ';
        }
        std::cout << '\n';
    }
}
\end{lstlisting}


    \subsection{Функция main}
    В функции main, код которой представлен в листинге~\ref{lst:main}, содержится бесконечный цикл, который обрабатывает пользовательский ввод. На каждой итерации цикла, пользователю предлагается выбрать конфигурацию конечного двумерного автомата и количество итераций. Затем внутри функции создаётся объект класса \texttt{CellularAutomaton}, с заданными пользователем параметрами, и у него вызывается метод \texttt{update} согласно указанному количеству итераций. Функция \texttt{main} возвращает целое число, которое является кодом завершения программы - 0, если программа выполнилась успешно, и ненулевое значение, если произошла какая-либо ошибка.


\begin{lstlisting}[caption={Код функции main.}, label={lst:main}]
int main()
{
    setlocale(LC_ALL, "Russian");

    while (true) {
        clear();

        cout << "Выберите граничные условия:\n"
            "Единичные (0)\n"
            "Нулевые (1)\n"
            "Торроидальные (2)\n"
            "Завершить работу (3)\n\n";
        int actionId = inputNumber(0, 3);

        clear();

        if (actionId == 3) {
            cout << "Выйти из программы? (yes/no)\n";
            if (userApprove()) return 0;
            continue;
        }

        BoundaryCondition boundaryCondition = static_cast<BoundaryCondition>(actionId);

        cout << "Укажите ширину поля (min 1): ";
        int fieldWidth = inputNumber(1);

        cout << "Укажите высоту поля (min 1): ";
        int fieldHeight = inputNumber(1);

        cout << "Укажите количество итераций (min 1): ";
        int iterationsCount = inputNumber(1);

        cout << "Заполнить поле случайными значениями? (yes/no)\n";
        bool fillWithRandom = userApprove();

        CellularAutomaton ca(fieldWidth, fieldHeight, fillWithRandom, boundaryCondition);
        clear();

        cout << "\nИтерация 0:\n";
        ca.displayField();

        for (int i = 0; i < iterationsCount; ++i)
        {
            cout << "\nИтерация " << i + 1 << ":\n";
            ca.update();
            ca.displayField();
        }

        cout << "\nНажмите на enter, чтобы продолжить...";
        waitForEnter();
    }
}
\end{lstlisting}

    \subsection{Пользовательский ввод}
    Одним из требований к лабораторным работам являлась защита от некорректного пользовательского ввода. Для реализации такой защиты и большей читаемости кода все функции связанные с пользовательским вводом были вынесены в отдельный файл. Все функции проверяют данные вводимые пользователем и, если что-то не так, печатают информацию о неверном выводе.

    \begin{itemize}
        \item {\tt int inputNumber(int minVal, int maxVal)} - принимает два числа, которые указывают диапозон возможных для ввода значений. Возвращает введённое пользователем число.
        \item {\tt char* inputString(int maxLen)} - принимает число, максимальную длину строки, возвращает указатель на строку введённую пользователем. Не позволяет вводить строки больше указанной длины.
        \item {\tt bool userApprove()} - возвращает true, если пользователь ввёл <<yes>> или <<y>> и false, если пользователь ввёл <<no>> или <<n>>.
        \item {\tt void waitForEnter()} - останавливает выполнение программы пока пользователь не нажмёт на клавишу <<Enter>>.
    \end{itemize}
    

    \newpage
    \section {Результаты работы программы}

    В данном разделе представлены скриншоты с примерами ввода-вывода, демонстрирующие работу программы и её основной функционал.

    На Рис.~\ref{fig:menu1} показано основное меню программы, в котором перечислены доступные пользователю действия.


    \newpage
    \section*{Заключение}
    
    \addcontentsline{toc}{section}{Заключение}
    
    В результате выполнения лабораторной работы было разработано консольное приложение, ...


    \newpage
    \section*{Список литературы}
    \addcontentsline{toc}{section}{Список литературы}
    
    \vspace{-1.5cm}
    \begin{thebibliography}{0}
        \bibitem{vostrov}
        Востров А. В, <<Теория алгоритмов>> URL: \url{https://tema.spbstu.ru/algorithm/}, Дата обращения: 01.12.2024
        \bibitem{novikov}
        Новиков, Ф. А. <<Дискретная математика для программистов>>. — 3-е изд. — Санкт-Петербург: Питер, 2009. — 383 с.
    \end{thebibliography}
\end{document}