Skip to content

🃏 A simulation of The Legend of the Five Rings card game. 🎴

License

Notifications You must be signed in to change notification settings

Sitaras/Legend-of-the-Five-Rings

Repository files navigation

-Ιωάννης Καπετανγεώργης: 1115201800061
-Δημήτριος Σιταράς: 	 1115201800178
--------------------------------------------------------------------------------------
~Eντολή μεταγλώττισης: make (υπάρχει αρχείο Makefile) 
~Εντολή εκτέλεσης: ./project 
--------------------------------------------------------------------------------------

>>>>> Όλος ο κώδικας είναι κατάλληλα σχολιασμένος.

>>>>> Πληρούνται όλες οι προϋποθέσεις/απαιτήσεις που αναγράφονται στην εκφώνηση της άσκησης (καθώς και στο forum του μαθήματος)
και εχουν υλοποιηθεί όλες οι λεπτομέρειες ετσι ώστε να λειτουργεί σωστά κάθε πιθανή εξέλιξη του παιχνιδιού.

>>>>> Όλη η μνήμη που δεσμεύεται δυναμικά κατα την εκτέλεση του παιχνιδιού, αποδεσμεύεται πλήρως (και σωστά).
( Έχει ελεγχθεί με την χρήση του valgrind στα μηχανήματα linux της σχολής )

>>>>> Χρησιμοποιείται η συνάρτηση sleep() με την καταλληλη καθυστέρηση καθε φορά, ώστε 
καθε εξοδος του προγραμματος να ειναι πιο κομψή και ευαναγνωστη.


---------------------------------------------------------------------------------------


~ Αναπαράσταση δεδομένων:

-Για τις κάρτες (στο αρχείο Cards.hpp) :
 Βασική κλάση είναι η Card (είναι abstract), η οποια εχει υποκλάσεις τις  
 GreenCard και BlackCard (και αυτες abstract).
 H Green Card εχει υποκλασεις τις Follower και Item (abstract και οι δυο επισης).
 Η Follower εχει υποκλάσεις τις Footsoldier, Archer, Cavalry, Bushido, Sieger, Atakebune.
 Η Item εχει υποκλάσεις τις Katana, Spear, Bow, Ninjato, Wakizashi.
 Ενω, η Black Card εχει υποκλάσεις τις Personallity και Holding (abstract και οι δυο επισης).
 Η Personality εχει υποκλάσεις τις Attacker, Defender, Champion, Chancellor, Shogun.
 Η Holding εχει υποκλάσεις τις Plain, Mine, Gold mine, Crystal Mine, Farmland, Gift&Favour, Stronghold.


-Η κλάση Player (στο αρχείο Player.hpp):
 Ενας παικτης του παιχνιδιού αναπαρισταται από το όνομα του (string), μια τραπουλα απο μαυρες καρτες (list<BlackCard*>* dynastyDeck), 
 μια απο πράσινες(list<GreenCard*>* fateDeck), απο τον στρατο του (list<BlackCard*>* army), απο τις καρτες που εχει στο χερι του (list<GreenCard*>* hand), απο τις  
 ιδιοκτησίες του (list<BlackCard*>* holdings), απο τις επαρχίες του(list<BlackCard*>* provinces), απο το φρουριο (Stronghold). 
 Επίσης, εχει χρήματα (int money) και εντιμότητα (int honour) καθώς στατισικά (Statistics *stats).
 
 Οπώς ειναι αντιληπτό τις τραπουλες, το χερι, το στρατο, τις ιδιοκτησίες και τις επαρχίες
 τις αναπαριστoύμε με την δομή της λίστας (λίστα δεικτών).

