Παίζοντας παιχνίδια στρατηγικής με τον αλγόριθμο Minimax

Σε αυτό το μάθημα, θα διερευνήσουμε έναν δημοφιλή αλγόριθμο που ονομάζεται minimax . Θα μάθουμε επίσης μερικές από τις φιλικές δυνατότητες πρόσθετης γειτονιάς, όπως ευρετικές βαθμολογίες , επαναληπτική εμβάθυνση και κλάδεμα άλφα-beta . Χρησιμοποιώντας αυτές τις τεχνικές, μπορούμε να δημιουργήσουμε έναν πιο ευέλικτο και ισχυρό παράγοντα παιχνιδιού. Θα είναι σε θέση να ανταγωνιστεί σε πολλές προκλήσεις, όπως το παιχνίδι στρατηγικής Απομόνωση.

Στην προηγούμενη δημοσίευση μου Πώς να κερδίσετε το Sudoku, μάθαμε πώς να διδάσκουμε υπολογιστές για την επίλυση του παζλ Sudoku. Εάν δεν το έχετε διαβάσει, προχωρήστε και δώστε του μια γρήγορη ανάγνωση. Αλλά αυτός ήταν πραγματικά ένας τρόπος να βραχεί τα πόδια μας, προτού καταδυθούμε σε πιο εξελιγμένες μεθόδους πρακτόρων παιχνιδιού. Ειδικά αυτές οι μέθοδοι που μπορούν να κάνουν στρατηγικές κινήσεις εναντίον ενός αντιπάλου!

Μην μπερδευτείτε

Το Isolation (ή Isola) είναι ένα επιτραπέζιο παιχνίδι στρατηγικής με βάση τη σειρά, όπου δύο παίκτες προσπαθούν να περιορίσουν τον αντίπαλό τους σε ένα 7x7 πούλι. Τελικά, δεν μπορούν πλέον να κάνουν κίνηση (απομόνωση τους).

Κάθε παίκτης έχει ένα κομμάτι, το οποίο μπορεί να κινείται σαν βασίλισσα στο σκάκι - πάνω-κάτω, αριστερά-δεξιά και διαγώνια. Υπάρχουν τρεις συνθήκες υπό τις οποίες μπορούν να μετακινηθούν τα κομμάτια -

  1. Δεν μπορούν να τοποθετήσουν το κομμάτι τους σε μια πλατεία που έχει ήδη επισκεφθεί.
  2. Δεν μπορούν να διασχίσουν τις πλατείες που έχουν ήδη επισκεφθεί (το να πιέζετε διαγώνια είναι εντάξει).
  3. Δεν μπορούν να διασχίσουν το κομμάτι του άλλου.

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

Τώρα αυτό μπορεί να φαίνεται σαν ένα απλό παιχνίδι - και για να είμαι ειλικρινής, είναι. Δεν είναι σαν να παίζουμε πόκερ ή Starcraft. Ωστόσο, υπάρχει ακόμη τεράστιος αριθμός πιθανών κινήσεων που μπορεί να κάνει ο κάθε παίκτης σε οποιοδήποτε σημείο κατά τη διάρκεια του παιχνιδιού.

Σε παζλ όπως το Sudoku, υπάρχει μια «απάντηση» για την οποία θέλουμε να λύσουμε. Αλλά δεν υπάρχει απάντηση όταν πρόκειται για παιχνίδια στρατηγικής.

Παίζουμε εναντίον άλλου αντιπάλου - όπως άτομο, υπολογιστή ή ντετέκτιβ γάτας. Αυτό απαιτεί στρατηγική και κάποια σκέψη για το πώς μπορεί να αποδειχθεί το παιχνίδι καθώς συνεχίζεται.

Τέτοια παιχνίδια μπορούν να εξελιχθούν και να παράγουν παράλογο ποσό πιθανών αποτελεσμάτων. Πρέπει λοιπόν να σκεφτούμε πώς μπορούμε να επιλέξουμε την καλύτερη δυνατή κίνηση, χωρίς να ξοδέψουμε το χρόνο που χρειάστηκε για να κατοικούν οι γάτες στη Γη.

