瀏覽代碼

RC: Part C

tags/v3.0b1^0
父節點
當前提交
6fd0fc10a9
共有 6 個檔案被更改,包括 102 行新增61 行删除
  1. 二進制
      release/8959_8997_PartC.zip
  2. 二進制
      report/images/maxValue.png
  3. 二進制
      report/report.pdf
  4. +98
    -57
      report/report.tex
  5. +2
    -2
      src/host/labyrinth/MinMaxPlayer.java
  6. +2
    -2
      src/host/labyrinth/Player.java

二進制
release/8959_8997_PartC.zip 查看文件


二進制
report/images/maxValue.png 查看文件

Before After
Width: 591  |  Height: 753  |  Size: 133 KiB

二進制
report/report.pdf 查看文件


+ 98
- 57
report/report.tex 查看文件

@@ -18,7 +18,7 @@
\newcommand{\CoAuthorMail}{cchoutou@ece.auth.gr}
\newcommand{\CoAuthorAEM}{8997}

\newcommand{\DocTitle}{Λαβύρινθος: Ο Θησέας και ο Μινώταυρος Β}
\newcommand{\DocTitle}{Λαβύρινθος: Ο Θησέας και ο Μινώταυρος III}
\newcommand{\Department}{Τμημα ΗΜΜΥ. Τομεάς Ηλεκτρονικής}
\newcommand{\ClassName}{Δομές δεδομένων}

@@ -32,7 +32,7 @@
%\setFancyHeadLERO{\ClassName}{\DocTitle}
%\BottomTitleSpace{8em}

\renewcommand{\bottomtitlespace}{0.1\textheight}
\renewcommand{\bottomtitlespace}{0.12\textheight}

% Document
% =================
@@ -45,20 +45,15 @@
%\listoftables

\section{Εισαγωγή}
Η παρούσα εργασία αφορά την δημιουργία ενός παιχνιδιού λαβυρίνθου “Μία νύχτα στο μουσείο”.
Η παρούσα εργασία αφορά την δημιουργία ενός παιχνιδιού με τίτλο “Μία νύχτα στο μουσείο”.
Στο συγκεκριμένο παιχνίδι καλούμαστε να υλοποιήσουμε ένα λαβύρινθο μέσα στον οποίο κινούνται δύο παίκτες, ο Μινώταυρος και ο Θησέας.
Στόχος του Μινώταυρου είναι να “πιάσει” τον Θησέα και στόχος του Θησέα είναι να βρει όλα τα εφόδια πού βρίσκονται κατανεμημένα στον ταμπλό, πριν ξημερώσει και πριν τον “πιάσει” ο Μινώταυρος.

\par Υπενθυμίζουμε ότι στην πρώτη εργασία κληθήκαμε να λύσουμε δύο βασικά προβλήματα.
Το πρόβλημα της δημιουργίας του λαβυρίνθου και το πρόβλημα της λειτουργίας των παικτών.
Το ταμπλό αποτελείται από πλακίδια και τοίχους.
Τα πλακίδια είναι διατεταγμένα σε τετραγωνικό σχήμα και ανάμεσά τους τοποθετούνται οι τοίχοι.
Το πρόβλημα έγκειται στην επιλογή και τοποθέτηση τοίχων με τέτοιο τρόπο ώστε να πληρούνται οι προδιαγραφές του παιχνιδιού όπως πχ κάθε πλακίδιο να έχει το πολύ δύο τοίχους ή τα εξωτερικά πλακίδια να έχουν τοίχο από την έξω μεριά.
Μετά από μια πιο λεπτομερή ανάλυση του προβλήματος, διαπιστώσαμε πως οι δοθείσες προδιαγραφές δεν αποτρέπουν τη δημιουργία κλειστών δωματίων, κάτι που θεωρήσαμε άδικο, με αποτέλεσμα, όπως περιγράφουμε και αναλυτικά παρακάτω, \textbf{να προσθέσουμε έναν ακόμη περιορισμό}.
\textbf{Την αποτροπή κλειστών δωματίων στο ταμπλό}.