-H κλάση Gameboard (στο αρχειο Gameboard.hpp):
 Έχει μια λίστα δεικτών σε Player, ενα δεικτη σε DeckBuilder ωστε να αρχικοποιει και να ανακατευει τις τράπουλες των παικτών 
 και περιέχει μεθόδους που υλοποιούν την κάθε φάση ( startingPhase(),equipPhase(),economyPhase(),battlePhase(),finalPhase() ).
 Η μέθοδος gameplay() καλεί ολες αυτές τις φασεις.
 Επιπλέον, υπαρχει και μέθοδος αρχικοποίησης (περα απο τον constructor υπαρχει η μεθοδος initializeGameBoard())
 και μέθοδοι που χρησιμοποιούνται μέσα σε κάποιες φασεις που εξυπηρετούν συγκεκριμένες λειτουργίες του
 παιχνιδιού (connectHoldings,checkWinningCondition,printGameStatistics).
 

-H κλάση Statistics (στο αρχειο Statistic.hpp):
 Ένα αντικείμενο της κλάσης Statistic αποθηκεύεται στα δεδομένα του κάθε Player για να αναπαριστά 
 τα στατιστικά του (stats).
 Περιέχει κάποιες μεταβλητές οι οποίες αποθηκεύουν συγκεκριμένα στοιχειά για τον κάθε παίχτη σε διάφορες στιγμές του γύρου έτσι ώστε στο τέλος του γύρου να υπολογίσουμε τα στατιστικά.
 Οι μεταβλητές αυτές είναι:
 initialArmy-> στην αρχή του κάθε γύρου αποθηκεύεται ο αριθμός των προσωπικοτήτων που κατέχει ο κάθε παίκτης (army).
 attackBonus-> κατά την διάρκεια ενός γύρου ένας παίκτης μπορεί να "πάρει" attackBonus όταν αναθέσει
 έναν follower σε ένα personality (equipPhase). Αντίθετα μπορεί να "χάσει" attackBonus όταν χάνεται
 στην μάχη ένας follower  ενός personality. Έτσι στις αντίστοιχες φάσεις του παιχνιδιού προσθέτουμε/αφαιρούμε του attackBonus που αυξήθηκε ή χάθηκε αντίστοιχα.
 defBonus-> ίδια λογική με το attackBonus άλλα για τους πόντους άμυνας.
 finalArmy-> στο τέλος του κάθε γύρου αποθηκεύεται ο αριθμός των προσωπικοτήτων που κατέχει ο κάθε παίκτης (army).
 moneySpent-> ο αριθμός χρημάτων που έχει ξοδέψει ο παίκτης για την αγορά provinces (economyPhase) καθώς και για τον εξοπλισμό των προσωπικοτήτων (equipPhase).
 moneyLost-> ο αριθμός των χαμένων χρημάτων ("χαμένα λεφτά" όπως αναφέρεται στην εκφώνηση) από την αρχή του παιχνιδιού. Τα χαμένα λεφτά του κάθε παίκτη για τον τρέχον γύρο εκτυπώνονται ξεχωριστά στο finalPhase.
 armyLost-> ο αριθμός των personalities που έχασε ο κάθε παίκτης στην μάχη. Αυξάνεται κάθε φορά που χάνεται μια προσωπικότητα στο battlePhase. 
 Τα στατιστικά που παρέχει η κλάση αυτή είναι:
 armyPercentage-> Το ποσοστό αύξησης/μείωσης του στρατού ενός παίκτη στον συγκεκριμένο γύρο. Υπολογίζεται με την χρήση των μεταβλητών initialArmy και finalArmy.
 armyLostPercentage-> το ποσοστό των αρχικού στρατού (του στρατού στην αρχή του γύρου (initialArmy))
 που χάθηκε στην μάχη.
 moneyPercentage-> το ποσοστό αύξησης η μείωσης των χρημάτων του παίκτη σε αυτόν τον γύρο.
 attackBonus, defBonus -> εξηγήθηκαν παραπάνω.
 moneySpent, moneyLost -> εξηγήθηκαν παραπάνω.

 Όλα τα παραπάνω στατιστικά εκτυπώνονται από την συνάρτηση printGameStatistics() η οποία καλείται στο
 finalPhase άλλα και μια φορά στην αρχή του παιχνιδιού από την main.



----------------------------------------------------------------------------------------

~main.cpp