Εντάξει, όχι άλλες γάτες!

Mighty Minimax και φίλοι

Τώρα που ξέρετε πώς να παίξετε το Isolation, ας ρίξουμε μια ματιά στο πώς μπορούμε να χρησιμοποιήσουμε τον αλγόριθμο ελαχιστοποίησης . βασικό στην κοινότητα AI. Θα εξετάσουμε επίσης ευρετικές βαθμολογίες , επαναληπτική εμβάθυνση και κλάδεμα άλφα-βήτα . Μαζί με αυτά, μπορούμε να δημιουργήσουμε έναν ανταγωνιστικό παράγοντα AI.

Ελάχιστο

Ο αλγόριθμος minimax είναι πολύ δημοφιλής για τη διδασκαλία των πρακτόρων AI πώς να παίζουν παιχνίδια στρατηγικής με βάση τη σειρά. Ο λόγος είναι ότι λαμβάνει υπόψη όλες τις πιθανές κινήσεις που μπορούν να κάνουν οι παίκτες ανά πάσα στιγμή κατά τη διάρκεια του παιχνιδιού. Με αυτές τις πληροφορίες, προσπαθεί στη συνέχεια να ελαχιστοποιήσει το πλεονέκτημα του παίκτη του αντιπάλου, μεγιστοποιώντας παράλληλα τον πράκτορα σε κάθε στροφή που παίζει ο πράκτορας AI.

Τώρα, πώς φαίνεται αυτό;

Λοιπόν, παρόμοιο με το πώς ένας πράκτορας AI θα έπαιζε ένα παιχνίδι όπως το Sudoku, μπορούμε να μοντελοποιήσουμε τις επόμενες πιθανές κινήσεις που μπορεί να κάνει ένας παίκτης μέσω ενός δέντρου αναζήτησης . Ωστόσο, θα πρέπει να χρησιμοποιήσουμε ένα δέντρο αναζήτησης με μεταβλητά πλάτη - ή με άλλα λόγια, το πλάτος ενός δέντρου. Ο λόγος είναι ότι υπάρχει ένας μεταβλητός αριθμός κινήσεων που κάθε παίκτης μπορεί να κάνει ανά πάσα στιγμή κατά τη διάρκεια του παιχνιδιού.

Το δέντρο που φαίνεται παραπάνω αντιπροσωπεύει τις επόμενες κινήσεις που είναι διαθέσιμες κατά τη διάρκεια ενός παιχνιδιού απομόνωσης. Έχει πλέγμα 2x3, με το κάτω δεξί τετράγωνο να μην είναι προσβάσιμο. Όπως μπορείτε να δείτε, οι δύο παίκτες είναι ένας μπλε κύκλος και ένας κόκκινος σταυρός.

Η κορυφή του δέντρου (ο ριζικός κόμβος) απεικονίζει μια κίνηση που έκανε η κόκκινη συσκευή αναπαραγωγής. Το μεσαίο επίπεδο δείχνει τις επόμενες πιθανές κινήσεις από τον μπλε παίκτη. Και το τρίτο επίπεδο δείχνει τις πιθανές κινήσεις του κόκκινου παίκτη, δεδομένης της προηγούμενης κίνησης που έκανε ο μπλε παίκτης.

Κάθε κατάσταση παιχνιδιού ή κόμβος στο δέντρο έχει πληροφορίες σχετικά με το ποιος παίκτης έχει το μεγαλύτερο κέρδος από οποιαδήποτε πιθανή κίνηση.

Τώρα μπορεί να αναρωτιέστε, τι καλό είναι αυτά τα τρίγωνα κάτω από κάθε κίνηση;

Το προς τα κάτω τρίγωνο αντιπροσωπεύει μια θέση στο δέντρο όπου το ελάχιστο θα ελαχιστοποιήσει το πλεονέκτημα του αντιπάλου. Ενώ, τα ανοδικά τρίγωνα είναι οι θέσεις όπου το ελάχιστο μεγιστοποιεί το πλεονέκτημα του πράκτορα.

