Files
algorithm/lab1/report/report.tex

450 lines
25 KiB
TeX
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

\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}{Введение}
Данная лабораторная работа по дисциплине <<Теория алгоритмов>> заключается в разработке консольного приложения на языке C++, которое позволяет создавать и запускать двумерные клеточные автоматы с различными настройками и функцией переходов, заданной вариантом лабораторной работы. Также в этом отчёте к лабораторной работе проводится анализ заданного клеточного автомата.
\newpage
\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}