Στην main δίνεται ως εισοδος το πληθος των παικτων του παιχνιδιού, 
δημιουργείται ένα αντικειμενo της κλάσης Gameboard (l5r) και 
δίνεται το πλήθος των παικτων ως ορισμα στον constructor, 
όπου αρχικοποιειται η λιστα δεικτων σε παικτες,
γινεται η εισαγωγη παικτών ταξινομημένα
σε φθίνουσα σειρα σύμφωνα με την εντιμότητά τους.
Έπειτα, το αντικειμενο καλει την μεθοδο initializeGameboard() ωστε να δημιουργήθουν/ανατεθούν και να 
ανακατευτουν τα decks (fate και dynasty) του καθε παικτη. Να αποδοθουν 4 Green Cards απο το fateDeck 
στο "χερι" του καθε παικτη και 4 Black Cards απο το dynastyDeck στο χωρο των επαρχιων (του καθε παικτη).
Τέλος, εκτυπώνονται τα στατιστικα και αρχίζει το παιχνίδι 🎮(Gameplay).

~Gameboard.cpp

Η συνάρτηση gameplay() καλεί ολες τις παρακάτω συναρτήσεις...
Ολες οι παρακάτω συναρτήσεις καλούνται μια φορά σε καθε γύρο απο την συνάρτηση gameplay() και όχι μια φορά για κάθε παίκτη.
Εσωτερικά των συναρτήσεων της κάθε φασης εκτελούνται επαναληπτικά για καθε παίκτη.

-startingPhase() 

Η μεθοδος αυτη αναπαριστά την αρχική φαση του παιχνιδιού όπου κάθε παίκτης:
επαναφέρει σε ορθή θέση όλες τις κάρτες του (untapEverything),
τραβάει μια πράσινη κάρτα (drawFateCard),
εμφανίζει τις διαθέσιμες επαρχίες (revealProvinces),
εκτυπώνει το τωρινό του χέρι (printHand) 
και τις επαρχίες (printProvinces)


-equipPhase()

Η διαδικασία που θα εξηγηθεί παρακάτω εκτελείται επαναληπτικά για κάθε παίκτη (pl).
Η μεθοδος αυτη αναπαριστά την φάση εξοπλισμού του παιχνιδιού:
Ελέγχεται αν εχει ο παίκτης στρατό (army).
Αν δεν εχει, τότε παίζει ο επόμενος σε σειρά παικτης, εκτός και αν είναι ο τελευταίος παίκτης οπότε το παιχνίδι προχωράει στην επόμενη φάση.
Αν έχει, τότε ο παίκτης διαλέγει ενα personality απο το army του για να το εξοπλίσει 
με μία πρασινη καρτα (green card) της επιλογής του απο το χερι του (διαφορετικά "παταει" το μηδέν και τερματίζεται η σειρά του).
Για την αγορά της πρασινης καρτας αυτής θα πρεπει:
να επαρκουν τα λεφτα του παικτη και 
η εντιμότητα της προσωπικότητας (που επιλέξε) να ειναι μεγαλυτερη ή ιση της ελάχιστης εντιμότητας που αναγράφεται στην πράσινη κάρτα
(αν δεν πληρει τα κριτηρια ο παικτης τοτε του δίνεται η δυνατότητα να επιλέξει ξανα απο την αρχή προσωπικότητα και πρασινη καρτα ή να τερματισει την σειρά του).
O παικτης συλλέγει τα χρήματα για να αγοράσει την κάρτα που επέλεξε κάνοντας tap τα holdings που εχει στην κατοχή του (η διαδικασία σταματάει είτε οταν ο παικτης φτάσει ή ξεπερασει το
κοστος της κάρτας είτε οταν γίνουν tap ολα τα holdings). 
Εφόσον εχει γινει η αγορά της κάρτας, δίνεται η δυνατότητα στον παίκτη να χρησιμοποιήσει αν θελει τα effect Bonus της καρτας αυτής (πρεπει να εχει βέβαια επαρκή ποσό χρημάτων).

Σημειώσεις:

* Τα holdings μπορουν να γίνουν μονο μια φορά tap σε καθε γύρο.