Αλλά το ελάχιστο μπορεί να γνωρίζει το πλεονέκτημα των δύο παικτών μόνο εάν γνωρίζει τις διαδρομές στο δέντρο που οδηγούν στη νίκη και για τους δύο παίκτες. Αυτό σημαίνει ότι το ελάχιστο πρέπει να διασχίζει στο κάτω μέρος του δέντρου για κάθε πιθανή σειρά κινήσεων. Στη συνέχεια, πρέπει να αντιστοιχίσει κάποιο σκορ (π.χ., +1 για μια νίκη και -1 για μια ήττα), και να διαδώσει αυτούς τους αριθμούς μέχρι το δέντρο. Με αυτόν τον τρόπο, κάθε κατάσταση παιχνιδιού ή κόμβος στο δέντρο έχει πληροφορίες σχετικά με το ποιος παίκτης έχει το μεγαλύτερο κέρδος από οποιαδήποτε πιθανή κίνηση.

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

Το δεύτερο επίπεδο μετά τον ριζικό κόμβο δείχνει τις επόμενες πιθανές κινήσεις για το μπλε πρόγραμμα αναπαραγωγής (ο παράγοντας AI μας). Ο αντιπρόσωπός μας θέλει να μεγιστοποιήσει τις διαθέσιμες βαθμολογίες κατά τη σειρά του. Έτσι θα επέλεγε την κίνηση που αναπαριστάται στον κόμβο με τα περισσότερα δεξιά μετά τον ριζικό κόμβο. Εξαιρετικά δροσερό!

Αλλά έχει νόημα να απλώς ορίσετε ένα +1 ή -1 στα αποτελέσματα του παιχνιδιού; Δεν θα έπρεπε αυτό το σκορ να λάβει υπόψη πώς κερδίζει ή χάνεται το παιχνίδι;

Ειδοποίηση Spoiler: η απάντηση είναι ναι!

Ευρετικά σκορ

Στον κόσμο των παιχνιδιών στρατηγικής, ένα ευρετικό σκορ είναι ουσιαστικά μια υποκειμενική αξία που αποδίδουμε σε κάποια κατάσταση του παιχνιδιού. Αυτή η αξία βασίζεται στην κατανόησή μας για το πώς κερδίζεται και χάνεται το παιχνίδι. Επιλέγοντας ένα καλά μελετημένο ευρετικό σκορ, είμαστε σε θέση να διδάξουμε στον πράκτορα AI πώς να επιλέξει καλύτερα τις επόμενες κινήσεις του ενώ παίζετε το παιχνίδι Isolation.

Τώρα υπάρχει πιθανώς ένας απεριόριστος αριθμός ευρετικών βαθμολογιών που θα μπορούσαμε να βρούμε. Αλλά εδώ θα δούμε μόνο μερικά από αυτά, εκτός από το αφελές σκορ (NS) των +1 και -1.

Μια ιδέα θα μπορούσε να είναι να μετρήσουμε όλες τις επόμενες πιθανές κινήσεις που έχει κάθε παίκτης ανά πάσα στιγμή, καθώς οι περισσότερες πιθανές κινήσεις σημαίνουν λιγότερες πιθανότητες να απομονωθούν. Θα το ονομάσουμε αυτό το σκορ ανοιχτής κίνησης (OMS) .

Μια άλλη ιδέα θα μπορούσε να είναι η χρήση της τιμής που αποκτήθηκε από το OMS και η αφαίρεση του αριθμού των επόμενων πιθανών κινήσεων που έχει ο αντίπαλος. Ο λόγος είναι ότι κάθε παίκτης θέλει να αυξήσει το ποσό των κινήσεών του, μειώνοντας παράλληλα τον αντίπαλό του. Θα το ονομάσουμε το βελτιωμένο σκορ (IS) .

Το παραπάνω σχήμα δείχνει τα ποσοστά νίκης σε πολλά προσομοιωμένα παιχνίδια απομόνωσης που παίζονται μεταξύ των πρακτόρων AI χρησιμοποιώντας διαφορετικά ευρετικά σκορ. Τώρα μπορείτε να δείτε πόσο διαφορετικά έκαναν τα σκορ μας κατά τη διάρκεια του πραγματικού παιχνιδιού. Ωστόσο, υπήρχαν κάποιες ευρετικές βαθμολογίες που ξεπέρασαν τις βαθμολογίες με τις οποίες δημιουργήσαμε

