Compare commits

...

3 Commits

Author SHA1 Message Date
70ae98f31a WIP: report part 2 2020-10-25 22:07:59 +02:00
35044f91c7 DEV: Doxyfile added 2020-10-25 22:06:45 +02:00
a96bb62966 WIP: Report part 1 2020-10-25 22:06:04 +02:00
12 changed files with 2779 additions and 74 deletions

2494
Doxyfile Normal file

File diff suppressed because it is too large Load Diff

@ -1 +1 @@
Subproject commit c27d16e915615bc56a7b09f56e882661ac69b860
Subproject commit 665a0fc185084bed02af44177b27a855bfb64580

BIN
report/images/Graph.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

BIN
report/images/concepts.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 538 KiB

Binary file not shown.

View File

@ -8,7 +8,7 @@
% Document configuration
\newcommand{\ClassName}{Δομές δεδομένων}
\newcommand{\DocTitle}{Λαβύρινθος: Ο Θησέας και ο Μινώταυρος}
\newcommand{\DocTitle}{Λαβύρινθος: Ο Θησέας και ο Μινώταυρος 1}
\newcommand{\InstructorName}{Σιάχαλου Σταυρούλα}
\newcommand{\InstructorMail}{ssiachal@auth.gr}
\newcommand{\CurrentDate}{\today}
@ -32,7 +32,141 @@
%\listoffigures
%\listoftables
\section{Εισαγωγή}
\section{Εισαγωγή}
Η παρούσα εργασία αφορά τη δημιουργία ενός παιχνιδιού λαβυρίνθου με θέμα \textit{“Μια νύχτα στο μουσείο”}.
Στο συγκεκριμένο παιχνίδι καλούμαστε να δημιουργήσουμε ένα λαβύρινθο μέσα στον οποίο κινούνται με τυχαίο τρόπο δύο παίχτες, ο Θησέας και ο Μινώταυρος.
Στόχος του Μινώταυρου είναι να “πιάσει” τον Θησέα και στόχος του Θησέα είναι να βρει όλα τα εφόδια που είναι τυχαία κατανεμημένα στο ταμπλό πριν ξημερώσει και πριν τον πιάσει ο Μινώταυρος.
Στο παιχνίδι αυτό υπάρχουν δύο βασικά προβλήματα τα οποία χρειάζεται να λύσουμε.
Το πρόβλημα τις δημιουργίας του λαβύρινθου και το πρόβλημα της λειτουργίας του παιχνιδιού.
\par Κατά την άποψή μας η δημιουργία του ταμπλό είναι το κυριότερο από τα δύο προβλήματα.
Το ταμπλό αποτελείται από πλακίδια και τοίχους.
Τα πλακίδια είναι διατεταγμένα σε τετραγωνικό σχήμα και ανάμεσά τους τοποθετούνται οι τοίχοι.
Το πρόβλημα έγκειται στην επιλογή και τοποθέτηση τοίχων με τέτοιο τρόπο ώστε να πληρούνται οι προδιαγραφές του παιχνιδιού όπως πχ κάθε πλακίδιο να μπορεί να έχει το πολύ δύο τοίχους ή τα εξωτερικά πλακίδια να έχουν τοίχο από την έξω μεριά.
Μετά από μια πιο λεπτομερή ανάλυση του προβλήματος, διαπιστώσαμε πως οι δοθείσες προδιαγραφές δεν αποτρέπουν τη δημιουργία κλειστών δωματίων, κάτι που θεωρήσαμε άδικο, με αποτέλεσμα, όπως περιγράφουμε και αναλυτικά παρακάτω, \textbf{να προσθέσουμε έναν ακόμη περιορισμό.
Την αποτροπή κλειστών δωματίων στο ταμπλό.}
\par Το πρόβλημα της λειτουργίας του υπόλοιπου παιχνιδιού έχει να κάνει με τη δημιουργία των παιχτών καθώς και τις κινήσεις τους.
Οι προδιαγραφές αφορούν περιορισμούς στην κίνηση των παιχτών και τον τρόπο με τον οποίο λειτουργεί το παιχνίδι.
Για παράδειγμα οι παίχτες δεν μπορούν να περάσουν μέσα από τοίχους, ή οι παίχτες κινούνται κατά ένα πλακίδιο τη φορά κλτ.
Σε αντίθεση με τη λύση στο πρόβλημα του ταμπλό εδώ δεν απαιτήθηκαν ιδιαίτερες τεχνικές.
\section{Παραδοτέα}
Τα επισυναπτόμενα παραδοτέα αποτελούνται από:
\begin{itemize}
\item Τον \eng{\textbf{root}}κατάλογο στον οποίο υπάρχει και το \eng{project}του \eng{eclipse.}
Αυτός ο κατάλογος μπορεί να γίνει \eng{import}στο \eng{eclipse.}
\item Ένας υποκατάλογος \eng{\textbf{src/}}με τον κώδικα της \eng{java,}αποτελούμενο από ένα αριθμό αντικειμένων ενσωματωμένο στο πακέτο \eng{host.labyrinth.}
Αναφορά σε αυτό τον κατάλογο υπάρχει στο \eng{eclipse project.}
\item Ένας υποκατάλογος \eng{\textbf{out/}} που περιέχει το παραγόμενο \eng{command line jar}του παιχνιδιού.
\item Ένας υποκατάλογος \eng{\textbf{doc/}}με την τεκμηρίωση του κώδικα όπως αυτή έχει παραχθεί από τα σχόλια, με το εργαλείο \eng{doxygen.}
Το αρχείο ρυθμίσεων του \eng{doxygen}είναι στον \eng{root} με το όνομα \eng{Doxyfile.}
Η πλοήγηση στην τεκμηρίωση μπορεί να γίνει ανοίγοντας το αρχείο \eng{doc/index.html}
\item Ένας υποκατάλογος \eng{\textbf{report/}} που περιέχει την \textbf{παρούσα αναφορά}.
\end{itemize}
Εκτός από τα επισυναπτόμενα αρχεία διαθέσιμο υπάρχει και το \textbf{\eng{git}αποθετήριο} ολόκληρης της εργασίας \href{https://git.hoo2.net/hoo2/Labyrinth}{εδώ}.
Αυτό περιέχει τόσο τον κώδικα της εφαρμογής όσο και τον κώδικα της αναφοράς.
\section{Υλοποίηση}
Η όλη υλοποίηση έγινε σε \eng{java.}
Πριν ασχοληθούμε όμως με τα ζητηθέντα αντικείμενα του προγράμματος, θα πρέπει να αναφερθούμε σε ορισμένες δομές που προστέθηκαν, αλλά και κάποιες σχεδιαστικές επιλογές που έγιναν για να απλοποιήσουν τον κώδικα.
\subsection{\eng{Accessor - mutator idiom}}
Στις προδιαγραφές της εργασίας αφήνεται να εννοηθεί πως ζητείται η χρήση του \eng{\textit{accessor - mutator idiom.}}
Θα πρέπει να παραδεχτούμε όμως, πως \textbf{θεωρούμε το συγκεκριμένο ιδίωμα ιδιαίτερα προβληματικό}.
Ο κύριος λόγος είναι πως παραβιάζει θεμελιακά τις αφαιρέσεις.
Αντ' αυτού \textbf{τα αντικείμενα που υλοποιούνται ως αφαιρέσεις μπορούν να προσφέρουν μεθόδους που εκτελούν κάποια λειτουργία, κρύβοντας τελείως τις εσωτερικές λεπτομέρειες τις υλοποίησης}.
Αυτός είναι και ο δρόμος που διαλέξαμε για το σχεδιασμό του προγράμματος.
Η κάθε τάξη προσφέρει δημόσια ένα αριθμό από μεθόδους που είναι απαραίτητες για την απαιτούμενη λειτουργικότητα της και κρύβει όσο καλύτερα γίνεται την εσωτερική υλοποίηση.
Ενώ λοιπόν υλοποιήσαμε το ζητηθέν \eng{get-set}ζευγάρι για την κάθε μεταβλητή των τάξεων, δεν το χρησιμοποιήσαμε πουθενά μέσα στο πρόγραμμα.
\subsection{Ενοποιημένο σύστημα συντεταγμένων}
Στις προδιαγραφές της εργασίας περιγράφεται επίσης ένα διπλό σύστημα συντεταγμένων, τόσο για τα πλακίδια όσο και για τα εφόδια.
Ένα καρτεσιανό που διευθυνσιοδοτεί ως προς δύο άξονες και περιέχει ένα ζευγάρι γραμμής και στήλης και ένα μονοδιάστατο που αποτελείται από τον γραμμικό συνδυασμό του καρτεσιανού.
Το μονοδιάστατο αντικατοπτρίζει και την απεικόνιση στη μνήμη ενός πίνακα 2 διαστάσεων σε \eng{row major order.}
\par Γενικά θεωρούμε ότι κάτι τέτοιο δημιουργεί πλεονασμό δεδομένων και επομένως είναι κακή πρακτική.
Αυτό γιατί μεταξύ άλλων μειονεκτημάτων, που κυρίως αφορά τον πολυνηματικό προγραμματισμό, οδηγεί και σε προγραμματιστικά λάθη που πιθανώς θα αφήνουν τα δύο συστήματα ασυγχρόνιστα.
Για να λύσουμε αυτό το πρόβλημα \textbf{δημιουργήσαμε την τάξη\eng{Position,}}στην οποία εσωτερικά χρησιμοποιούμε μόνο το ένα από τα δύο συστήματα, για την ακρίβεια το μονοδιάστατο και ταυτόχρονα παρέχουμε μεθόδους για την πρόσβαση στη θέση και από τα δύο συστήματα.
Η τάξη μεταξύ άλλων προσφέρει και \textbf{στατικές μεθόδους για τις μετατροπές} προσφέροντας έτσι μια είδους εργαλειοθήκη για την εφαρμογή.
Έτσι χρησιμοποιήσαμε την \eng{Position}όπου ήταν δυνατό μέσα στον κώδικα.
\section{Αναβάθμιση της τάξης\eng{Tile}}
Κατά τον προγραμματισμό του παιχνιδιού παρατηρήσαμε πως τόσο η τάξη\eng{Tile}όσο και η\eng{Supply}έχουν πληροφορίες για τη θέση τους στο ταμπλό.
Αυτό σημαίνει πως και τα πλακίδια όσο και τα εφόδια ανήκουν στο ταμπλό.
Κάτι τέτοιο γίνεται αντιληπτό ακόμα και από τις προδιαγραφές της\eng{Board}η οποία είναι αυτή που περιέχει τους πίνακες αναφορών τόσο των πλακιδίων όσο και των εφοδίων.
Μια ποιο διαισθητική προσέγγιση βέβαια θα ήθελε τα εφόδια να ανήκουν στα πλακάκια και όχι στο ταμπλό.
\par Όπως είναι φυσικό θελήσαμε να υλοποιήσουμε αυτή την αίσθηση.
Αν όμως μετακινούσαμε τις αναφορές των εφοδίων στην\eng{Tile}θα αλλοιώναμε τις προδιαγραφές της εκφώνησης.
Έτσι επιλέξαμε μια μέση οδό.
Εμπλουτίσαμε την\eng{Tile}με μεθόδους που αφορούν τα εφόδια.
Αυτές είναι οι:
\begin{itemize}
\item \eng{\textbf{\textit{int hasSupply (Supply[] supplies)}}}\\
που δίνει την δυνατότητα να ελέγξουμε αν ένα πλακίδιο έχει κάποιο ενεργό εφόδιο. Και
\item \eng{\textbf{\textit{void pickSupply (Supply[] supplies, int supplyId)}}}\\
που δίνει την δυνατότητα σε κάποιο παίκτη να “σηκώσει” το εφόδιο.
\end{itemize}
Έτσι έχουμε ομοιομορφία με τις αντίστοιχες μεθόδους \eng{\textit{boolean hasWall(int direction)}}και\eng{\textit{int hasWalls()}}της\eng{Tile.}
\par Ένας παρατηρητικός αναγνώστης θα διαπιστώσει πως οι συναρτήσεις για τα εφόδια είναι αναγκασμένες να πάρουν τον πίνακα αναφορών στα εφόδια ως όρισμα.
Αυτό είναι το τίμημα που πρέπει να πληρώσουμε προωθώντας τις μεθόδους αυτές στην\eng{Tile.}
\section{\eng{Concepts}}
Η δημιουργία της\eng{Board}αποτέλεσε τον μεγαλύτερο όγκο του κώδικα της παρούσας εργασίας.
Για να κάνουμε τον κώδικα καθαρότερο αλλά και ευκολότερο στην κατανόηση επινοήσαμε κάποια\eng{\textbf{concepts}.}
Η ιδέα των\eng{concepts}προέρχεται από την\eng{C++}όπου τα\eng{concepts}είναι ένα είδους \eng{compile time predicate}και εφαρμόζεται στους τύπους δεδομένων.
Εμείς για την εργασία υλοποιήσαμε κάποια\eng{concepts} σε μορφή\eng{predicate.}
Στο σχήμα \ref{fig:concepts} φαίνεται μια οπτικοποιημένη έκδοση τους.
\subsection{\eng{Sentinel tile}}
\WrapFigure{0.5}{r}{fig:concepts}{images/concepts.png}{Οπτική αναπαράσταση των\eng{concepts}που χρησιμοποιούμε σε ένα ταμπλό $7x7$}
Πρόκειται για\eng{concept}που μας επιτρέπει να ελέγξουμε αν το πλακίδιο είναι \textbf{“πλακίδιο φρουρός”}.
Αν δηλαδή βρίσκεται στα εξωτερικά άκρα του ταμπλό.
Η υλοποίηση αυτού του\eng{concept}γίνεται μέσω τεσσάρων συναρτήσεων που ελέγχουν χωριστά τις τέσσερεις διευθύνσεις του ταμπλό.
\par Για την παράδειγμα η \eng{\textit{boolean isLeftSentinel (int tileId)}}μας δίνει την δυνατότητα να ελέγξουμε αν το πλακίδιο είναι “πλακίδιο φρουρού” αριστερά του ταμπλό.
Αυτό είναι χρήσιμο για λειτουργίες όπως για παράδειγμα αν θέλουμε να δούμε μήπως χρειάζεται να τοποθετηθεί τοίχος αριστερά του πλακιδίου.
Αντίστοιχα υπάρχουν και οι υπόλοιπες συναρτήσεις για τις υπόλοιπες διευθύνσεις.
\subsection{\eng{Walkable direction}}
Πρόκειται για\eng{predicate}που μας επιτρέπει να ελέγξουμε αν μια διεύθυνση σε κάποιο πλακίδιο είναι \textbf{“διασχίσημη”}.
Για να ισχύει κάτι τέτοιο θα πρέπει:
\begin{itemize}
\item Η διεύθυνση να μην έχει τοίχο.
\item Η διεύθυνση να μην είναι η “Κάτω” διεύθυνση του πλακιδίου εισόδου στο λαβύρινθο.
\end{itemize}
\subsection{\eng{Wallable direction}}
Πρόκειται για\eng{predicate}που μας επιτρέπει να ελέγξουμε αν μια διεύθυνση κάποιου πλακιδίου είναι \textbf{”χτίσιμη”}.
Αυτό το\eng{concept}είναι πολύ χρήσιμο κατά τη δημιουργία των τοίχων.
Για να είναι μια διεύθυνση χτίσιμη θα πρέπει:
\begin{itemize}
\item Η διεύθυνση να μην έχει τοίχο.
\item Η διεύθυνση να μην είναι η “Κάτω” διεύθυνση του πλακιδίου εισόδου στο λαβύρινθο.
\item Το γειτονικό πλακίδιο σε αυτή τη διεύθυνση να μην περιέχει ήδη τον μέγιστο αριθμό πλακιδίων.
\item Ο τοίχος να μην δημιουργεί κάποιο κλειστό δωμάτιο.\\
Αυτή η απαίτηση δεν υπάρχει στις προδιαγραφές και την παίρνουμε υπόψιν μόνο αν ο χρήστης την έχει ζητήσει από την γραμμή εντολών.
Ο λόγος είναι γιατί ο υπολογισμός της κοστίζει και αυτό μπορεί να μην παίζει ρόλο για ταμπλό μεγέθους $15x15$, αλλά αν ζητηθεί κάποιο πολύ μεγαλύτερο τότε ο χρόνος είναι υπολογίσιμος.
Φυσικά στον κώδικα κάνουμε χρήση αυτού του \eng{concept}μόνο κατά τη δημιουργία του ταμπλό.
\end{itemize}
\subsection{\eng{Wallable tile}}
Πρόκειται για\eng{predicate}που μας επιτρέπει να ελέγξουμε αν κάποιο πλακιδίο είναι \textbf{”χτίσιμo”}.
Για να ισχύει αυτό θα πρέπει:
\begin{itemize}
\item Το πλακίδιο να μην έχει ήδη τον μέγιστο αριθμό τοίχων.
\item Να υπάρχει τουλάχιστον μία “χτίσιμη” διεύθυνση στο πλακίδιο.
\end{itemize}
\subsection{Εύρεση κλειστών δωματίων}
Όπως αναφέραμε και παραπάνω οι προδιαγραφές της εργασίας δεν αποτρέπουν τη δημιουργία κλειστών δωματίων, κάτι που θεωρήσαμε άδικο.
Για το λόγο αυτό υλοποιήσαμε ένα αλγόριθμο που ανιχνεύει την πιθανότητα δημιουργίας κλειστών δωματίων του οποίου η ενεργοποίηση γίνεται κατόπιν επιλογής του χρήστη από τη γραμμή εντολών.
\InsertFigure{0.6}{fig:graph}{images/graph.png}{Γράφος.}
% References
% ============================

View File

@ -1,11 +1,13 @@
/**
* @file Board.java
*
* @author Christos Choutouridis AEM:8997
* @email cchoutou@ece.auth.gr
* @author
* Christos Choutouridis
* <cchoutou@ece.auth.gr>
* AEM:8997
*/
package net.hoo2.auth.labyrinth;
package host.labyrinth;
import java.util.ArrayList;
import java.util.function.IntFunction;
@ -131,7 +133,8 @@ class Board {
}
/**
* Predicate to check if a direction is Walkable
* Predicate to check if a direction is Walkable.
*
* @param tileId The starting tileId.
* @param direction The desired direction.
* @return True if it is walkable.
@ -142,9 +145,10 @@ class Board {
}
/**
* Predicate to check if a direction is Walkable
* Predicate to check if a direction is Walkable.
*
* @param row Row position of the starting tile.
* @param column Column position of the starting tile.
* @param col Column position of the starting tile.
* @param direction The desired direction.
* @return True if it is walkable.
*/
@ -175,7 +179,7 @@ class Board {
* @return A random direction;
*/
int dice () {
ShuffledRange d = new ShuffledRange(Direction.Begin, Direction.End, Direction.Step);
ShuffledRange d = new ShuffledRange(DirRange.Begin, DirRange.End, DirRange.Step);
return d.get();
}
@ -205,6 +209,13 @@ class Board {
*/
Supply[] getSupplies() { return supplies; }
/**
* @note Use it with care. Any use of this function results to what Sean Parent calls "incidental data-structure".
* <a href="https://github.com/sean-parent/sean-parent.github.io/blob/master/better-code/03-data-structures.md"> see also here</a>
* @return Reference to inner walls array.
*/
ArrayList<Edge> getWalls() { return walls; }
void setN(int N) { this.N = N; }
void setS(int S) { this.S = S; }
void setW(int W) { this.W = W; }
@ -221,6 +232,14 @@ class Board {
* Any call to this function will probably add memory for the garbage collector.
*/
void setSupplies(Supply[] supplies) { this.supplies= supplies; }
/**
* @param walls Reference to walls that we want to act as replacement for the inner walls vector.
* @note Use with care.
* Any call to this function will probably add memory for the garbage collector.
*/
void setWalls (ArrayList<Edge> walls) { this.walls= walls; }
/** @} */
@ -269,16 +288,16 @@ class Board {
/**
* Predicate to check if a wall creates a closed room.
*
* This algorithm has a complexity of O(N^2logN) where N represents the total
* This algorithm has a complexity of @f$ O(N^2logN) @f$ where N represents the total
* number of tiles.
* It should be used with care.
*
* @param tileId The tileId of the wall where the wall is.
* @param direction The wall's relative direction from the tile.
* @param tileId The tileId of the wall.
* @param direction The wall's relative direction.
* @return True if the wall creates a closed room, false otherwise.
*/
private boolean makesClosedRoom (int tileId, int direction) {
// Get a snapshot list of all the walls (all the walls on the board)
// Clone the list of all the walls locally.
ArrayList<Edge> w = new ArrayList<Edge>();
for (Edge it : walls)
w.add(new Edge(it));
@ -288,14 +307,14 @@ class Board {
int size;
do {
size = w.size(); // mark the size (before the pass)
for (int i =0, S=w.size() ; i<S ; ++i)
if (g.attach(w.get(i))) { // Can we attach the edge(wall) to the graph ?
w.remove(i); // If yes remove it from the wall list
for (int i =0, S=w.size() ; i<S ; ++i) // for each edge(wall) on the local wall list
if (g.attach(w.get(i))) { // can we attach the edge(wall) to the graph ?
w.remove(i); // if yes remove it from the local wall list
--i; --S; // decrease iterator and size to match ArrayList's new values
}
} while (size != w.size()); // If the size hasn't change(no new graph leafs) exit
// Search if a vertex is attached more than once.
// Search if a vertex is attached to the graph more than once.
// This means that there is at least 2 links to the same node
// so the graph has a closed loop
for (Edge it : walls) {
@ -365,7 +384,7 @@ class Board {
return false;
if (tiles[tileId].hasWalls() >= Const.maxTileWalls)
return false;
Range dirs = new Range(Direction.Begin, Direction.End, Direction.Step);
Range dirs = new Range(DirRange.Begin, DirRange.End, DirRange.Step);
for (int dir ; (dir = dirs.get()) != Const.noTileId ; )
if (isWallableDir(tileId, dir))
return true;
@ -388,6 +407,7 @@ class Board {
boolean right = isRightSentinel(i);
wallCount += ((up?1:0) + (down?1:0) + (left?1:0) + (right?1:0));
tiles[i] = new Tile (i, up, down, left, right);
// If we have loopGuard enable we populate walls also.
if (Session.loopGuard) {
if (up) walls.add(new Edge(i, Direction.UP));
if (down) walls.add(new Edge(i, Direction.DOWN));
@ -404,14 +424,16 @@ class Board {
*/
private void createInnerWall(int tileId) {
// Randomly pick a wallable direction in that tile.
ShuffledRange randDirections = new ShuffledRange(Direction.Begin, Direction.End, Direction.Step);
ShuffledRange randDirections = new ShuffledRange(DirRange.Begin, DirRange.End, DirRange.Step);
int dir;
do
dir = randDirections.get();
while (!isWallableDir(tileId, dir));
// Add wall to tileId and the adjacent tileId
Position neighbor = new Position(Position.toRow(tileId), Position.toCol(tileId), dir);
tiles[tileId].setWall(dir);
tiles[neighbor.getId()].setWall(Direction.opposite(dir));
// If we have loopGuard enable we populate walls also.
if (Session.loopGuard)
walls.add(new Edge(tileId, dir));
}
@ -419,7 +441,6 @@ class Board {
/**
* This utility creates the inner walls of the board.
*
* @param walls The number of walls to create
* @return The number of walls failed to create.
*/
private int createInnerWalls () {

View File

@ -1,10 +1,12 @@
/**
* @file Common.java
*
* @author Christos Choutouridis AEM:8997
* @email cchoutou@ece.auth.gr
* @author
* Christos Choutouridis
* <cchoutou@ece.auth.gr>
* AEM:8997
*/
package net.hoo2.auth.labyrinth;
package host.labyrinth;
import java.util.ArrayList;
import java.util.Collections;
@ -36,16 +38,31 @@ class Direction {
static final int RIGHT =3; /**< East direction */
static final int DOWN =5; /**< South direction */
static final int LEFT =7; /**< West direction */
static final int Begin =1; /**< Iterator style begin of range direction (starting north) */
static final int End =8; /**< Iterator style end of range direction (one place after the last) */
static final int Step =2; /**< Step for iterator style direction */
/**
* Utility to get the opposite
* Utility to get the opposite direction.
* @param direction Input direction
* @return The opposite direction
*/
static int opposite (int direction) { return (direction+4)%End; }
static int opposite (int direction) { return (direction+4)%DirRange.End; }
}
/**
* Helper C++ like enumerator class for direction ranged loops.
*
* We can make use of this in loops like:
* <pre>
* for (int i=DirRange.Begin ; i<DirRange.End ; i += DirRange.Step) { }
*
* or
*
* Range directions = new Range(DirRange.Begin, DirRange.End, DirRange.Step);
* </pre>
*/
class DirRange {
static final int Begin =1; /**< Iterator style begin of range direction (starting north) */
static final int End =8; /**< Iterator style end of range direction (one place after the last) */
static final int Step =2; /**< Step for iterator style direction */
}
/**
@ -55,7 +72,7 @@ class Direction {
* Position is a helper class to enable us cope with the redundant position data (id and coordinates).
* This class provide both static conversion functionalities between id and coordinates
* and data representation in the coordinates system.
* For clarity we adopt a row-column naming convention.
* For clarity we adopt a tileId convention.
*/
class Position {
@ -219,18 +236,21 @@ class ShuffledRange extends Range {
* This class is the wall representation we use in the room preventing algorithm.
* In this algorithm we represent the crosses between tiles as nodes (V) of a graph and the
* walls as edges. So for example:
*
* _ V = 15
* /
* +---+---+---+ We have a 4x4=16 vertices board(nodes) and 14 edges(walls).
* | | To represent the vertices on the board we use the
* + +---+ + same trick as the tileId.
* | | | The edges are represented as vertices pairs.
* + + + + <.
* | | | \_ V = 7
* + +---+---+
* ^ ^
* V = 0 V = 3
* <pre>
* 12--13--14---15
* | |
* 8 9--10 11
* | | |
* 4 5 6 7
* | | |
* 0 1---2---3
* </pre>
* In this example we have a 4x4=16 vertices board(nodes) and 14 edges(walls).
* To represent the vertices on the board we use the same trick as the tileId
*
* V = Row*(N+1) + Column, where N is the board's tile size.
*
* The edges are represented as vertices pairs. For example (0, 4) or (13, 14).
*
* @note
* Beside the fact that we prefer this kind of representation of the walls in
@ -242,7 +262,7 @@ class ShuffledRange extends Range {
*/
class Edge {
/**
* This constructor as as the interface between the application's wall
* This constructor acts as the interface between the application's wall
* representation and the one based on graph.
* @param tileId The tile id of the wall.
* @param direction The direction of the tile where the wall should be.
@ -286,13 +306,13 @@ class Edge {
* @brief
* Provides a graph functionality for the room preventing algorithm.
* We use a graph to represent the wall structure of the walls. This way
* is easy to find any closed loops. Using graph we transform the problem
* of the closed room in the problem of finding a non simple graph.
* its easy to find any closed loops. Using graph we transform the problem
* of the closed room into the problem of finding a non simple graph.
*
* If the board has non connected wall structure then we need more than
* If the board has non connected wall structure then we would need more than
* one graph to represent it.
*
* An example graph from a board, starting from V=1 is:
* An example graph we can create from the board bellow, starting from V=1 is:
* <pre>
* 6---7 8 (1)
* | | / \
@ -327,7 +347,7 @@ class Graph {
/**
* Attach an edge into a graph IFF the graph already has a vertex
* with the same value of one of the vertices of the edge.
* with the same value as one of the vertices of the edge.
* @param e The edge to attach.
* @return The status of the operation.
* @arg True on success
@ -348,17 +368,18 @@ class Graph {
/**
* Recursive algorithm that tries to attach an edge into a graph
* IFF the graph already has a vertex.
* with the same value of one of the vertices of the edge.
* IFF the graph already has a vertex with the same value as one
* of the vertices of the edge.
*
* @param e The edge to attach.
* @param count An initial count value to feed to the algorithm.
* @param count An initial count value to feed the algorithm.
* @return The status of the operation.
* @arg True on success
* @arg False on failure
*/
private int tryAttach (Edge e, int count) {
for (Graph n: E)
count += n.tryAttach (e, count);
count = n.tryAttach (e, count);
if (V == e.getV1()) {
E.add(new Graph(e.getV2()));
++count;
@ -372,7 +393,8 @@ class Graph {
/**
* Recursive algorithm that tries to count the number of vertices
* on the graph with the value of `v`
* on the graph with the same value as `v`.
*
* @param v The vertex to count
* @param count An initial count value to feed to the algorithm.
* @return The number of vertices with value `v`
@ -384,6 +406,7 @@ class Graph {
return ++count;
return count;
}
private int V; /**< The value of the current vertex/node */
private ArrayList<Graph> E; /**< A list of all the child nodes */
}

View File

@ -1,11 +1,22 @@
/**
* @file Game.java
*
* @author Christos Choutouridis AEM:8997
* @email cchoutou@ece.auth.gr
* @author
* Christos Choutouridis
* <cchoutou@ece.auth.gr>
* AEM:8997
*/
package net.hoo2.auth.labyrinth;
/**
* @mainpage A labyrinth board game
*
* @section intro_sec Introduction
*
* This is the introduction.
*
* etc...
*/
package host.labyrinth;
import java.util.Scanner;
@ -28,8 +39,8 @@ public class Game {
int nextRound() { return ++round; }
/**
* Utility to hold the execution of the program waiting for user input.
* This is true only if the user passed the interactive flag.
* Utility to hold the execution of the program waiting for user input.
* This is true only if the user passed the interactive flag.
*/
void waitUser () {
if(Session.interactive) {

View File

@ -1,5 +1,13 @@
package net.hoo2.auth.labyrinth;
/**
* @file Player.java
*
* @author
* Christos Choutouridis
* <cchoutou@ece.auth.gr>
* AEM:8997
*/
package host.labyrinth;
/**
* @brief
@ -11,9 +19,12 @@ class Player {
/**
* Create a new player and put him at the row-column coordinates
* @param id The id of the player
* @param name The name of the player
* @param board Reference to the board of the game
* @param id The id of the player
* @param name The name of the player
* @param champion Flag to indicate if a player is a `champion`
* @param board Reference to the board of the game
* @param row The row coordinate of initial player position
* @param column The column coordinate of initial player's position
*/
Player(int id, String name, boolean champion, Board board, int row, int column) {
this.playerId = id;
@ -27,9 +38,11 @@ class Player {
/**
* Create a new player and put him at the row-column coordinates
* @param id The id of the player
* @param name The name of the player
* @param board Reference to the board of the game
* @param id The id of the player
* @param name The name of the player
* @param champion Flag to indicate if a player is a `champion`
* @param board Reference to the board of the game
* @param tileId The tileId coordinate of player's initial position
*/
Player(int id, String name, boolean champion, Board board, int tileId) {
this.playerId = id;
@ -105,6 +118,7 @@ class Player {
int getScore () { return score; }
int getX() { return x; }
int getY() { return y; }
boolean getChampion(){ return champion; }
void setPlayerId(int id) { playerId = id; }
void setName(String name) { this.name = name; }
@ -118,6 +132,10 @@ class Player {
assert (y >= 0 && y< Session.boardSize) : "Y(row) coordinate must be in the range [0, Session.boardSize)";
this.y = y;
}
void setChampion (boolean champion) {
this.champion = champion;
}
/** @} */
/** @name Class data */

View File

@ -1,11 +1,13 @@
/**
* @file Supply.java
*
* @author Christos Choutouridis AEM:8997
* @email cchoutou@ece.auth.gr
* @author
* Christos Choutouridis
* <cchoutou@ece.auth.gr>
* AEM:8997
*/
package net.hoo2.auth.labyrinth;
package host.labyrinth;
/**
* @brief
@ -76,7 +78,7 @@ class Supply {
int supplyId () { return supplyId; }
/**
* Set the supplyId
* @param sId The Id to set
* @param sID The Id to set
* @return The supplyId
* @note This function also returns the supplyId to help in chained expressions.
*/

View File

@ -1,11 +1,13 @@
/**
* @file Tile.java
*
* @author Christos Choutouridis AEM:8997
* @email cchoutou@ece.auth.gr
* @author
* Christos Choutouridis
* <cchoutou@ece.auth.gr>
* AEM:8997
*/
package net.hoo2.auth.labyrinth;
package host.labyrinth;
/**
* @brief
@ -132,7 +134,7 @@ class Tile {
/**
* Sets the tile's wall in the requested direction.
* @param up The direction for the wall.
* @param direction The direction for the wall.
*/
void setWall (int direction) {
switch (direction) {
@ -145,7 +147,7 @@ class Tile {
/**
* Clears the tile's wall in the requested direction.
* @param up The direction for the wall
* @param direction The direction for the wall
*/
void clearWall (int direction) {
switch (direction) {