* Αν το personality δεν εχει την απαιτούμενη εντιμότητα για την πρασινη κάρτα που επιλέχθηκε να αγοραστεί ή δεν επαρκούν τα λεφτα για την αγορα της καρτας αυτής ή και τα δύο 
τοτε εμφανίζονται τα αντίστοιχα μηνύματα και δινεται η δυνατότητα στον παικτη να επιλέξει ξανα από την αρχή personallity και green card ή να τερματισει την σειρά του.

* Λεφτά που τυχών περισσεύουν μετα απο κάποια αγορά χάνονται ("Χαμένα λεφτά").

* Η παραπάνω διαδικασία επαναλαμβάνεται μέχρι ο παικτής να πατήσει το μηδέν (επίσης τερματίζει όταν τελίωσουν/αγοραστούν οι πράσινες κάρτες στο χέρι του παίκτη).

* Όταν δεν έχει αρκετά untapped holdings (για συλλογή χρημάτων) ωστε να κανει την αγόρα της κάρτας που έχει επιλέξει, τοτε παραλειπεται η διαδικασία "holdings tapping" και του δίνεται η
  δυνατότητα να επιλέξει άλλη κάρτα για αγορά ή να τερματίσει την σειρα του. 



-battlePhase()

Η διαδικασία που θα εξηγηθεί παρακάτω εκτελείται επαναληπτικά για κάθε παίκτη (pl).
Η μέθοδος αυτή αναπαριστά την φάση μάχης του παιχνιδιού όπου:
Αν δεν εχει στρατό, τότε παίζει ο επόμενος σε σειρά παικτης, εκτός και αν είναι ο τελευταίος παίκτης οπότε το παιχνίδι προχωράει στην επόμενη φάση.
Αν ο παίκτης έχει στρατό τότε επιλέγει το αν θέλει να επιτεθεί σε κάποιον η όχι.
Αν επιλέξει να επιτεθεί τότε διαλέγει ποιες από τις κάρτες του army θα χρησιμοποιηθούν για την επίθεση.
Έπειτα από την επιλογή των επιτιθέμενων κάρτων ο παίκτης επιλέγει σε ποιον παίκτη θέλει να επιτεθεί (pl2) καθώς και σε ποιο από τα provinces του θα επιτεθεί (attackedProv).
Μετά από όλες τις επιλογές, υπολογίζεται η δύναμη επίθεσης (attackPower) και η δύναμη άμυνας (defPower). Η δύναμη επίθεσης αντιστοιχεί στο άθροισμα των πόντων επιθέσεις όλων των κάρτων που ο παίκτης έχει επιλέξει να χρησιμοποιήσει για την επίθεση. Η δύναμη άμυνας προκύπτει από το σύνολο των ποντών άμυνας όλων των αμυνόμενων κάρτων (όσων κάρτων του αμυνόμενου είναι untapped) καθώς και του πόντους άμυνας της υπό επίθεση επαρχίας (οι οποίοι προκύπτουν από το Stronghold).
Έπειτα, ανάλογα με τους πόντους επίθεσης και άμυνας διακρίνονται περιπτώσεις (που περιγράφονται στην εκφώνηση) σχετικά με το αποτέλεσμα της μάχης.

Περίπτωση 1 ( η διαφορά attackPower και defPower είναι μεγαλύτερη από την αρχική άμυνα της αμυνόμενης επαρχίας)
  Σε αυτήν την περίπτωση, προφανώς, κερδίζει την μάχη ο επιτιθέμενος. Καταστρέφεται η αμυνόμενη επαρχία καθώς και ολόκληρος ο αμυνόμενος στρατός του παίκτη που δέχεται την επίθεση (pl2).