Είναι ενδιαφέρον ότι οι δύο πρώτοι είναι σχεδόν ίδιοι με τη βελτιωμένη βαθμολογία. Θα τους ονομάσουμε επιθετική βελτιωμένη βαθμολογία (AIS) και εξαιρετικά επιθετική βελτιωμένη βαθμολογία (SAIS) . Αλλά υπάρχει μια μικρή διαφορά μεταξύ αυτών των αποτελεσμάτων και του πρωτότυπου. Οι δύο πρώτες βαθμολογίες εφαρμόζουν έναν συντελεστή δύο και τριών στην τιμή με την οποία αφαιρείτε (ο αριθμός των κινήσεων που διατίθενται στον αντίπαλο) κατά τον υπολογισμό της βελτιωμένης βαθμολογίας.

Μπορείτε να ανακαλύψετε έναν βέλτιστο «επιθετικό παράγοντα» για εφαρμογή κατά τον υπολογισμό αυτής της βαθμολογίας!

Μια άλλη ειδοποίηση spoiler - υπάρχουν καλύτερες τιμές.

Τι γίνεται όμως αν καταλήξουμε σε μια ευρετική βαθμολογία που απαιτεί πολύ χρόνο για να υπολογίσουμε; Τι γίνεται αν το δέντρο είναι τεράστιο; Θα έχει ο παράγοντας AI μας αρκετό χρόνο για να βρει τις επόμενες καλύτερες κινήσεις του, ενώ εξακολουθεί να ανταποκρίνεται αρκετά κατά τη διάρκεια του παιχνιδιού;

Επαναληπτική εμβάθυνση

Τώρα γνωρίζουμε ότι ο πράκτορας AI μπορεί να μοντελοποιήσει όλες τις πιθανές κινήσεις χρησιμοποιώντας ένα δέντρο αναζήτησης και την αντίστοιχη ευρετική βαθμολογία των κόμβων του. Δυστυχώς όμως, όταν παίζουμε το Isolation, το δέντρο μας θα είναι τεράστιο. Θα χρειαζόταν περισσότερος χρόνος για την αναζήτηση του δέντρου και τον υπολογισμό αυτών των τιμών από ό, τι υπάρχουν χρόνια από το big bang!

Εισαγάγετε την επαναληπτική εμβάθυνση - τη στρατηγική διαχείρισης του χρόνου για πράκτορες παιχνιδιού. Με τη χρήση αυτής της μεθόδου, μπορούμε να μειώσουμε τον χρόνο υπολογισμού και αναζήτησης έως τον μέγιστο χρόνο επιλογής μας. Με αυτόν τον τρόπο, ο παράγοντας AI μπορεί να ανταποκριθεί τουλάχιστον όσο πιο γρήγορα θα μπορούσε ένας άνθρωπος.

Αλλά πώς λειτουργεί η επαναληπτική εμβάθυνση;

Επιτρέπει στο ελάχιστο να μετακινείται επίπεδο προς επίπεδο και να υπολογίζει ευρετικές βαθμολογίες μέχρι ένα συγκεκριμένο χρονικό όριο. Μόλις επιτευχθεί αυτό το χρονικό όριο, ο πράκτορας AI αναγκάζεται να χρησιμοποιήσει την καλύτερη κίνηση που ανακάλυψε ενώ είχε μετακινηθεί όλο και πιο βαθιά στο δέντρο.

Τώρα αυτό παρέχει κάποια εικόνα για το πόσο δύσκολο μπορεί να είναι. Η δημιουργία ενός παράγοντα τεχνητής νοημοσύνης που είναι αρκετά έξυπνη και ανταποκρίνεται αρκετά για παιχνίδια στρατηγικής, μπορεί να είναι αρκετά δύσκολη, ακόμη και για τους μάγους AI. Ειδικά αν τέτοια παιχνίδια περιέχουν έναν κόσμο δυνατοτήτων.

