Описание класса CellularAutomaton

This commit is contained in:
2024-12-05 14:12:22 +03:00
parent 3d8453bdf7
commit 018235e02b

View File

@@ -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<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}
\subsection{Пользовательский ввод}
Одним из требований к лабораторным работам являлась защита от некорректного пользовательского ввода. Для реализации такой защиты и большей читаемости кода все функции связанные с пользовательским вводом были вынесены в отдельный файл. Все функции проверяют данные вводимые пользователем и, если что-то не так, печатают информацию о неверном выводе.
@@ -153,10 +356,6 @@
\item {\tt bool userApprove()} - возвращает true, если пользователь ввёл <<yes>> или <<y>> и false, если пользователь ввёл <<no>> или <<n>>.
\item {\tt void waitForEnter()} - останавливает выполнение программы пока пользователь не нажмёт на клавишу <<Enter>>.
\end{itemize}
\subsection{Функция main}
\newpage