Περίπτωση 2 (το attackPower είναι μεγαλύτερο από το defPower, άλλα η διαφορά τους μικρότερη από την άμυνα της επαρχίας)
  Και σε αυτήν την περίπτωση, νικητής της μάχης είναι ο επιτιθέμενος. Η αμυνόμενη επαρχία ΔΕΝ καταστρέφεται (σύμφωνα με τους κάνονες), καταστρέφεται όμως ολόκληρος ο αμυνόμενος στρατός (εάν υπάρχει) του pl2. Έπειτα, ο επιτιθέμενος πρέπει να χάσει προσωπικότητες η ακολούθους με δύναμη ίση η μεγαλύτερη από την διάφορα attackPower-defPower. Η διάφορα αυτή αποθηκεύεται στην μεταβλητή sub και μειώνεται κάθε φορά μου μια προσωπικότητα ή ακόλουθος χάνεται (έως ότου το sub γίνει <=0 δηλαδή χαθούν οι επιθυμητοί πόντοι επίθεσης). Έτσι ο επιτιθέμενος παίκτης έχει την επιλογή να χάσει οποιαδήποτε προσωπικότητα ή ακόλουθο επιθυμεί. Μετά από αυτήν την διαδικασία γίνονται tap όσες προσωπικότητες πολέμησαν και επέζησαν από την μάχη, μειώνεται το honour αυτών των προσωπικοτήτων και ελέγχεται αν κάποια προσωπικότητα χρειάζεται να κάνει τιμητική αυτοκτονία (Seppuku). Επίσης για κάθε μια προσωπικότητα που συμμετείχε στην μάχη μειώνεται το durability των items που κατέχει (αν κατέχει) καθώς και γίνονται detouch όσα item έχουν durability 0.

Περίπτωση 3 ( attackPower == defPower )
  Περίπτωση ισοπαλίας. Σε αυτήν την περίπτωση καταστρέφεται ο στρατός και των δυο παικτών που συμμετείχαν στην μάχη (αμυνόμενου και επιτιθέμενου).

Περίπτωση 4 (atttackPower < defPower )
  Σε αυτήν την περίπτωση νικητής της μάχης είναι ο αμυνόμενος. Έτσι, ολόκληρος ο στρατός του επιτιθέμενου καταστρέφεται. Όσον αφορά τον στρατό του αμυνόμενου, ο τελευταίος είναι υποχρεωμένος να "χάσει" τουλάχιστον τόσους πόντους επίθεσης όσους και η διαφορά πόντων επίθεσης και πόντων άμυνας. 
Έτσι στην αρχή της περίπτωσης 4 επιλέγονται για να αμυνθούν οι λιγότερες δυνατές κάρτες έτσι ώστε να ελαχιστοποιηθεί η διαφορά μεταξύ attackPower και defPower (προφανώς ενώ το defPower είναι μεγαλύτερο). Η επιλογή αυτή γίνεται έτσι ώστε ο αμυνόμενος να χάσει όσο το δυνατόν λιγότερες προσωπικότητες μετά την μάχη. Η υλοποίηση αυτή είναι απλή καθώς επιλέγονται μια-μια οι κάρτες που θα αμυνθούν έως ότου η συνολική δύναμη άμυνας είναι μεγαλύτερη από την δύναμη του επιτιθέμενου.
Για λόγους καλύτερης ροής του παιχνιδιού επιλέξαμε οι προσωπικότητες/ακόλουθοι που απαιτείται να "χαθούν" από τον αμυνόμενο να επιλέγονται τυχαία (καθώς είναι η σειρά του επιτιθέμενου παίκτη). Διαφορετικά θα ήταν πολύ απλό να υλοποιηθεί ακριβώς ίδια με την Περίπτωση 2 καθώς η διαδικασία που θέλουμε είναι ίδια οπότε αρκούσε αυτούσιος ο κώδικας της περίπτωσης 2. Έπειτα από την παραπάνω "καταστροφή" του αμυνόμενου στρατού (η οποία εξηγείται παραπάνω, επομένως δεν χρειάζεται να περιγραφεί ξανά) τελειώνει η φάση μάχης. Στο τέλος της παραπάνω διαδικασίας γίνονται tap όσες κάρτες χρησιμοποιήθηκαν για να αμυνθούν ( isDefending==true ).



-economyPhase()