Δυστυχώς, ο αριθμός των κινήσεων που μπορεί να «φανταστεί» ο πράκτορας AI να προχωρήσει είναι περιορισμένος. Έτσι είναι πιθανό να μπορούσε να πάρει μια απόφαση που οδηγεί στο θάνατό της. Αυτό είναι ένα πολύ γνωστό φαινόμενο που ονομάζεται φαινόμενο ορίζοντα . Ωστόσο, πρέπει να εξετάσουμε αναμφισβήτητα τον πιο αποτελεσματικό αλγόριθμο χρονικής περικοπής που χρησιμοποιείται κατά την αναζήτηση δέντρων.

Κλάδεμα άλφα-βήτα

Εντάξει, αυτές είναι σταφίδες και όχι δαμάσκηνα, αλλά ακόμα - πώς ήταν κάτι τέτοιο; Εννοώ, σοβαρά, μια ομάδα σταφίδας μπλε;

Ίσως έχετε ήδη μαντέψει ότι το κλάδεμα άλφα-βήτα δεν έχει καμία σχέση με τα δαμάσκηνα και περισσότερο σχετικά με τη μείωση του μεγέθους (κλάδεμα) του δέντρου αναζήτησης. Όταν έχουμε ένα πολύ μεγάλο δέντρο αναζήτησης, αποδεικνύεται ότι δεν είναι πάντα απαραίτητο να διασχίζουμε κάθε κόμβο όταν χρησιμοποιείτε ελάχιστα.

Πρέπει να δώσουμε στο ελάχιστο τη δυνατότητα να σταματήσουμε την αναζήτηση μιας συγκεκριμένης περιοχής του δέντρου όταν βρίσκει το εγγυημένο ελάχιστο ή μέγιστο του συγκεκριμένου επιπέδου.

Εάν μπορούμε να το κάνουμε αυτό, αυτό μπορεί να μειώσει σημαντικά τον χρόνο απόκρισης του παράγοντα AI και να βελτιώσει την απόδοση.

Πώς λειτουργεί το κλάδεμα άλφα-βήτα;

Ο αλγόριθμος ελαχιστοποίησης κινείται μέσω του δέντρου χρησιμοποιώντας αναζήτηση πρώτου βάθους. Αυτό σημαίνει ότι διασχίζει το δέντρο πηγαίνοντας από αριστερά προς τα δεξιά, και πάντα πηγαίνοντας το πιο βαθύ μπορεί να πάει. Στη συνέχεια ανακαλύπτει τιμές που πρέπει να εκχωρηθούν σε κόμβους ακριβώς πάνω από αυτό, χωρίς να κοιτάξει ποτέ άλλα κλαδιά του δέντρου.

Το κλάδεμα άλφα-beta επιτρέπει στο minimax να λαμβάνει εξίσου καλές αποφάσεις με το minimax που μπορεί να κάνει μόνος του, αλλά με υψηλότερο επίπεδο απόδοσης.

Εξετάστε την παρακάτω εικόνα, στην οποία έχουμε ένα δέντρο με διάφορες βαθμολογίες σε κάθε κόμβο. Ορισμένοι κόμβοι είναι σκιασμένοι με κόκκινο χρώμα, υποδεικνύοντας ότι δεν χρειάζεται να τους ελέγξετε.

Κάτω αριστερά του δέντρου, το ελάχιστο βλέπει τις τιμές 5 και 6 στο κάτω ανώτατο επίπεδο. Καθορίζει ότι 5 πρέπει να αντιστοιχιστούν στο ελάχιστο επίπεδο ακριβώς πάνω από αυτό. Βγάζει νόημα.

Όμως, αφού κοιτάξουμε τα 7 και 4 του σωστού μέγιστου επιπέδου κλάδου, συνειδητοποιεί ότι στον παραπάνω κόμβο ελάχιστου επιπέδου πρέπει να εκχωρηθεί μέγιστη τιμή 4. Δεδομένου ότι το δεύτερο ανώτατο επίπεδο ακριβώς πάνω από το πρώτο επίπεδο ελάχιστου θα πάρει το μέγιστο μεταξύ 5 και το πολύ 4, είναι σαφές ότι θα επιλέξει 5. Μετά από αυτό, θα συνεχίσει να διασχίζει το δέντρο για να εκτελέσει το ίδιο ακριβές σύνολο λειτουργιών εντός των άλλων κλάδων του δέντρου.

