Αυτόνομοι Πράκτορες Εργασία εξαμήνου Μάθηση του παιχνιδιού British square με χρήση Temporal Difference(TD) Κωνσταντάκης Γιώργος 2010030090
Περιγραφή του παιχνιδιού Το British square είναι ένα επιτραπέζιο παιχνίδι το οποίο παίζεται σε ένα 5x5 ταμπλό από 2 παίκτες. Οι παίκτες παίζουν εναλλάξ τοποθετώντας πούλια σε κάποιο από τα διαθέσιμα τετράγωνα του ταμπλό. Ο μοναδικός κανόνας είναι να ότι κάποιος παίκτης δεν μπορεί να τοποθετήσει κάποιο πούλι σε γειτονικό τετράγωνο από κάποιο πούλι του αντιπάλου. Γειτονικά τετράγωνα θεωρούνται αυτά τα οποία βρίσκονται πάνω, κάτω, δεξιά και αριστερά από κάθε πούλι. Τα διαγώνια τετράγωνα δεν θεωρούνται γειτονικά. Το παιχνίδι τελειώνει όταν κάποιος παίκτης δεν μπορεί να τοποθετήσει κάποιο πούλι στο ταμπλό. Όταν το παιχνίδι τελειώσει μετρούνται τα πούλια του κάθε παίκτης και αυτός που έχει τα περισσότερα κερδίζει. Το παιχνίδι μπορεί να παιχτεί και σε μεγαλύτερα ταμπλό.
Στην παραπάνω εικόνα βλέπω ένα παιχνίδι το οποίο έχει τελειώσει μιας και κανένας από τους 2 παίκτες δεν μπορεί να τοποθετήσει κάποιο πούλι χωρίς να παραβιάσει τον κανόνα δηλαδή χωρίς να τοποθετήσει πούλι σε γειτονικό τετράγωνο από πούλι του αντιπάλου. Ο νικητής του συγκεκριμένου παιχνιδιού είναι ο κόκκινος με 7 πούλια έναντι του μπλε με έξι. Περιγραφή εργασίας Σαν εργασία του μαθήματος επέλεξα να υλοποιήσω το παραπάνω παιχνίδι στον υπολογιστή και να εφαρμόσω έναν αλγόριθμο μάθησης ώστε ο υπολογιστής να «μάθει» να παίζει το παιχνίδι μέσω κάποιας λογικής και όχι απλά τυχαία. Για μάθηση χρησιμοποίησα τον αλγόριθμο Temporal Difference (TD) Learning. Η μάθηση γίνεται με τον εξής τρόπο. Για να έχουμε μια καλή evaluation function χρειάζεται αρχικά να βρούμε features τα οποία περιγράφουν το παιχνίδι κάθε στιγμή. Δηλαδή συναρτήσεις που περιγράφουν σε τι κατάσταση είναι το παιχνίδι την εκάστοτε στιγμή. Τα features που χρησιμοποίησα στην δικιά μου υλοποίηση περιγράφονται παρακάτω στην υλοποίηση της εργασίας. Αφότου λοιπόν επιλέξουμε τα κατάλληλα features τα συνδυάζουμε με κάποια βάρη και με τον τρόπο αυτό υλοποιούμε την evaluation function. Ο τύπος της είναι ο παρακάτω i=k V(s) = φ(i) w(i) i=0
Όπου φ(i) είναι η τιμή του κάθε feature, το w(i) η τιμή του κάθε βάρους και k είναι ο αριθμός των features. Μετά από κάθε γύρο που παίζει ο πράκτορας μας γίνεται ανανέωση των βαρών. Τα βάρη ανανεώνονται με βάση την παρακάτω συνάρτηση. w(i) = w(i) + a φ(i) [V(s ) V(s)] Όπου w(i) είναι η τιμή του βάρους που έχει πριν την ανανέωση, α είναι ο ρυθμός μάθησης, φ(i) είναι η τιμή του κάθε feature i, V(s) είναι η τιμή αξιολόγηση της κατάστασης s στην οποία βρίσκεται αυτή την χρονική στιγμή το παιχνίδι και V(s ) είναι η τιμή αξιολόγηση της κατάστασης s η οποία είναι η επόμενη κατάσταση του παιχνιδιού. Για να βρούμε την s γίνεται η χρήση του αλγορίθμου minimax θεωρώντας ότι ο παίκτης max είναι ο πράκτορας μας ενώ ο παίκτης min είναι ο αντίπαλος. Αρχικά γίνεται ένας μεγάλος αριθμός επαναλήψεων στις οποίες ο πράκτορας και ο αντίπαλος παίζουν τυχαία και αυτό γίνεται για να περάσει ο πράκτορας από όσες περισσότερες καταστάσεις γίνεται ώστε να υπολογιστούν σωστότερα τα βάρη. Οι επαναλήψεις αυτές είναι η περίοδος που ο πράκτορας κάνει learning. Στην συνέχεια αφότου έχουν ανανεωθεί τα βάρη ο πράκτορας να κάνει learning και επιλέγει την κίνηση η οποία έχει την μεγαλύτερη τιμή σύμφωνα με την συνάρτηση V(s).
Υλοποίηση εργασίας Η δημιουργία του παιχνιδιού έγινε σε Java. Αρχικά για την λειτουργία του παιχνιδιού χρησιμοποιώ ένα δισδιάστατο πίνακα μεγέθους 5x5,που αποτελεί το ταμπλό του παιχνιδιού οποίος σε κάθε θέση του έχει τις τιμές 0,1,2 οι οποίες αντιπροσωπεύουν την κενή θέση, το πούλι του παίκτη 1 και το πούλι του παίκτη 2 αντίστοιχα. Επίσης οι αρχικές τιμές των βαρών είναι 1. Όταν ο αλγόριθμός βρει μια τερματική κατάσταση της δίνει τιμή V(s)=10000 αν είναι κερδοφόρα αλλιώς V(s)= -10000 Κλάσεις και μέθοδοι που χρησιμοποιήθηκαν: Για το ταμπλό του παιχνιδιού χρησιμοποίησα τις παρακάτω κλάσεις Board, ChessLabel, ChessPart, Pawn, Screen, οι οποίες μα δόθηκαν στο μάθημα της τεχνητής νοημοσύνης για την χρήση στο project του μαθήματος. Εγώ το προσάρμοσα ώστε το ταμπλό να είναι 5x5, και τα πούλια που χρησιμοποιώ είναι τα στρατιωτάκια. Η κλάση run είναι αυτή που δημιούργησα εγώ και η οποία περιέχει τον κώδικα για την λειτουργία του παιχνιδιού και την μάθηση. Παρακάτω περιγράφω τις μεθόδους που υπάρχουν και την λειτουργεία τους. Validity(x, y, player). H μέθοδος αυτή παίρνει σαν όρισμα τις συντεταγμένες x, y και τον παίκτη οποίος παίζει (1 ή 2) και ελέγχει αν ο παίκτης player μπορεί να τοποθετήσει πούλι στην θέση x, y. Ο έλεγχος γίνεται με βάση τον πίνακα temp_board που όπως ανέφερα στην αρχή αποτελεί το ταμπλό. Αν η
κίνηση επιτρέπεται η μέθοδος επιστρέφει true αλλιώς false. the_user_plays( player) H μέθοδος αυτή παίρνει σαν όρισμα ποιος παίκτης είναι αυτός που παίζει (1 ή 2). Η λειτουργία της μεθόδου είναι αν κάποιος πραγματικός παίκτης θέλει να παίξει απέναντι από τον υπολογιστή. Οπότε παίρνει σαν είσοδο 2 τιμές που αποτελούν τις συντεταγμένες που ο παίκτης θέλει να τοποθετήσει το πούλι του, ελέγχει αν είναι έγκυρες και στην συνέχεια επιστρέφει τις τιμές ώστε να τοποθετηθεί το πούλι στο board. the_compouter_plays(player) Έχει ακριβώς την ίδια λειτουργία με την από πάνω μέθοδο με την διαφορά ότι τις 2 τιμές της παράγει τυχαία το πρόγραμμα μέσω της συνάρτησης random. Αυτός είναι ο κώδικας με τον οποίο παίζει και ο αντίπαλος. ready_agent(player) H μέθοδος αυτή καλείται όταν έχει ήδη γίνει μάθηση δηλαδή και διαβάζει τα βάρη για να υπολογίσει το evaluation function για την κάθε κίνηση. Για να επιλέξω την κατάλληλη κίνηση χρησιμοποιώ το minimax. the_end(player) Η μέθοδος αυτή παίρνει σαν όρισμα ένα παίκτη και ελέγχει αν αυτό ο παίκτης έχει κάποια διαθέσιμη κίνηση (ο έλεγχος γίνεται με χρήση της μεθόδου validity). Αν ο παίκτης έχει κάποια διαθέσιμη κίνηση τότε επιστρέφει false αλλιώς αν δεν υπάρχει διαθέσιμη κίνηση για τον συγκεκριμένο παίκτη επιστρέφει true.
are_you_winning(player) Η μέθοδος αυτή παίρνει σαν όρισμα ένα παίκτη και ελέγχει αν ο συγκεκριμένος παίκτης έχει περισσότερα πούλια την συγκεκριμένη στιγμή από τον αντίπαλο του. Αν ισχύει επιστρέφει true ειδάλλως επιστρέφει false. fi_calculation() H μέθοδος αυτή συμπληρώνει το πίνα με τα φ(i) ανάλογα με τις τιμές που έχουν την συγκεκριμένη στιγμή Τα Features που χρησιμοποιώ είναι τα εξής: 1. Τα δικά μου πούλια 2. Τα πούλια του αντιπάλου 3. Πούλια δικά μου στις γωνίες 4. Πούλια του αντιπάλου στις γωνίες 5. Διαθέσιμες κινήσεις δικές μου 6. Διαθέσιμες κινήσεις του αντιπάλου 7. Πούλια δικά μου σε μεσαίες θέσεις 8. Πούλια του αντιπάλου σε μεσαίες θέσεις minimax_min(player) Η μέθοδος αυτή παίρνει σαν όρισμα τον player (1 ή 2). Υπολογίζει το value με βάση την evaluation function και επιλέγει την ελάχιστη τιμή και στο τέλος την επιστρέφει minimax_max(player) Και αυτή η μέθοδος παίρνει σαν όρισμα τον player. Στην συνέχεια με βάση της τιμές που επιστρέφει η παραπάνω μέθοδος ( minimax_min ) βρίσκει την μέγιστη και την κρατάει. Αυτές οι 2 μέθοδοι χρησιμοποιώντας για το minimax. Έτσι τελικά έχουμε υπολογίσει το V(s ) που ανέφερα στην περιγραφή παραπάνω. Οπότε τώρα εφαρμόζοντας την εξίσωση για το update των βαρών που έχω αναφέρει παραπάνω ανανεώνονται τα βάρη.
learning_agent(player) Η μέθοδος αυτή χρησιμοποιείται για να καλέσει την παραπάνω μέθοδος. Στην συνέχεια επιλέγει μια τυχαία κίνηση για να παίξει ο πράκτορας. Τέλος έχουμε την συνάρτηση main η οποία καλεί τις μεθόδους των πρακτόρων για να παίξουν ανάλογα με την επιλογή που θα κάνει ο χρήστης. Αν εκτελεί 1 η φορά τον κώδικά πρέπει να επιλέξει την 1 η επιλογή για να δημιουργήσει ο πράκτορας το αρχείο με τα βάρη. Τις επόμενες φορές μπορεί να επιλέξει την 2 η επιλογή ώστε να διαβάσει τις τιμές των βαρών από το αρχείο και να παίξει με βάση αυτές. Αποτελέσματα Στα αποτελέσματα για κάποιο λόγο έχουμε πάρα πολλές ισοπαλίες όπως επίσης δεν πρόσεξα να υπάρχει βελτίωση σε σχέση με τον πράκτορα που παίζει τυχαία. Ο λόγος πιστεύω είναι ότι μάλλον δεν έχω επιλέξει «καλά» features, όπως επίσης ότι και ο αντίπαλος παίζει τελείως τυχαία. Οπότε σαν βελτίωση πιστεύω ότι ίσως θα μπορούσαν να επιλεγούν καλύτερα features και να δοκιμαστεί απέναντι σε ένα αντίπαλο που θα έπαιζε με βάση κάποια στρατηγική.