Η διαδικασία που θα εξηγηθεί παρακάτω εκτελείται επαναληπτικά για κάθε παίκτη (pl).
Η μεθοδος αυτη αναπαριστά την φάση αγορών του παιχνιδιού:
Ελέγχεται αν ο παίκτης έχει επαρχίες από όπου μπορει να αγοράσει black cards (holdings ή personalities).
Αν δεν εχει, τότε παίζει ο επόμενος σε σειρά παικτης, εκτός και αν είναι ο τελευταίος παίκτης οπότε το παιχνίδι προχωράει στην επόμενη φάση.
Αν έχει, τότε ο παίκτης διαλέγει την black card που επιθυμεί να αγορασει  (διαφορετικά "παταει" το μηδέν και τερματίζεται η σειρά του).
Η αγόρα γίνεται εφόσον ο παίκτης εχει τα επαρκή λεφτά. 
Αν δεν μπορεί να καλύψει το κόστος της κάρτας του δίνεται η δυνατότητα να επιλέξει
ξανα απο την αρχή black card ή να τερματισει την σειρά του.
O παικτης συλλέγει τα χρήματα για να αγοράσει την κάρτα που επέλεξε κάνοντας tap τα holdings που εχει στην κατοχή του (η διαδικασία σταματάει είτε οταν ο παικτης φτάσει ή ξεπερασει το
κοστος της κάρτας είτε οταν γίνουν tap ολα τα holdings). 
Όταν, αγοραστεί η κάρτα τότε μεταφέρεται ανάλογα με την κατηγορία της (Personality ή Holding) στο army ή στα holdings του παίκτη και το κενο που δημιουργήθηκε στην αντίστοιχη επαρχία αναπληρώνεται
αμέσως με μια κάρτα απο το dynasty deck, η οποία όμως ειναι "αναποδογυρισμένη" (IsReleaved==false).
Αν η κάρτα που αγόρασε ο παίκτης είναι τύπου holding τότε μεσω της συνάρτησης connectholdings() (η οποία καλείται αμέσως μετά την "πρόσθεση" της holding καρτας στην λίστα των holdings του παίκτη),
ελέγχουμε αν το holding αυτο ειναι κατηγορίας ή MINΕ ή GOLD_MINE ή CRYSTAL_MINE και στη συνέχεια ψάχνουμε αν ο παικτης αυτος εχει holdings που να ανήκουν πάλι στις ίδιες κατηγορίες
ώστε να τα συνδέσουμε σχηματίζοντας μια αλυσίδα μεταξύ τους αποφέροντας ετσι περισσότερα χρηματα στον παικτη οταν τα κάνει tap.
Συγκεκριμένα η συνάρτηση αυτή συνδέει:
MINE με GOLD_MINE,
GOLD_MINE με MINE και με CRYSTAL_MINE,
CRYSTAL_MINE με GOLD_MINE.
Οι συνδέσεις έχουν τα ανάλογα bonus στο harvest Value του καθε holding, τα οποια bonus αναφέρονται στην εκφώνηση στο σημείο: "2.2.2 Κανόνες δημιουργίας αλυσίδας και παρεχόμενα bonus"

Σημειώσεις:

* Τα holdings μπορουν να γίνουν μονο μια φορά tap σε καθε γύρο.

* Υπάρχει η περίπτωση να εχει γίνει ήδη tap κάποιων ή όλων των holdings στην equipPhase, οπότε δεν γίνεται να τα ξανακάνουμε tap.

* Τα χρηματα του παίκτη, δεν "διατηρούνται" από το equipPhase() στο economyPhase().

* Λεφτά που τυχών περισσεύουν μετα απο κάποια αγορά χάνονται ("Χαμένα λεφτά").

* Η παραπάνω διαδικασία επαναλαμβάνεται μέχρι ο παικτής να πατήσει το μηδέν (επίσης τερματίζει όταν αγοραστούν ολες οι διαθέσιμες black cards που παρέχουν για αυτο τον γύρο οι επαρχίες).
 
* Όταν δεν έχει αρκετά untapped holdings (για συλλογή χρημάτων) ωστε να κανει την αγόρα της κάρτας που έχει επιλέξει, τοτε παραλειπεται η διαδικασία "holdings tapping" και του δίνεται η
  δυνατότητα να επιλέξει άλλη κάρτα για αγορά ή να τερματίσει την σειρα του.