Ακολουθεί η αλγοριθμική αναπαράσταση του ελάχιστου με το κλάδεμα άλφα-βήτα.

Η χρήση αυτής της μεθόδου παρέχει έναν εύκολο τρόπο μείωσης του χώρου αναζήτησης του πράκτορα AI. Με αυτόν τον τρόπο, το κλάδεμα άλφα-beta επιτρέπει στο minimax να λαμβάνει καλές αποφάσεις που το minimax θα μπορούσε να κάνει μόνος του, αλλά με υψηλότερο επίπεδο απόδοσης.

Isola-ter

Έχουμε διερευνήσει πώς να δημιουργήσουμε το δικό μας παράγοντα AI που μπορεί να παίξει το παιχνίδι Isolation σε αρκετά ανταγωνιστικό επίπεδο. Χρησιμοποιώντας τον αλγόριθμο minmax, είδαμε πώς ο πράκτορας AI μπορεί να μοντελοποιήσει το παιχνίδι και να λαμβάνει αποφάσεις με βάση μια ευρετική βαθμολογία. Μάθαμε επίσης πώς να προσδιορίσουμε μια σαφώς καθορισμένη ευρετική για τη δεδομένη εργασία μας (Απομόνωση).

Αλλά ανακαλύψαμε επίσης ότι θα ήταν υπερβολικά υπολογιστικό έντονο για να αφήσουμε το minimax να τρέξει. Επομένως, έπρεπε να χρησιμοποιήσουμε τεχνικές όπως επαναληπτική εμβάθυνση και κλάδεμα άλφα-βήτα. Αυτά θα αναγκάζονταν τον πράκτορα AI να βρει την επόμενη κίνηση εντός εύλογου χρονικού διαστήματος. Τι γίνεται όμως αν θέλουμε ο πράκτορας AI να έχει υψηλότερο ποσοστό νίκης, ενώ τουλάχιστον να ανταποκρίνεται τόσο στον άνθρωπο;

Λοιπόν, υπάρχουν και άλλες τεχνικές που θα μπορούσαμε να διερευνήσουμε για να αυξήσουμε το ποσοστό νίκης του πράκτορα μας καθώς και το χρόνο απόκρισης. Αγγίξαμε την ιδέα να τροποποιήσουμε τις παραμέτρους του ευρετικού μας σκορ (θυμηθείτε τον «επιθετικό παράγοντα»;). Θα μπορούσαμε ακόμη και να βρούμε ένα ευρετικό σκορ καλύτερα προσαρμοσμένο για να παίξουμε Isolation.

Υπάρχουν επίσης ανακλαστικές ιδιότητες που σχετίζονται με τις πιθανές κινήσεις στον πίνακα απομόνωσης. Αυτά γίνονται εμφανή όταν αναλύουμε το πλήρως κατοικημένο δέντρο αναζήτησης, το οποίο θα μας επέτρεπε ενδεχομένως να κόβουμε πολλά κλαδιά από το δέντρο αναζήτησης. Επίσης, εάν αναβαθμίσαμε το υλικό μας, ο πράκτορας AI θα ήταν πιο γρήγορος - και έτσι θα μπορούσαμε να διερευνήσουμε περισσότερες δυνατότητες.

Εάν θέλετε να μπείτε στις όμορφες λεπτομέρειες για το πώς να το εφαρμόσετε μόνοι σας, ρίξτε μια ματιά στον κώδικα που έγραψα για να λύσετε αυτό το πρόβλημα για το Nanodegree Udacity Artificial Intelligence. Μπορείτε να το βρείτε στο repo GitHub μου.

Γεια, είμαι Grant! Είμαι ανεξάρτητος dev και quant. Δείτε τον ιστότοπό μου στη διεύθυνση //freelancequant.com. Στην υγειά σας!