\documentclass{article} \usepackage{amsmath} \usepackage{algorithm} \usepackage[noend]{algpseudocode} \usepackage{hyperref} \usepackage[utf8]{inputenc} \title{FOP Projektgruppe 175} \author{Steffen Wagner\\ Dennis Weinberger\\ Jonas Süß\\ Joachim Schmidt} \begin{document} \maketitle \tableofcontents \pagebreak \section{Der Graph} \subsection{Bildung der Kanten} Der Algorithmus für die Bildung der Kanten ist eine Version des \href{https://de.wikipedia.org/wiki/Algorithmus_von_Prim}{Algorithmus von Prim}: \begin{algorithm} \caption{Bildung von Kanten}\label{generate} \begin{algorithmic}[1] \Procedure{generateEdges}{} \If{nodes is empty} return \EndIf \State $castle \gets allCastles[0]$ \State $remainingCastles \gets allCastles$ \State $connectedCastles \gets empty$ \Loop \If{$remainingCastles$ is empty} break \EndIf \State connect $castle$ to nearest castle \State remove $castle$ from $remainingCastles$ \State add $castle$ to $connectedCastles$ \EndLoop \ForAll{castle in allCastles} \ForAll{nearCastle in allCastlesInRadius(castle)} \State connect $castle$ to $nearCastle$ \EndFor \EndFor \EndProcedure \end{algorithmic} \end{algorithm} % Erklärung des Algorithmus Der Algorithmus ist in zwei Schritte aufgeteilt: \begin{itemize} \item Minimale Verbindung von allen Burgen \item Ästhetische Verbesserung der Kanten \end{itemize} Die minimale Verbindung aller Burgen erfolgt, indem sichergestellt wird, dass jede Burg mit einer anderen verbunden ist und dass alle Burgen in einer gemeinsamen Verbindung zusammenhängen. Der Algorithmus fängt bei einer bestimmten Start-Burg an und verbindet diese Burg mit der nächstliegenden Burg, die noch nicht verbunden wurde. Daraufhin wird das gleiche mit der nächsten, übernächsten, usw. Burg getan, bis die letzte Burg erreicht wurde. Zu diesem Zeitpunkt sind alle Burgen durch einen Graph verbunden. Die Ästhetische Verbesserung erfolgt, indem alle Burgen im Umkreis einer Burg durch eine Kante verbunden werden. \subsection{Überprüfung der Erreichbarkeit aller Knoten} Der Algorithmus, der prüft, ob alle Knoten erreichbar sind, ist folgender: \begin{algorithm} \caption{Erreichbarkeit aller Knoten}\label{connected} \begin{algorithmic}[1] \Procedure{allNodesConnected}{} \State $\textit{firstNode} \gets \text{first element of }\textit{nodes}$ \State $allVisitedNodes \gets \textit{empty}$ \State $nextVisitNodes \gets empty$ \State $\text{append } firstNode \text{ to } allVisitedNodes$ \State $\text{neighborsOf } firstNode$ \State $\rightarrow \text{filter out all } x \text{ where } allVisitedNodes \text{ contains } x$ \State $\rightarrow \text{append to } nextVisitNodes$ \Loop \If {$nextVisitNodes \text{ is empty}$} break \EndIf \State $\text{append first element of } nextVisitNodes \text{ to } allVisitedNodes$ \State $\text{neighborsOf first element of } nextVisitNodes$ \State $\rightarrow \text{filter out all } x \text{ where } allVisitedNodes \text{ contains } x$ \State $\rightarrow \text{append to } nextVisitNodes$ \State $\text{delete first element of } nextVisitNodes$ \EndLoop \EndProcedure \end{algorithmic} \end{algorithm} Der Algorithmus verwendet zwei unterschiedliche Datentypen: \begin{itemize} \item HashSet wird verwendet, um die bisher besuchten Knoten zu speichern. Eine HashSet hat den Vorteil, dass Elemente nur einmal gespeichert werden können. \item ArrayDeque wird verwendet, um die nächsten Knoten, die besucht werden, zu speichern. \end{itemize} Der Algorithmus sammelt sozusagen alle Knoten, die aufgrund von momentanen Erkenntnissen erreichbar sind, in der ArrayDeque \texttt{nextVisitNodes}. Hingegen sind alle Knoten, die schon erreicht worden sind, in dem HashSet \texttt{allVisitedNodes} gespeichert. Der Algorithmus geht die ArrayDeque \texttt{nextVisitNodes} solange durch, bis diese leer ist. In jeder Iteration wird das erste Element der Liste aus der Liste entfernt. Zunächst wird dieses Element dem HashSet \texttt{allVisitedNodes} hinzugefügt. Daraufhin werden die Nachbarn dieses Elements herausgefunden. Diejenigen Nachbarn, die schon in dem HashSet \texttt{allVisitedNodes} vorhanden sind, werden verworfen. Die restlichen Nachbarn werden der ArrayDeque \texttt{nextVisitNodes} hinzugefügt. \subsection{Wege finden} \subsubsection{Teil (a)} Eine pseudocode-Darstellung des Algorithmus: \begin{algorithm} \caption{Berechnung der Distanzen}\label{path} \begin{algorithmic}[1] \Procedure{run}{} \State $v \gets$ getSmallestNode() \Loop \If{$v$ is null} \Return \EndIf \ForAll{edges} \If{edge is passable} \State $n \gets$ otherNode \State $a \gets$ v.value + edge.value \If{n.value = -1 or n.value > a} \State n.value $\gets$ a \State n.previous $\gets$ v \EndIf \EndIf \EndFor \State $v \gets getSmallestNode()$ \EndLoop \EndProcedure \end{algorithmic} \end{algorithm} Die algorithmische Komplexität im worst-case ist: $$O(n^2)$$ $n$ soll in diesem Fall die Anzahl an Knoten wiedergeben. Da es sich bei \texttt{availableNodes} um eine \texttt{LinkedList>} handelt, muss bei jedem Durchgehen der Liste jedes Element einzeln abgearbeitet werden. In der Funktion \texttt{getSmallestNode()} ist dies der Fall. Das bedeutet, dass bei jeder Aufruf von \texttt{getSmallestNode()} eine Komplexität von $O(n)$ hat, wenn $n$ die Anzahl der Knoten darstellt. Bei jeder Iteration des Algorithmus wird zuerst der Knoten mit dem kleinsten Wert gesucht. Dann werden alle Nachbarn dieses Knotens abgeprüft. Das können höchstens $n - 1$ Knoten sein, da ausgeschlossen wird, dass ein Knoten eine Kante mit sich selber haben kann. \subsubsection{Teil (b)} Anstelle einer \texttt{LinkedList} braucht man eine Datenstruktur, die bereits nach der Größe sortiert ist, damit bei dem Zugriff auf das kleinste Element nur ein Schritt erforderlich ist. Ein Beispiel dafür ist die \texttt{PriorityQueue}, die wir in Hausübung 8 implementiert haben. Dort werden Elemente beim Einfügen bereits sortiert, sodass der Zugriff auf das (in diesem Fall) kleinste Element in $O(1)$, also konstanter Zeit, gemacht werden kann. $$O(n)$$ \subsubsection{Teil (c)} Sei $n$ die Anzahl an Knoten. \textbf{Invariante}: Nach $h \geq 0$ Durchläufen gilt: \texttt{availableNodes}, die Liste von Knoten, die noch nicht bearbeitet wurden enthält $n - h$ Elemente. Diese Knoten sind alle Knoten ohne die $h$ kleinsten Knoten, also alle $n - h$ größten Knoten. Für alle noch nicht abgearbeiteten Knoten gilt: Für alle abgearbeiteten Knoten gilt: \subsection{Kürzester Pfad zu allen Knoten} \subsubsection{Teil (a)} \subsubsection{Teil (b)} \section{Weitergestaltung des Spiels} \subsection{Computergegner} \subsection{Missionen} \subsubsection{Begrenzte Rundenanzahl} \subsubsection{Capture the Flag} In dieser Mission werden wichtige Burgen, sogenannte Flags, gleichmäßig auf die Spieler verteilt. Es ist das Ziel, zuerst vor allen anderen Spielern alle diese Burgen zu erobern. \subsection{Joker} \end{document}