* Σχετικά με την δημιουργία αλυσίδας, το μέγιστο bonus που μπορει να εχουν τα holdings των σχετικών κατηγοριών είναι όταν συνδεθούν όλα μεταξύ τους έτσι: MINE<->GOLD_MINE<->CRYSTAL_MINE



-finalPhase()
 
Στην τελική φάση του παιχνιδιού αρχικά ελέγχεται αν ο παίκτης έχει υπερβεί το όριο των πράσινων καρτών στο χέρι του (hand). 
Το όριο αυτό είναι μια σταθερά που ορίζεται στο αρχείο Cards.cpp. Αν ο παίχτης έχει υπερβεί το όριο αυτό, τότε (αφού τυπωθούν όλες οι κάρτες του) επιλέγει ποια/ποιες από τις κάρτες του θέλει να "πετάξει" έτσι ώστε να είναι εντός ορίων. 
Έπειτα (εφόσον υπάρχουν) τυπώνονται οι επαρχίες, οι κάρτες στο χέρι του καθώς και τα holdings του παίκτη. Τέλος τυπώνεται η Arena του παίκτη (printArena) δηλαδή όλες οι προσωπικότητες του παίκτη καθώς και όλοι οι ακόλουθοι ή τα items της κάθε προσωπικότητας.
Η παραπάνω διαδικασία εκτελείται επαναληπτικά για κάθε έναν από τους παίκτες.
Στην συνεχεία, για κάθε παίκτη, τυπώνονται τα στατιστικά του γύρου που μόλις τέλειωσε (printGameStatistics). 
Τέλος, ελέγχεται αν υπάρχει νικητής (checkWinningCondition). Αν υπάρχει νικητής, τυπώνονται τα κατάλληλα μηνύματα και το παιχνίδι τερματίζεται. 
Αν δεν υπάρχει νικητής, ξεκινάει ο επόμενος γύρος του παιχνιδιού.

 * checkWinningCondition() : Η συνάρτηση αυτή, αρχικά, για κάθε έναν παίκτη ελέγχει αν έχουν καταστραφεί όλες οι επαρχίες του ( getProvinces()->size()==0 ) και αν ναι ο παίκτης γίνεται eliminated από το παιχνίδι (διαγράφεται από την λίστα των παικτών). Έπειτα από τις απαραίτητες διαγραφές των παικτών αν έχει μείνει μόνο ένας παίκτης στο παιχνίδι ( playersList->size()<=1 ) τότε αυτός ο παίκτης είναι ο νικητής του παιχνιδιού καθώς είναι ο μόνος που έχει τουλάχιστον μια μη κατεστραμμένη επαρχία. 
   




----------------------------------------------------------------------------------------
~Παρατηρήσεις: 

Γενικές:

-Σε όλες τις κλάσεις παρέχονται οι κατάλληλοι setters/getters έτσι ώστε στο public "κομμάτι" της κάθε κλάσης να υπάρχει μονό ότι πραγματικά χρειάζεται να είναι δημόσιο.

-Για τα decks του παιχνιδιού καθώς και για τις μετατροπές των τύπων των κάρτων χρησιμοποιήθηκαν τα αρχεία που μας δόθηκαν (DeckBuilder,Typeconverter) με κάποιες μικρές αλλαγές.

-Δεν έχει γίνει καμία αλλαγή στα στατιστικά των καρτών.

---------
🃏 CARDS:
---------

-Οι κάρτες κάθε κατηγορίας αρχικοποιούνται με τα στατιστικά που εχουν δωθεί απο τα αρχεια .txt.

-Το μελος cardText των green card αρχικοποιείται με την συμβολοσειρα "EMPTY", αφου
 δεν μας παρεχετε η συγκεκριμένη πληροφορια. 

-Κάθε Personality εχει μια λίστα δεικτών σε GreenCard που "προστίθονται" Followers ή Items (Follower "is a" GreenCard, Item "is a" GreenCard)
 (αυτο γινεται στο equipPhase). Αυτή η λίστα (με τα περιεχόμενα της) διαγράφεται αυτόματα από τον destructor του κάθε personality.

