From 018235e02b8dd16d56102d741c224c75f390760f Mon Sep 17 00:00:00 2001 From: Arity-T Date: Thu, 5 Dec 2024 14:12:22 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9E=D0=BF=D0=B8=D1=81=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D0=B5=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81=D0=B0=20CellularAutomat?= =?UTF-8?q?on?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lab1/report/report.tex | 207 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 203 insertions(+), 4 deletions(-) diff --git a/lab1/report/report.tex b/lab1/report/report.tex index c55de64..2e1eaee 100644 --- a/lab1/report/report.tex +++ b/lab1/report/report.tex @@ -144,6 +144,209 @@ \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 > m\_field} -- двумерный вектор, представляющий текущее состояние клеточного автомата; + \item \texttt{std::vector > 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> m_field; + std::vector> 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(m_fieldWidth, 0)); + m_fieldNextState.resize(m_fieldHeight, std::vector(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} + \subsection{Пользовательский ввод} Одним из требований к лабораторным работам являлась защита от некорректного пользовательского ввода. Для реализации такой защиты и большей читаемости кода все функции связанные с пользовательским вводом были вынесены в отдельный файл. Все функции проверяют данные вводимые пользователем и, если что-то не так, печатают информацию о неверном выводе. @@ -153,10 +356,6 @@ \item {\tt bool userApprove()} - возвращает true, если пользователь ввёл <> или <> и false, если пользователь ввёл <> или <>. \item {\tt void waitForEnter()} - останавливает выполнение программы пока пользователь не нажмёт на клавишу <>. \end{itemize} - - - - \subsection{Функция main} \newpage