\par Λαμβάνοντας υπόψιν τόσο τα δεδομένα που μας δόθηκαν, δηλαδή για την δομή του παιχνιδιού, όσο και τα δύο βασικά προβλήματα που χρειάστηκε να επεξεργαστούμε και να λύσουμε στο πρώτο μέρος, αποφασίσαμε να υλοποιήσουμε την δεύτερη εργασία με γνώμονα τις σχεδιαστικές επιλογές και τα \eng{concepts} που αναπτύξαμε και περιγράφονται αναλυτικά στην αναφορά του πρώτου μέρους.
Όσον αφορά επίσης τον τρόπο κίνησης των παικτών επιλέξαμε μόνο ο Θησέας να έχει την δυνατότητα να επιλέγει την κατεύθυνση της επόμενης κίνησης του, ενώ ο Μινώταυρος να κινείται με τυχαίο τρόπο.
\par Υπενθυμίζουμε πως στις πρώτες εργασίες κληθήκαμε να υλοποιήσουμε το ταμπλό και τα στοιχεία που το απαρτίζουν καθώς και τις βασικές λειτουργίες του παιχνιδιού.
Στη δεύτερη εργασία κληθήκαμε επιπρόσθετα να υλοποιήσουμε ένα παίκτη ο οποίος χειρίζεται το ζάρι προς όφελός του.
Στην παρούσα εργασία ασχοληθήκαμε με τη δημιουργία ενός παίκτη που κάνει χρήση του αλγόριθμου \eng{minimax}, με σκοπό να προβλέψει καλύτερα την κίνησή του, αναλύοντας τις πιθανές κινήσεις του αντιπάλου.
Φυσικά όλα τα βασικά συστατικά του παιχνιδιού που αναπτύξαμε στις δύο πρώτες εργασίες είναι παρόντα.
Οι τροποποιήσεις σε αυτά είναι ελάχιστες και αφορούν κυρίως την συμβατότητα με τις νέες λειτουργίες, όπως αυτές περιγράφονται στην εκφώνηση.