-Κάθε Personality μπορεί να έχει μέχρι τρείς ακόλουθους ή αντικειμένα στην κατοχή
 της ( ο αριθμός αυτός μπορεί να αλλάξει στο αρχείο Cards.cpp καθώς έχει οριστεί σαν σταθερά (MAXEQUIP) ).

-Κάθε personality έχει μια μεταβλητή isDefending η οποία χρησιμοποιείται μόνο κατά την διάρκεια του battlePhase (μόνο στην περίπτωση 4 καθώς σε όλες τις υπόλοιπες περιπτώσεις αμύνεται ολόκληρος ο στρατός του παίκτη). Η μεταβλητή αυτή μας "δείχνει" αν η συγκεκριμένη κάρτα χρησιμοποιείται από τον αμυνόμενο για να αμυνθεί στην συγκεκριμένη μάχη.

-Ανάλογα με την κατηγορία παρέχεται η κατάλληλη μέθοδος print() (ειναι virtual) ωστε να εκτυπωνονται 
 τα στατιστικά της κάθε κάρτας.

-Πολλές μέθοδοι στις κλάσεις ειναι virtual (όπως η παραπάνω) (ή και pure virtual) ωστε να πετυχουμε 
 προσβαση στην μεθοδο της κλασης που θελουμε, αφου χρησιμοποιούμε δεικτες κυριως στις βασικες κλασεις GreenCard
 και BlackCard.

-Ολές οι κλάσεις κληρονομούν από την βασική κλάση Card εναν int type και εναν int kind.
 Τo int type αρχικοποείται (στον constructor) πάντα με τα καταλληλα enums για τα αντικείμενα των κλάσεων Holding, Personality, Item, Follower 
 και έχουμε υλοποιήσει την μέθοδο getType() ωστε να λειτουργούν σωστά οι συναρτήσεις που μας παρέχονται στο TypeConverter.cpp (τις οποίες χρησιμοποιήσαμε αρκετά).
 Ενώ, το int kind αρχικοποείται (στον constructor) πάντα με τα καταλληλα enums για τα αντικείμενα των κλάσεων Katana, Spear, Bow, Ninjato, Wakizashi,Footsoldier, Archer, Cavalry, Bushido, Sieger, Atakebune/Naval,Attacker, Defender, Champion, Chancellor, Shogun,Plain, Mine, Gold mine, Crystal Mine, Farmland, Gift&Favour, Stronghold
 και έχουμε υλοποιήσει την μέθοδο getKind() ωστε να μπορουμε να ξέρουμε καθε φόρα το είδος μιας κάρτας 
 (χρησιμοποιήθικε στην μέθοδο Gameplay::connectholdings(), θα χρειαζόταν όμως σίγουρα σε πολύ περισσότερα σημεία σε περίπτωση πιστής αντιγραφής του παιχνιδιού).

----------
🧑 PLAYER: 
----------

-Καθε πάικτης μπορει να εχει μέχρι έξι πρασινες καρτες στο χέρι του ( ο αριθμός αυτός μπορεί να αλλάξει στο αρχείο Cards.cpp καθώς έχει οριστεί σαν σταθερά "MAXHAND" ).

-Το StrongHold ειναι το πρώτο holding για κάθε παίκτη.

-Επιλέχθηκε ως σχεδιαστική επιλογή για την αγορα των καρτών και tapping των holdings ο 1ος τρόπος που αναφέρεται στο Lists.

-Τα χαμένα λεφτά του κάθε παίκτη, εμφανίζονται μετά την αγορά μιας κάρτας.

-Χαμένα λεφτά είναι αυτά τα χρήματα που περίσεψαν μετα την αγορά της κάρτας.


-------------
🎮 GAMEBOARD:
-------------

-Μέγιστο όριο παικτων: 8 (ο αριθμός αυτός μπορεί να αλλάξει στο αρχείο Gameboard.cpp καθώς έχει οριστεί σαν σταθερά "MAXPLAYERS" ).

-H συναρτηση Gameboard::gameplay() τερματίζει όταν βρεθεί νικητής στο παιχνίδι.