\section{Παραδοτέα}
Τα επισυναπτόμενα παραδοτέα αποτελούνται από:
@@ -69,28 +64,28 @@
\item Ένας υποκατάλογος \eng{\textbf{doc/}} με την τεκμηρίωση του κώδικα όπως αυτή έχει παραχθεί από τα σχόλια, με το εργαλείο \eng{doxygen}.
Το αρχείο ρυθμίσεων του \eng{doxygen} είναι στον \eng{root} με το όνομα \eng{Doxyfile}.
Η πλοήγηση στην τεκμηρίωση μπορεί να γίνει ανοίγοντας το αρχείο \eng{doc/html/index.html}
\item Ένας υποκατάλογος \eng{\textbf{report/}} που περιέχει την \textbf{παρούσα αναφορά}.
\item Το αρχείο \eng{\textbf{report.pdf}} που αποτελεί την \textbf{παρούσα αναφορά}.
\end{itemize}
Εκτός από τα επισυναπτόμενα αρχεία διαθέσιμο υπάρχει και το \textbf{\eng{git} αποθετήριο} ολόκληρης της εργασίας \href{https://git.hoo2.net/hoo2/Labyrinth}{εδώ}.
Αυτό περιέχει τόσο τον κώδικα της εφαρμογής όσο και τον κώδικα της αναφοράς.

\section{Σχεδιαστικές επιλογές}
Πριν ασχοληθούμε όμως με τα ζητηθέντα αντικείμενα του προγράμματος, θα πρέπει να αναφερθούμε σε ορισμένες δομές που προστέθηκαν, αλλά και κάποιες σχεδιαστικές επιλογές που έγιναν για να απλοποιήσουν τον κώδικα.
Αρκετές από αυτές προέρχονται από την προηγούμενη εργασία.
Αρκετές από αυτές προέρχονται από τις προηγούμενες εργασίες.
Τις παραθέτουμε όμως και εδώ καθώς παίζουν σημαντικό ρόλο, τόσο στην λειτουργία του προγράμματος όσο και στην καλύτερη κατανόηση της τρέχουσας εργασίας.

\subsection{\eng{Accessor - mutator idiom}}
Στις προδιαγραφές της εργασίας αφήνεται να εννοηθεί πως ζητείται η χρήση του \eng{\textit{accessor - mutator idiom}}.
Θα πρέπει να παραδεχτούμε όμως, πως \textbf{θεωρούμε το συγκεκριμένο ιδίωμα ιδιαίτερα προβληματικό}.
Ο κύριος λόγος είναι πως παραβιάζει θεμελιακά τις αφαιρέσεις προδίδοντας τον εσωτερικό σχεδιασμό του αντικειμένου.
Ακόμα δίνει πρόσβαση στην εσωτερική δομή του “πίσω από την πλάτη” του αντικειμένου.
Ακόμα δίνει πρόσβαση στην εσωτερική δομή του, “πίσω από την πλάτη” του αντικειμένου.
Εν αντιθέτως με το ιδίωμα αυτό, \textbf{τα αντικείμενα που υλοποιούνται ως αφαιρέσεις θα μπορούσαν να προσφέρουν μεθόδους που εκτελούν κάποια λειτουργία, κρύβοντας τελείως τις εσωτερικές λεπτομέρειες της υλοποίησης}.
Αυτός είναι και ο δρόμος που διαλέξαμε για το σχεδιασμό του προγράμματος.
Η κάθε τάξη του προγράμματός μας προσφέρει δημόσια ένα αριθμό από μεθόδους που είναι απαραίτητες για την εκάστοτε απαιτούμενη λειτουργικότητα και κρύβει όσο καλύτερα γίνεται την εσωτερική υλοποίηση.
Ενώ λοιπόν υλοποιήσαμε το ζητηθέν \eng{get-set} ζευγάρι για την κάθε μεταβλητή των τάξεων, δεν το χρησιμοποιήσαμε πουθενά μέσα στο πρόγραμμα.
Ενώ λοιπόν υλοποιήσαμε το ζητηθέν \eng{get-set} ζευγάρι για την κάθε μεταβλητή των τάξεων, δεν το χρησιμοποιήσαμε σχεδόν καθόλου μέσα στο πρόγραμμα.

\subsection{Ενοποιημένο σύστημα συντεταγμένων}
Στις προδιαγραφές της εργασίας περιγράφεται επίσης ένα διπλό σύστημα συντεταγμένων, τόσο για τα πλακίδια όσο και για τα εφόδια.
Στις προδιαγραφές της 1ης εργασίας περιγράφεται επίσης ένα διπλό σύστημα συντεταγμένων, τόσο για τα πλακίδια όσο και για τα εφόδια.
Ένα καρτεσιανό που διευθυνσιοδοτεί ως προς δύο άξονες και περιέχει ένα ζευγάρι γραμμής και στήλης και ένα μονοδιάστατο που αποτελείται από τον γραμμικό συνδυασμό των προηγουμένων.
Το μονοδιάστατο αντικατοπτρίζει και την απεικόνιση στη μνήμη ενός πίνακα 2 διαστάσεων σε \eng{row major order}.

@@ -106,7 +101,7 @@
Ακόμα σημαίνει πως δημιουργούν επιπλέον πλεονασμό σε δεδομένα, καθώς απαιτείται οι συντεταγμένες του πλακιδίου που βρίσκεται το εφόδιο να επαναληφθούν μέσα στην \eng{Supply}.
Κάτι τέτοιο γίνεται αντιληπτό και από τις προδιαγραφές της \eng{Board} η οποία είναι αυτή που περιέχει τους πίνακες αναφορών τόσο των πλακιδίων όσο και των εφοδίων.
\textbf{Μια πιο διαισθητική προσέγγιση βέβαια θα ήθελε τα εφόδια να ανήκουν στα πλακίδια} και όχι στο ταμπλό.
Με αυτό τον τρόπο η τάξη \eng{Supply} δεν θα είχε τις επαναλαμβανόμενες πληροφορίες θέσης, αλλά αντίθετα η τάξη \eng{Tile} θα είχε απλώς μια επιπρόσθετη πληροφορία για το αν υπάρχει εφόδιο ή όχι.
Με αυτό τον τρόπο η τάξη \eng{Supply} δεν θα είχε τις επαναλαμβανόμενες πληροφορίες θέσης, αλλά αντίθετα η τάξη \eng{Tile} θα είχε απλώς μια επιπρόσθετη πληροφορία για το αν φιλοξενεί κάποιο εφόδιο ή όχι.

\par Όπως είναι φυσικό θελήσαμε να υλοποιήσουμε αυτή την προσέγγιση.
Αν όμως μετακινούσαμε τις αναφορές των εφοδίων στην \eng{Tile} θα αλλοιώναμε τις προδιαγραφές της εκφώνησης.
@@ -124,31 +119,40 @@
Αυτό είναι το τίμημα που πρέπει να πληρώσουμε προωθώντας τις μεθόδους αυτές στην \eng{Tile}.

\subsection{Αναβάθμιση της τάξης \eng{Board}}
Στην διάρκεια του σχεδιασμού θεωρήσαμε ωφέλιμη την εισαγωγή της μεταβλητής \eng{\textit{ArrayList<Integer[]> moves}} στην τάξη \eng{Board}.
Σε αυτή καταχωρούμε τις πληροφορίες της τελευταίας κίνησης του κάθε παίκτη, όπως το \eng{id} του πλακιδίου που βρίσκεται ο παίκτης, οι συντεταγμένες του και η συλλογή εφοδίου.
Στην διάρκεια του σχεδιασμού θεωρήσαμε ωφέλιμη την εισαγωγή του πίνακα \eng{\textit{int[][] moves}} στην τάξη \eng{Board}.
Σε αυτόν καταχωρούμε τις πληροφορίες της τελευταίας κίνησης του κάθε παίκτη, όπως το \eng{id} του πλακιδίου που βρίσκεται ο παίκτης, οι συντεταγμένες του και η “ζαριά” της κίνησης.
Στην προσθήκη αυτή οδηγηθήκαμε αφού παρατηρήσαμε πως για την τάξη \eng{HeuristicPlayer} είναι απαραίτητη η πρόσβαση στην θέση και στο \eng{id} του αντιπάλου.
Αυτή πραγματοποιείται μέσω της μεταβλητής \eng{moves} και της συνάρτησης \eng{\textit{getOpponentMoves()}}.
Έτσι ο κάθε \eng{HeuristicPlayer} μπορεί να διαπιστώσει αν στο οπτικό του πεδίο βρίσκεται κάποιος αντίπαλος και να κινηθεί κατάλληλα.
Φυσικά την ίδια απαίτηση έχουμε και με την τάξη \eng{MinMaxPlayer}.
Η πρόσβαση στις κινήσεις πραγματοποιείται μέσω της μεταβλητής \eng{moves} και της συνάρτησης \eng{\textit{getOpponentMove()}}.
Έτσι ο κάθε \eng{HeuristicPlayer} ή \eng{MinMaxPlayer} μπορεί να διαπιστώσει αν στο οπτικό του πεδίο βρίσκεται κάποιος αντίπαλος και να κινηθεί κατάλληλα.

\par Ακόμα μέσω του ίδιου μηχανισμού δίνουμε την δυνατότητα στους παίκτες να μαθαίνουν το \eng{ID} του αντιπάλου.
Αυτό είναι χρήσιμο για τον \eng{MinMaxPlayer} όταν προσπαθεί να σκηνοθετήσει τις κινήσεις του αντιπάλου.
Θα αναλύσουμε περισσότερα όμως γύρω από αυτό στην παράγραφο ??.

\subsection{Αναβάθμιση της τάξης \eng{Player}}
Για την επέμβαση σε αυτή την τάξη κινηθήκαμε με γνώμονα την αντιμετώπιση δύο προβλημάτων που μας παρουσιάστηκαν.
Αρχικά για την σωστή λειτουργία τη κλάσης \eng{HeuristicPlayer}, όπως αναφέραμε και παραπάνω, είναι αναγκαία η πρόσβαση στο \eng{id} του αντιπάλου.
Για τον λόγο αυτό επιλέξαμε να δημιουργείται ένα \eng{id} για κάθε παίκτη μέσω συνάρτησης της τάξης \eng{Board}, στο οποίο θα έχουμε πρόσβαση μέσω της μεταβλητής \eng{\textit{ArrayList<Integer[]> moves}}.
Για τον λόγο αυτό επιλέξαμε να δημιουργείται ένα \eng{id} για κάθε παίκτη μέσω συνάρτησης της τάξης \eng{Board}, στο οποίο θα έχουμε πρόσβαση μέσω του πίνακα \eng{\textit{int[][] moves}}.
Τη λειτουργία αυτή αναλαμβάνει η συνάρτηση \eng{\textit{int generatePlayerId()}}.

\par
Επιπρόσθετα, θέλαμε να ενοποιήσουμε τις υλοποιήσεις των τάξεων \eng{Player} και \eng{HeuristicPlayer} και να τις κάνουμε συμβατές με την αρχή του \eng{Liskov} \footnote{\eng{\url{https://en.wikipedia.org/wiki/Liskov_substitution_principle}}}.
Για το λόγο αυτό οι συναρτήσεις \eng{\textit{move(), statistics()}} και \eng{\textit{final\_statistice()}} είναι πλέον υλοποιημένες και στα δύο αντικείμενα.
Επιπρόσθετα, θελήσαμε να ενοποιήσουμε τις υλοποιήσεις των τάξεων \eng{Player}, \eng{HeuristicPlayer} και \eng{MinMaxPlayer}, ώστε να τις κάνουμε συμβατές με την αρχή του \eng{Liskov} \footnote{\eng{\url{https://en.wikipedia.org/wiki/Liskov_substitution_principle}}}.
Για το λόγο αυτό οι συναρτήσεις \eng{\textit{move(), statistics()}} και \eng{\textit{final\_statistice()}} είναι πλέον υλοποιημένες και σε όλα τα αντικείμενα.
Αυτό μας ανάγκασε να μετακινήσουμε την μεταβλητή \eng{path} στο \eng{base object} δηλαδή στην \eng{Player}.

\section{\eng{Concepts}}
Αν και τα \eng{concepts} υλοποιήθηκαν για την εκπόνηση του πρώτου μέρους, τα παραθέτουμε συνοπτικά και σε αυτή την αναφορά, καθώς τα θεωρούμε ουσιαστικό κομμάτι τόσο για το πρώτο, όσο και για το δεύτερο μέρος της εργασίας.
Για την εργασία υλοποιήσαμε κάποια \eng{concepts} σε μορφή συναρτήσεων κατά την εκτέλεση του προγράμματος.
Τα \eng{concepts} αυτά αφορούν έννοιες σχετικές με την εφαρμογή και έχουν την μορφή \eng{predicate}.
Αν και τα \eng{concepts} υλοποιήθηκαν για την εκπόνηση του πρώτου μέρους, τα παραθέτουμε συνοπτικά και σε αυτή την αναφορά, καθώς τα θεωρούμε ουσιαστικό κομμάτι για όλα τα μέρη της εργασίας.
Τα \eng{”concepts”} μας έχουν τη μορφή συναρτήσεων και αφορούν έννοιες σχετικές με την εφαρμογή.
Μας δίνεται έτσι η δυνατότητα να ελέγχουμε αν κάποια είσοδός ενός \eng{predicate-concept} πληροί τις προδιαγραφές του ή όχι.
Στο σχήμα \ref{fig:concepts} φαίνεται μια οπτικοποιημένη έκδοση τους.

\subsection{Πλακίδιο φρουρός - \textit{\eng{isSentinel()}}}
\WrapFigure{0.45}{r}{fig:concepts}{images/concepts.png}{
Οπτική αναπαράσταση των \eng{concepts} που χρησιμοποιούμε σε ένα ταμπλό $7x7$.
Με πράσινο αναπαρίστανται όσα πληρούν κάποιο \eng{concept} και με κόκκινο όσα όχι.
Τα πλακίδια με το γκρι χρώμα, είναι τα πλακίδια φρουροί.
}
Πρόκειται για \eng{concept} που μας επιτρέπει να ελέγξουμε αν το πλακίδιο είναι \textit{”πλακίδιο φρουρός”}.
Αν δηλαδή βρίσκεται στα εξωτερικά άκρα του ταμπλό.
Η υλοποίηση αυτού του \eng{concept} γίνεται μέσω τεσσάρων συναρτήσεων που ελέγχουν χωριστά τις τέσσερεις διευθύνσεις του ταμπλό.
@@ -167,11 +171,6 @@
\end{itemize}

\subsection{Χτίσιμη διεύθυνση - \textit{\eng{isWallableDir()}}}
\WrapFigure{0.45}{r}{fig:concepts}{images/concepts.png}{
Οπτική αναπαράσταση των \eng{concepts} που χρησιμοποιούμε σε ένα ταμπλό $7x7$.
Με πράσινο αναπαρίστανται όσα πληρούν κάποιο \eng{concept} και με κόκκινο όσα όχι.
Τα πλακίδια με το γκρι χρώμα, είναι τα πλακίδια φρουροί.
}
Πρόκειται για \eng{predicate} που μας επιτρέπει να ελέγξουμε αν μια διεύθυνση κάποιου πλακιδίου είναι \textit{”χτίσιμη διεύθυνση”}.
Αν δηλαδή μπορούμε να τοποθετήσουμε τοίχο στη διεύθυνση αυτή.
Για να είναι μια διεύθυνση χτίσιμη θα πρέπει:
@@ -196,7 +195,7 @@
\end{itemize}

\subsection{Δημιουργός κλειστού δωματίου - \textit{\eng{isRoomCreator()}}} \label{sec:isRoomCreator}
Όπως αναφέραμε και παραπάνω οι προδιαγραφές της εργασίας δεν αποτρέπουν τη δημιουργία κλειστών δωματίων.
Οι προδιαγραφές της εργασίας που αφορούν τη δημιουργία του ταμπλό, δεν αποτρέπουν την εμφάνιση κλειστών δωματίων.
Για το λόγο αυτό υλοποιήσαμε ένα αλγόριθμο που ανιχνεύει την πιθανότητα δημιουργίας κλειστών δωματίων του οποίου η ενεργοποίηση γίνεται κατόπιν επιλογής του χρήστη από τη γραμμή εντολών.

\par Ένας αλγόριθμος για να είναι λειτουργικός χρειάζεται δεδομένα.
@@ -239,10 +238,9 @@
Φυσικά θα μπορούσαμε να χρησιμοποιήσουμε υπομνηματισμό και να αποθηκεύουμε τους γράφους
Όμως λόγο του ότι η επιβάρυνση λαμβάνει χώρα μόνο μία φορά κατά την εκκίνηση, σε συνδυασμό με το μικρό μέγεθος του ταμπλό, αποφασίσαμε να μην προχωρήσουμε σε περαιτέρω βελτιστοποίηση.


\section{Υλοποίηση}
Για την μεταγλώττιση της εφαρμογής, απαιτείται \eng{java} έκδοση 8 ή και μεταγενέστερη καθώς έχουμε κάνει χρήση \eng{lambdas}.
Για υπενθύμιση, αναφέρουμε συνοπτικά τη λειτουργία ορισμένων αντικειμένων που προσθέσαμε κατά την πρώτη εργασία.
Για υπενθύμιση, αναφέρουμε συνοπτικά τη λειτουργία ορισμένων αντικειμένων που προσθέσαμε κατά την πρώτη και δεύτερη εργασία.
\begin{itemize}
\item \eng{\textbf{Const}}\\
Το αντικείμενο αυτό περιέχει σταθερές για όλη την εφαρμογή.
@@ -272,16 +270,63 @@
Η τάξη αυτή κληρονομεί την \eng{Range} και προσθέτει τη λειτουργία του τυχαίου ανακατέματος των τιμών.
\end{itemize}

\subsection{Τάξη \eng{HeuristicPlayer}}
Η υλοποίηση της τάξης \eng{HeuristicPlayer} πραγματοποιήθηκε έτσι ώστε να ικανοποιούνται τα ζητήματα της εκφώνησης.
Η βασική λειτουργία της τάξης είναι η συνάρτηση \eng{\textit{double evaluate(int currentPos, int dice)}} η οποία ζητήθηκε και από την εκφώνηση.
Για τη δημιουργία της βασιστήκαμε στην ανάπτυξη κριτηρίων που θα βοηθήσουν τον παίκτη να “καταλήξει” στην βέλτιστη απόφαση με βάση το προκαθορισμένο οπτικό του πεδίο.
Τα κριτήρια αυτά είναι η απόσταση από κάποιο εφόδιο και η απόσταση από τον αντίπαλο.
Στην τελική αξιολόγηση της κίνησης τα κριτήρια συνδυάζονται με συντελεστές βάρους οι οποίοι αποτελούν σταθερές και θέτονται κατά τη μεταγλώττιση του προγράμματος.
\par
Ένα ακόμη χαρακτηριστικό της τάξης είναι η εκτενής χρήση της μεταβλητής \eng{path}.
Όπως αναφέραμε και παραπάνω η μεταβλητή αυτή είναι προσβάσιμη τόσο από την \eng{HeuristicPlayer}, όπως ζητήθηκε, όσο και από την \eng{Player}.
Και οι δύο τάξεις καταχωρούν πληροφορίες για την κίνησή του κάθε παίκτη, με την διαφορά πως η \eng{HeuristicPlayer} καταχωρεί περισσότερες.
\subsection{Αλγόριθμος \eng{minimax}}
\WrapFigure{0.45}{r}{fig:maxValue}{images/maxValue.png}{
Διάγραμμα ροής της \eng{\textit{maxValue()}}, όπου γίνεται αναδρομική κλήση της \eng{\textit{minValue()}}.
}
Ο σκοπός της παρούσας εργασίας θεωρούμε πως ήταν η υλοποίηση του αλγόριθμου \eng{minimax}.
Για τον αλγόριθμο αυτό αρχικά απαιτείται η δημιουργία ενός δέντρου.
Το κάθε επίπεδο του δέντρου έχει για κόμβους όλες τις δυνατές κινήσεις των παικτών εναλλάξ.
Έτσι ο κάθε κόμβος αναπαριστά μια κίνηση και τα παιδιά του κάθε κόμβου αναπαριστούν όλες τις δυνατές κινήσεις-απαντήσεις του αντίπαλου παίκτη στην κίνηση αυτή.
Καθώς εκτελείται ο αλγόριθμος η αξιολόγηση της κάθε κίνησης από τους κατώτερους κόμβους ανεβαίνει προς τα πάνω.
Η επιλογή γίνεται εναλλάξ από τον κάθε παίκτη.
Έτσι ο αντίπαλος επιλέγει για τιμή του κάθε κόμβου την τιμή από τα παιδιά με την μικρότερη αξιολόγηση, ενώ ο παίκτης μας την τιμή με την μεγαλύτερη.
Στο τέλος ο βασικός κόμβος περιέχει την μέγιστη δυνατή τιμή λαμβάνοντας υπόψιν την καλύτερη δυνατή κίνηση-απάντηση του αντιπάλου.

\par Για τον κάθε κόμβο υλοποιήσαμε την τάξη \eng{Node} ακολουθώντας τις οδηγίες της εκφώνησης.
Πέρα από αυτές όμως χρειαστήκαμε και μια επιπλέον πληροφορία, που αφορά το μονοπάτι της επιλογής των κόμβων από τον αλγόριθμο.
Δηλαδή, σε κάθε κόμβο αποθηκεύουμε επιπλέον ένα δείκτη προς τον κόμβο από τον οποίο έγινε η επιλογή της τιμής του.
Με αυτό τον τρόπο ήμαστε σε θέση, μετά την εκτέλεση του αλγόριθμου, να γνωρίζουμε τόσο την τιμής της αξιολόγησης, όσο και την κίνηση από την οποία προήλθε.

\par Η υλοποίηση του \eng{minimax} αλγόριθμου έγινε στην τάξη \eng{MinMaxPlayer}.
Η τάξη αυτή κληρονομεί την \eng{Player} και μαζί και τις βασικές λειτουργίες όπως τους \eng{Constructors} και το \eng{accessor - mutator idiom}.
Ακολουθώντας τον σχεδιασμό της \eng{HeuristicPlayer}, υλοποιήσαμε την \eng{MinMaxPlayer}, δίχως κανένα \eng{data member}.
Αυτά ανήκουν όλα στην \eng{Player}.
Έτσι όλη η επιπρόσθετη λειτουργικότητα της τάξης αφορά τον αλγόριθμο \eng{nimimax}.
Οι κύριες μέθοδοι που υλοποιήθηκαν για την δημιουργία του δέντρου είναι:\\
\begin{itemize}
\item \eng{\textbf{\textit{int[] dryMove()}}}\\
Η συνάρτηση αυτή προσομοιώνει την κίνηση κάποιου παίκτη χρησιμοποιώντας για ταμπλό αυτό από τα ορίσματά της.
Έτσι μπορούμε να πραγματοποιήσουμε διαφορετικές κινήσεις σε διαφορετικούς κλώνους του ταμπλό χωρίς να αλλοιώσουμε το βασικό ταμπλό του παιχνιδιού.
\item \eng{\textbf{\textit{void createMySubtree()}}}\\
Η συνάρτηση αυτή είναι η μία από τις δύο μεθόδους που υλοποιούν το δέντρο με τις δυνατές κινήσεις των παικτών.
Ξεκινώντας από τη τρέχουσα θέση του παίκτη και για κάθε “διασχίσιμη διεύθυνση” δημιουργούμε και ένα αντίγραφο του ταμπλό και σε αυτό εκτελούμε την κίνηση του παίκτη εικονικά μέσω της συνάρτησης \eng{\textit{dryMove()}}.
Έπειτα αποθηκεύουμε στο δέντρο την κίνηση αυτή ώς κόμβο και καλούμε την συνάρτηση \eng{\textit{createOppSubtree()}} με αυτόν σαν όρισμα.

\item \eng{\textbf{\textit{void createOppSubtree()}}}\\
Η συνάρτηση εκτελεί την ίδια διαδικασία με την \eng{\textit{createMySubtree()}} αλλά για τον αντίπαλο αυτή τη φορά.
\item \eng{\textbf{\textit{double evaluation()}}}\\
Η συνάρτηση αυτή είναι υπεύθυνη για την αξιολόγηση της κάθε κίνησης.
Τόσο στην περίπτωση της του παίκτη, όσο και στην περίπτωση του αντιπάλου.
Για να είναι συμβατή με τα ζητούμενα, αξιολογεί την κίνηση “κοιτώντας” το ταμπλό στην κατεύθυνση της κίνησης και μόνο.
Αυτή η συμπεριφορά είναι αρκετά περιοριστική και οδηγεί σε πολύ φτωχά αποτελέσματα.
Για παράδειγμα ενώ μια κίνηση προς τον αντίπαλο αξιολογείται αρνητικά καθώς ο παίκτης μπορεί να τον “δει”, η κατεύθυνση μακριά από τον αντίπαλο δεν αξιολογείται θετικά.
Ακόμα στην περίπτωση που η αξιολόγηση αφορά κίνηση του αντιπάλου, δεν έχουμε την δυνατότητα να αξιολογήσουμε την κατάσταση της πίστας συνολικά.
Για να αντιμετωπίσουμε αυτόν τον τελευταίο περιορισμό, μετά την προσομοίωση της κίνησης του αντιπάλου, αξιολογούμε ξανά την τελευταία κίνηση του παίκτη.
Μόνο που πλέον ο αντίπαλος είναι σε νέα θέση.
\end{itemize}

\par Τόσο η \eng{\textit{createMySubtree()}}, όσο και η \eng{\textit{createOppSubtree()}} εσωτερικά αξιολογούν την κάθε κίνηση.
Αυτό είναι περιττό καθώς οι μόνοι κόμβοι που απαιτείται να αξιολογηθούν είναι τα φύλλα.
Παρόλα αυτά αποφασίσαμε να εκτελέσουμε την \eng{\textit{evaluate()}} που αξιολογεί την κίνηση σε κάθε κόμβο ώστε να συμβαδίζουμε με τις οδηγίες της εκφώνησης.

\par Ο αλγόριθμος ολοκληρώνεται με την υλοποίηση των συναρτήσεων που ανάγουν τις αξιολογήσεις των κόμβων προς τα πάνω.
Αυτές είναι οι \eng{\textit{maxValue()}} και \eng{\textit{minValue()}} και εκτελούνται αναδρομικά εναλλάξ από τον παίκτη και τον αντίπαλο.
Στο σχήμα \ref{fig:maxValue} φαίνεται το διάγραμμα ροής της \eng{\textit{maxValue()}}.
Η \eng{\textit{minValue()}} είναι αντίστοιχη.
Ο παίκτης προσπαθεί μέσω της \eng{\textit{maxValue()}} να επιλέξει τη μεγαλύτερη αξιολόγηση ενώ ο αντίπαλος, μέσω της \eng{\textit{minValue()}}, επιλέγει την μικρότερη.

\section{Εκτελέσιμο} \label{sec:excecutable}
Όπως αναφέραμε και στην παράγραφο με τα παραδοτέα, σε αυτά υπάρχει και το παραγόμενο εκτελέσιμο για την γραμμή εντολών.
@@ -328,22 +373,18 @@
\eng{\texttt{java -jar labyrinth -r 200 -s 7}}\\[1.2ex]
Αν ο χρήστης δεν χρησιμοποιήσει την επιλογή τότε ο προεπιλεγμένος αριθμός είναι 100.
\end{itemize}
\InsertFigure{0.5}{fig:executable}{images/screenshot.png}{
\InsertFigure{0.6}{fig:executable}{images/screenshot.png}{
Στιγμιότυπο από την εκτέλεση του προγράμματος σε \eng{interactive mode} και με αποφυγή κλειστών δωματίων.
Η εντολή που χρησιμοποιήθηκε είναι \eng{\texttt{java -jar labyrinth -i -{}-norooms}}
}

\section{Παρατηρήσεις}
Θα θέλαμε εδώ να σταθούμε και σε κάποιες διορθώσεις που χρειάστηκε να πραγματοποιήσουμε στον κώδικα που καταθέσαμε για την πρώτη εργασία.
Για την ακρίβεια παρατηρήσαμε πως ο \eng{copy constructor} της \eng{Board} αποτύγχανε να αντιγράψει το διάνυσμα αναφορών των τοίχων.
Ακόμα ο αλγόριθμος που αναλάμβανε να τοποθετήσει τους εσωτερικούς τοίχους στο ταμπλό αποτύγχανε να εξαντλήσει όλες τις δυνατές θέσεις με τους πιθανούς τοίχους.
Λεπτομέρειες για τις διορθώσεις μπορεί κάποιος να δει και \href{https://git.hoo2.net/hoo2/Labyrinth/commit/c14d1d812f312eda499c445e2827a8fbafa34100}{εδώ}.

\par Κλείνοντας θα θέλαμε να παρατηρήσουμε πως η παρούσα υλοποίηση ήταν μια προσπάθεια να ισορροπήσουμε μεταξύ των ζητηθέντων και μεταξύ πρακτικών που διευκολύνουν στη συγγραφή ευκολότερου και καθαρότερου κώδικα.
Γενικά, όπως είναι ίσως ήδη γνωστό, πιστεύουμε πως \textbf{αν ο χρήστης μιας βάσης κώδικα έχει τη δυνατότητα να χρησιμοποιήσει λανθασμένα τον κώδικα, κάποια στιγμή θα το κάνει.}
Ακόμα και αν ο χρήστης είναι ο ίδιος ο αρχικός συντάκτης του κώδικα.
Για το λόγο αυτό προσπαθήσαμε να περιορίσουμε, όπου αυτό δεν ήταν αντίθετο με τα ζητούμενα, την δυνατότητα της λανθασμένης χρήσης εισάγοντας αρκετά επιπλέον αντικείμενα και δομές ως εργαλεία για την εφαρμογή.
Κλείνοντας θα θέλαμε να πούμε πως η παρούσα εργασία ήταν μια προσπάθεια να υλοποιήσουμε τα ζητούμενα χρησιμοποιώντας όμως πρακτικές που θεωρούμε αναγκαίες για την συγγραφή κώδικα.
Πρακτικές που στόχο έχουν να αποτρέψουν την πιθανότητα λανθασμένης χρήσης σε βάθος χρόνου.
Για το λόγο αυτό προσπαθήσαμε να περιορίσουμε, όπου αυτό δεν ήταν αντίθετο με τα ζητούμενα, την δυνατότητα της λανθασμένης χρήσης εισάγοντας αρκετά επιπλέον εργαλεία για την εφαρμογή.
Τέτοια για παράδειγμα είναι η τάξη \eng{Position} ή η αποφυγή των \eng{setters} κτλ.
Ακόμα προσπαθήσαμε να οργανώσουμε τις δομές δεδομένων με τέτοιο τρόπο ώστε να περιορίσουμε τον απαιτούμενο κώδικά όσο το δυνατό περισσότερο.
Αυτό έχει ως αποτέλεσμα ένα κάπως πιο μακροσκελές κώδικα, με πολλά αντικείμενα και συναρτήσεις, που ίσως είναι δυσανάλογος των μικρών απαιτήσεων της εργασίας.
Ελπίζουμε να μην θεωρηθούν υπερβολικά.

% References


+ 2
- 2
src/host/labyrinth/MinMaxPlayer.java 查看文件

@@ -343,7 +343,7 @@ class MinMaxPlayer extends Player {
*/
private double maxValue (Node node) {
if (node.getChildren() == null) {
node.setPath(node);
//node.setPath(node);
return node.getNodeEvaluation();
}
else {
@@ -367,7 +367,7 @@ class MinMaxPlayer extends Player {
*/
private double minValue (Node node) {
if (node.getChildren() == null) {
node.setPath(node);
//node.setPath(node);
return node.getNodeEvaluation();
}
else {


+ 2
- 2
src/host/labyrinth/Player.java 查看文件

@@ -204,11 +204,11 @@ class Player {
void setChampion (boolean champion) {
this.champion = champion;
}
public void setDirCounter(int[] dirCounter) {
void setDirCounter(int[] dirCounter) {
this.dirCounter = dirCounter;
}

public void setPath(ArrayList<Integer[]> path) {
void setPath(ArrayList<Integer[]> path) {
this.path = path;
}
/** @} */


Loading…
取消
儲存