Σάββατο 18 Δεκεμβρίου 2021

Κάρελ το Ρομπότ (Δημιουργός Κόσμου - Μέρος Δεύτερο)

 Ολοκληρώθηκε το πρόγραμμα που φτιάχνει Κόσμους για το Κάρελ το Ρομπότ.


Πρόλογος

Στο πρόγραμμα αυτό εφαρμόζεται προγραμματισμός με γεγονότα, με ορισμό "ελαφριών" γεγονότων σε αντικείμενα που δημιουργούμε. Λέγονται "ελαφριά" στη Μ2000 για να ξεχωρίζουν από τα αντικείμενα τύπου Γεγονός. Τα αντικείμενα τύπου Γεγονός που δεν έχουμε σε αυτό το πρόγραμμα είναι λίστες συναρτήσεων με κοινή υπογραφή (με καθορισμένο αριθμό ορισμάτων και βασικό τύπο ορισμάτων - αριθμητικό ή αλφαριθμητικό, πίνακας ή απλή μεταβλητή, πέρασμα με ή χωρίς αναφορά). Τα αντικείμενα αυτά έχουν μια Κάλεσε Γεγονός που με μια κλήση καλούνται όλες οι συναρτήσεις (κάποιες από αυτές μπορεί να είναι αναφορές σε συναρτήσεις αντικειμένων, οπότε η κλήση οδηγείται σε αντικείμενα, κάποιες άλλες μπορεί να είναι "ψεύτικες" συναρτήσεις σε τμήματα όπου η κλήση είναι σαν κλήση γεγονότος ή "call back"). Τα ελαφριά γεγονότα έχουν τη διαφορά ότι δεν έχουν λίστα συναρτήσεων και ο διερμηνευτής κρατάει το που ορίσαμε το αντικείμενο ΜεΓεγονότα (είναι μια λέξη που βάζουμε κατά τον ορισμό τους), και όταν καλούμε ένα γεγονός, δεν εξετάζει καν πόσα ορίσματα και τι θα στείλουμε, απλά κοιτάει αν υπάρχει συνάρτηση εξυπηρέτησης εκεί που υποτίθεται θα υπάρχει, και αν όχι τότε απλά πετάει τα ορίσματα και συνεχίζει το πρόγραμμα, ενώ αν ναι τότε καλεί τη συνάρτηση εξυπηρέτησης σαν να ήταν κώδικας του τμήματος που βρίσκεται η συνάρτηση, δηλαδή με θέαση ίδια με αυτή του τμήματος (εκτός από τις στατικές ρουτίνες του τμήματος που δεν τις βλέπουν αυτές οι συναρτήσεις). Αυτές είναι οι κλήσεις τύπου "call back". Μια call back κλήση είναι η κλήση που γίνεται από αυτό που καλούμε προς το μέρος μας, πριν τερματίσει αυτό που καλούμε. Δεν θα είχε νόημα αυτή η κλήση αν η call back συνάρτηση ή ότι άλλο δεν είχε πρόσβαση σε μεταβλητές (δηλαδή να αλλάξει κατάσταση) στο χώρο που ξεκίνησε η αρχική κλήση. Η ΓΛΩΣΣΑ της ΑΕΠΠ δςεν θα μπορούσε να κάνει κάτι τέτοιο, γιατί δεν έχει τρόπο να έχει συναρτήσεις με θέαση στο περιβάλλον έξω από τη συνάρτηση. Σε αντίθεση οι C++ και C έχουν αυτή την δυνατότητα σε επίπεδο αρχείου, δηλαδή αν ένα πρόγραμμα είναι γραμμένο σε δυο ή περισσότερα αρχεία, ανά αρχείο υπάρχουν μεταβλητές θεατές στο αρχείο αυτό, και σε όλες τις συναρτήσεις σε αυτό. Στη Μ2000 στις πρώτες εκδόσεις μόνο γενικές μπορούσαν να θεαθούν μέσα σε συναρτήσεις και τμήματα. Αυτό συνεχίζει και τώρα αλλά έχουν μπει και άλλες μορφές κλήσεων που μεταθέτουν με τη κλήση και το όνομα χώρου για να υπάρχει η κοινή θέαση μεταβλητών. Χωρίς αυτό δεν θα δούλευαν και οι φόρμες χρήστη, αφού τα γεγονότα χρειάζονται εξυπηρέτηση από συναρτήσεις που πρέπει να έχουν επαφή με το περιβάλλον, εδώ ενός τμήματος, εκεί όπου θα "αλλάζουν" κατάσταση σε αυτό (αυτή είναι η έννοια εξυπηρέτησης γεγονότος, να επιφέρει αλλαγές στο έξω περιβάλλον, από το "γεγονός" που δημιουργείται στο αντικείμενο. Μπορούμε να έχουμε πέρασμα με αναφορά ώστε να έχουμε και ανάδραση, όπως για παράδειγμα το κλείσιμο μιας φόρμας χρήστη μπορεί να ακυρωθεί αν θέλουμε, οπότε το αντίστοιχο γεγονός δίνει "ανάδραση" κατάλληλη μέσω μεταβλητής που πέρασε με αναφορά.


Φτιάχνω το Κόσμο του Κάρελ του Ρομπότ

Το πρόγραμμα υπάρχει στο Git  και το αντιγράφετε ως έχει (ως gsb αρχείο, με Win Dir$ στη κονσόλα της Μ2000 ανοίγει ο Explorer στο φάκελο του χρήστη της Μ2000), ή κόβεται το κώδικα από το τμήμα Α και το βάζεται σε ένα δικό σας τμήμα στον διορθωτή της Μ2000 και το εκτελείτε άμεσα! 

Περιλαμβάνει και τον κόσμο που φαίνεται στην εικόνα. Ο κόσμος αυτός είναι στην αρχή του κώδικα, ως json αρχείο. Η εφαρμογή φτιάχνει json αρχείο και το αποθηκεύει με κατάληξη kword. Έχει ενσωματωθεί και η βοήθεια με υπερκείμενο.

Μετακινούμε το ρομποτ και σχεδιάζουμε το κόσμο, ασχολούμενοι με τα τοιχώματα και τα μπίμπερ. Για τα τοιχώματα, ο Κάρελ τα βάζει κάτω δεξιά (ή νοτιανατολικά). Το τι θα δούμε εξαρτάται από την "συνέχεια". Δηλαδή αν πάμε σε μια κενή φόρμα (επιλέγοντας διαστάσεις καθαρίζει ο κόσμος), θα πρέπει να βάλουμε Εμπόδιο δυο φορές συνεχόμενα για να δούμε γραμμή!

Μπορούμε να φτιάξουμε οποιοδήποτε σχέδιο, αρκεί να μετακινηθούμε αριστερά από εκεί που θέλουμε να αλλάξουμε κάτι. Ο Κάρελ για να φτιάξει τον κόσμο του μετακινείται ως "φάντασμα" δηλαδή διαπερνάει τους τοίχους. Αυτό γίνεται με τέσσερα πλήκτρα με τα λεκτικά Βορράς, Ανατολή, Νότος, Δύση. Αν θέλουμε να δούμε πως θα προχωρήσει με τις δικές του μοναδικές εντολές Εμπρός και Αριστερά υπάρχουν κουμπιά κάτω από το σχέδιο.

Το κουμπί έλεγχος κάνει παιχνίδι τον Κάρελ, αν και δεν "τερματίζει" αν δεν το τερματίσουμε με Esc ή διπλό πάτημα στο Έλεγχος.

Το επόμενο βήμα είναι να φτιαχτεί το πρόγραμμα που θα φορτώνει το κόσμο που θέλουμε (την άσκηση) και θα εκτελεί το πρόγραμμα του ασκούμενου, στη γλώσσα Κάρελ. Στο git έχω ανεβάσει τον AST-Διερμηνευτή, και πάνω σε αυτό θα βασιστώ για το τελικό πρόγραμμα.

Για να σώσουμε ένα κόσμο ανοίγει η φόρμα διαλόγου, για το όνομα αρχείου. Εδώ η Μ2000 έχει μια παραξενιά που μάλλον θα την βγάλω σε επόμενη έκδοση*. Δεν επιτρέπει να γράψουμε νέο όνομα αν ο φάκελος είναι read only δηλαδή μόνο για ανάγνωση. Χρειάστηκε στο φάκελο του χρήστη να πάω ένα επίπεδο παραπάνω, να μπω με cmd.exe (με δικαιώματα administrator) για να δώσω το attrib -r m2000 και να κάνω τον φάκελο για ανάγνωση και για εγγραφή. Εν τω μεταξύ για να σώσουμε πρόγραμμα ή για να γράψουμε αρχεία δεν είχε ζήτημα η Μ2000. Μόνο στο να "ανοίξει" ο διάλογος το πεδίο που δέχεται νέο όνομα, στη περίπτωση του read only φακέλου! Ο οποίος φάκελος δεν έγινε από μένα read only, και αν δεν το έβρισκα από το "σφάλμα" (που βασικά δεν είναι σφάλμα) του διαλόγου δεν θα το είχα καταλάβει! Το έψαξα λίγο και μάλλον κάτι έκανε ο Defenter των Windows, και για προστασία δήθεν "κλείδωσε" τους φακέλους. Στη πράξη το read only δεν κλειδώνει τίποτα στα Windows (έχει άλλες κλειδαριές...που δεν φαίνονται). Είναι απλός ένα "σινιάλο".  Οι περισσότεροι προγραμματιστές κάνουν κάτι απλό, δοκιμάζουν να δουν αν μπορούν να γράψουν ένα μικροσοπικό αρχείο! Αν γράφεται τότε ο φάκελος δεν είναι πραγματικά read-only.

*Ανέβηκε η αναθεώρηση 48 που αφαιρεί τον έλεγχο folder read only στη φόρμα διαλόγου που ανοίγει με την εντολή: Αποθήκευση.ως

Λίγα λόγια για το πρόγραμμα

https://github.com/M2000Interpreter/KarelTheRobot/blob/main/KarelTheRobot.gsb

Το πρόγραμμα είναι ένα αρχείο  gsb με ένα τμήμα το Α. Μέσα σε αυτό έχουμε 1500+ γραμμές. Αυτές αν και φαίνονται πολλές, δεν είναι! 

Το πρώτο μέρος έχει τη δημιουργία της Λιστ1$ μιας μεταβλητής αλφαριθμητικής στην οποία εκχωρούμε ένα json αντικείμενο που το έχουμε ως αλφαριθμητική τιμή σταθερή. Δηλαδή το αντικείμενο είναι στη λεγόμενη serialized μορφή.

Από τη γραμμή 44 φτιάχνουμε τη διεπαφή, δηλαδή στήνουμε τη φόρμα μας. Εδώ δεν χρησιμοποιούμε φόρμα χρήστη αλλά αλλάζουμε την κονσόλα. Δηλαδή όλο το πρόγραμμα θα τρέχει μόνο στη κονσόλα. Στην 51 γραμμή το Συγγραφή ! 3 κάνει το tab να πιάνει τρεις χαρακτήρες πλάτος. Αυτό με βόλευε κατά την δημιουργία του προγράμματος.

Στη 53 ξεκινάει η δημιουργία του συστήματος βοήθειας με υπερκείμενο. Υπάρχει τρόπος δηλαδή να ετοιμάσουμε κεφάλαια και αυτά να καλούν το ένα το άλλο με υπερσυνδέσμους σε τετράγωνες αγκύλες [ ] . Δείτε ότι ένας υπερσύνδεσμος αντί να ανοίξει νέο κεφάλαιο ανοίγει μια σελίδα στον τρέχοντα φυλλομετρητή ιστοσελίδων πχ στο Firefox ή στο Chrome.

Στην 114 γραμμή η Διαμέσου ΦόρτωσεΣυνάρτηση καλεί μια ρουτίνα απλή που γυρνάει με την εντολή Επιστροφή. Αυτές οι ρουτίνες δεν έχουν τοπικές, δηλαδή δεν ανοίγουν πρόσκαιρο χώρο για ορισμούς όπως κάνει μια ρουτίνα με όνομα με παρενθέσεις. Έτσι ότι φτιάχνει μένει. Εκεί λοιπόν έχω βάλει ορισμούς και άλλα σχετικά για το πρόγραμμα. Στην ουσία μετάθεσα το κομμάτι αυτό προς το τέλος.

Η Διαφυγή Όχι απενεργοποιεί το Esc, για να μην διακόπτεται το πρόγραμμα. Αλλά μπορούμε να το διακόψουμε με το CTRL+C. Θέλουμε το Esc για άλλες δουλειές!

Στην 144 υπάρχει μια μυστήρια εντολή: Θέση ! η οποία ακολουθεί μια Δρομέας 0,2 στην 143. Με την εντολή Δρομέας μετακινούμε νοητά την θέση που τυπώνουμε χαρακτήρες στη φόρμα μας (η Πλάτος μας δίνει το μέγιστο στη γραμμή χαρακτήρες, η Ύψος μας δίνει τον αριθμό γραμμών). Η Εντολή Θέση είναι η αντίστοιχη για τον δρομέα γραφικών, και κανονικά δέχεται ένα ή δυο αριθμητικά νούμερα. Πχ Θέση 6000, 3000 θα μετακινήσει το δρομέα γραφικών (νοητά, δεν το βλέπουμε) εκεί που η 6000twips οριζόντια συντεταγμένη συναντάει την 3000twips κάθετη συντεταγμένη (το 0,0 είναι πάνω αριστερά, και οι κάθετες συντεταγμένες είναι θετικές προς τα κάτω). Με τη Θέση ! μεταφέρουμε τη θέση του δρομέα χαρακτήρων (πάνω αριστερή γωνία θέσης χαρακτήρα) ως θέση δρομέα γραφικών. Ομοίως η Δρομέας ! κάνει το ανάποδο αλλά εκεί βρίσκει τη θέση χαρακτήρα και τη γραμμή που περιέχει την θέση του δρομέα γραφικών (έτσι μια Δρομέας ! και μετά Θέση ! ενδέχεται να αλλάξει τον δρομέα γραφικών). Αυτά τα κάνουμε για να πάρουμε πραγματικά νούμερα, επειδή κάναμε επιλογές για την εμφάνιση της κονσόλας:

Εντολή Παράθυρο 12, 0 στην 118 γραμμή λέει να μπουν 12pt χαρακτήρες στη τρέχουσα γραμματοσειρά, και να καλυφθεί όλη η οθόνη του μόνιτορ 0 (αν το 0 το κάνουμε 1 και υπάρχει δεύτερο μόνιτορ θα μεταφερθεί εκεί η κονσόλα). Παρακάτω όμως η εντολή Φόρμα με δυο νούμερα ζητάει στο χώρο της κοσνόλας να έχουμε ένα πλάτος χαρακτήρων με έναν αριθμό γραμμών (ύψος σε χαρακτήρες). Αυτό αλλάζει το μέγεθος της γραμματοσειράς και ενδεχομένως το διάκενο μεταξύ των γραμμών (το αυξάνει αν χρειάζεται για να καλύψουν οι γραμμές το χώρο της κονσόλας). Έτσι το που θα είναι η τρίτη γραμμή δεν το ξέρουμε πριν εκτελεστεί το πρόγραμμα! Να γιατί μας ενδιαφέρει να στοιχίσουμε οτιδήποτε στη φόρμα μας βάσει ενός προσχεδιασμένου πλάτους και ύψους φόρμας. Βέβαια αυτό το πρόγραμμα έχει γραφτεί έτσι ώστε αν θέλουμε να αυξήσουμε ή να μειώσουμε το πλάτος σε χαρακτήρες (ενώ κρατάμε σταθερό το ύψος). Η αλλαγή θα επιφέρει αλλαγή στο διάστιχο και στο μέγεθος χαρακτήρων με συνέπεια να έχουμε μικρότερα γράμματα στα πλήκτρα (στόχοι στη κονσόλα της Μ2000 κατά την ορολογία της Μ2000).

Οι στόχοι στη Μ2000 είναι πλαίσια που έχουν ιδιότητες και μπορούν με μια εντολή να αλλάξουμε κάποιες από αυτές και να δούμε τις αλλαγές στην οθόνη. Δεν είναι πραγματικά αντικείμενα όπως τα στοιχεία ελέγχου των φορμών χρήστη. Για να πάρουμε "ανάδραση" δηλαδή ότι επιλέξαμε κάποιο στόχο πρέπει να χρησιμοποιηθεί η Σάρωσε. Αυτή η εντολή παίρνει ένα αριθμό σε χιλιοστά του δευτερολέπτου (παίρνει και δεκαδικά) και στο χρόνο αυτό ή γυρνάει άπραγη ή έχει βρει σε ποιον στόχο κάναμε αριστερό κλικ και έχει κάνει ένα από τα δυο πράγματα ανάλογα με το τι ζητάμε από έναν στόχο: Ή να εκτελέσει κώδικα σαν να εκτελέστηκε στην κοσνόλα (δηλαδή με θέαση μόνο σε ότι είναι γενικό) ή να στείλει χαρακτήρες στο πληκτρολόγιο, και ειδικότερα στην μνήμη εντός της Μ2000 (όχι απευθείας στο πληκτρολόγιο, αυτό το τελευταίο το κάνουμε για το Esc πιο μετά για άλλο λόγο). Σημασία έχει ότι εδώ δεν χρησιμοποιούμε τους στόχους για να στείλουμε κάτι στο πληκτρολόγιο αλλά για να αλλάξουμε μια τιμή στην γενική αριθμητική μεταβλητή Κωδ. Αυτή η μεταβλητή ορίζεται στο τμήμα Α, θα σκιάσει τυχόν γενικές Κωδ που ήδη υπάρχουν και θα διαγραφεί στο πέρας εκτέλεσης της Α. Αν κάνουμε λάθος και γράψουμε μέσα στο τμήμα μια εντολή εκχώρησης Κώδ=0 τότε θα φτιαχτεί τοπική και ο διερμηνευτής θα δώσει προτεραιότητα σε αυτήν με συνέπεια οι αλλαγές της γενικής Κωδ στους στόχους να μην φαίνεται στο πρόγραμμα (εμείς θα διαβάζουμε τη τοπική). Για το λόγο αυτό όταν κάνουμε εκχώρηση σε γενική χρησιμοποιούμε ή το <= πχ Κωδ<=0 ή τη Στη, πχ Στη Κωδ=0 η οποία δεν δημιουργεί νέες μεταβλητές, αν βρει ότι υπάρχουν (η Στη είναι η Let στο αγγλικό λεξιλόγιο, η απλή = κοιτάει αν υπάρχει τοπική και αν όχι την φτιάχνει, δεν κοιτάει καθόλου αν υπάρχουν γενικές, όπως η Στη).


Οι στόχοι δεν μας δίνουν τα στοιχεία τους, μόνο αλλαγές μπορούμε να κάνουμε δίνοντας νέες τιμές. Επίσης μπορούμε να ενεργοποιήσουμε ή όχι κάποιον στόχο δίνοντας το νούμερό του και τιμή 1 ή 0.

Για να απλοποιήσω το πρόγραμμα έφτιαξα την Μνήμη ως μια Λίστα με κλειδιά/τιμές, όπου κλειδί είναι ένα όνομα πχ το ΕΜΠ είναι για το πλήκτρο Εμπόδιο, και τιμή ένας αυτόματος πίνακας (touple) με έξι στοιχεία (παίρνει και αριθμούς και αλφαριθμητικά, στον ίδιο πίνακα). Ο πίνακας καταχωρείται με δείκτη. Έτσι όταν αργότερα ζητήσουμε την τιμή στο κλειδί "ΕΜΠ" θα πάρουμε το δείκτη, σαν δεύτερο δείκτη και όχι αντιγραφή στοιχείων σε νέο πίνακα.

Στη γραμμή 201 είναι η εντολή Στόχος(2, !Μνήμη("ΕΜΠ")) η οποία είναι κλήση της ρουτίνας Στόχος(). Αυτή η ρουτίνα δέχεται αρκετές παραμέτρους, με πρώτη τον αριθμό που θα δίνει στην μεταβλητή Κωδ όταν ο στόχος ενεργοποιηθεί!. Αντί να δώσουμε έναν έναν τις επόμενες παραμέτρους λέμε στο διερμηνευτή ότι ακολουθεί πίνακας και να τις πάρει από εκεί και να τις βάλει στο σωρό τιμών για να διαβαστούν από την ρουτίνα. Έτσι τώρα αυτό που δίνουμε το έχουμε κρατημένο και στη Μνήμη. Η μεταβλητή Μνήμη έχει το δείκτη στη λίστα, αλλά τα Μνήμη() και Μνήμη$() διαβάζουν αριθμητικές (ή αντικείμενα) τιμές και αλφαριθμητές αντίστοιχα βάσει κλειδιού, αλφαριθμητικό ή αριθμός, ή αν έχουμε το ! στο τέλος ενός αριθμού βάσει τρέχουσας σειράς. Οι λίστες ενδέχεται να χάσουν την σειρά των κλειδιών αν διαγράψουμε κλειδί, γιατί η διαγραφή λειτουργεί ως εξής: Αναζήτηση σε πίνακα κατακερματισμού και αφαίρεση του κλειδιού, με αντιγραφή του τελευταίου στοιχείου στη θέση εκείνου που διαγράφτηκε. Η αντιγραφή είναι πάντα "σύντομη" γιατί γίνεται με αντιγραφή σταθερού μήκους μνήμης (όσο το μήκος μιας εγγραφής). Τα αλφαριθμητικά και τα αντικείμενα που "απασχολούν" μεγάλη μνήμη συνήθως, στην εγγραφή απασχολούν μόνο το μήκος ενός δείκτη. Αυτού του είδους λίστα χρησιμοποιεί ο διερμηνευτής για όλα τα Αναγνωριστικά, και τα βρίσκει σε O(1) σε σταθερό χρόνο, ανεξάρτητα από τον αριθμό Αναγνωριστικών!

Κάποιοι στόχοι στο πρόγραμμα έχουν φτιαχτεί μόνο για να εμφανίζουν ταμπέλες! Δηλαδή δεν είναι ενεργοί στόχοι. Πχ στη 294 διαβάζουμε:Κεφαλίδα(Μεγάλο, αρπ, ΓΡΑΜΜΗ+3, "Σκοπός του Κάρελ") όπου τα ορίσματα που δίνουμε λένε πόσο πλάτος θα έχει ο στόχος, που θα γραφτεί (το αρπ είναι η μεταβλητή αριστερό περιθώριο που υπολογίσαμε στην αρχή), και θα γραφτεί στη τρίτη γραμμή μετά την τρέχουσα που μας δίνει η μεταβλητή μόνο για ανάγνωση Γραμμή. Στο τέλος δίνουμε και ένα αλφαριθμητικό για το τι θέλουμε να γράφει ο στόχος!

Στην 327 γραμμή υπάρχει μια λάμδα συνάρτηση (θα μπορούσε να ήταν και κανονική) . Στην 358 γραμμή έχουμε αυτό Οθόνη : Αναφορά Μνήμη(ΘέσηΣτηΛίστα(Ποιός, Κωδ)!)#Τιμή$(5) δηλαδή δυο εντολές, η Οθόνη σβήνει το κάτω μέρος της φόρμας (το μέρος που μπορεί να ολισθαίνει) και το είχαμε ορίσει σε τρεις γραμμες ύψος, και η Αναφορά δίνει το πέμπτο στοιχείο, αλφαριθμητικό, από τον πίνακα  στην Μνήμη, αλλά δεν δίνουμε κλειδί αλλά θέση, τη θέση που μας επιστρέφει η ΘέσηΣτηΛίστα. Αυτή παίρνει την λίστα Ποιος και τον αριθμό Κωδ και δίνει τον αριθμό θέσης. Αυτό έγινε γιατί η Ποιος είναι μια Λίστα που δημιουργήσαμε στη γραμμή 188 με την Ποιός=Λίστα, και στη ρουτίνα Στόχος() (οι ρουτίνες βλέπουν τις μεταβλητές του τμήματος που εκτελούνται), υπάρχει η εντολή Προσθήκη Ποιός, οδηγ:=Μ όπου το οδηγ είναι ο αριθμός κωδ, και το Μ ο αριθμός στόχου. Έτσι το Ποιός(6) θα μας δώσει τον πραγματικό αριθμό στόχου σε εκείνον το στόχο που γυρνάει το 6 στην κωδ όταν ενεργοποιηθεί. Δείτε όμως ότι η λίστα Ποιος και η λίστα Μνήμη σε οποιαδήποτε Χ θέση έχουν στοιχεία για τον ίδιο στόχο, έτσι με την ΘέσηΣτηΛίστα() πάμε μέσω κωδ να βρούμε ποιος είναι ο στόχος ώστε από την Μνήμη() να δώσουμε τη θέση (να γιατί είναι το ! στο τέλος)  και να πάρουμε το πίνακα από όπου θα διαβάσουμε την 6η στην ουσία τιμή γιατί οι αυτόματοι πίνακες (touple) ξεκινούν από 0.

Κατά τη συγγραφή του προγράμματος η χρήση της αναζήτησης είναι πολύ χρήσιμη. Πχ. αν επιλέξουμε μια λέξη, με τα F2 πάμε στην ίδια παραπάνω και με το F3 πάμε στην ίδια παρακάτω. Με συνδυασμό Ctrl ή Shift, ανοίγει φόρμα και ζητάει όνομα, είτε για να το βρει μέσα σε λέξη είτε για να το βρει ως ολόκληρη λέξη. Επίσης το F5 κάνει αλλαγές στις λέξεις άμεσα (με undo Ctrl+Z και redo Ctrl+Y, δείτε και το σχετικό μενού με δεξί κλικ στο ποντίκι πάνω στον δρομέα, η Ctrl+F10 ή αριστερό κλικ στην επικεφαλίδα του διορθωτή). Αν θέλουμε αλλαγή μόνο σε πεζά κεφαλαία τότε αυτό το κάνει η F4, αλλά εδώ δεν υπάρχει undo. Το F4 κάνει επιλογή λέξης αν δεν έχει γίνει και αν έχει γίνει κάνει ομοιόμορφες όλες τις λέξεις. Αν θέλουμε κάποια λέξη να έχει τόνο τότε αλλαγές θα κάνουμε με το F5. To F5 έχει και αυτό παραλλαγή με το Shift, όπου οι αλλαγές γίνονται και σε μέρος λέξης. Το undo γίνεται όσο είμαστε μέσα στον διορθωτή. Αν θέλουμε να έχουμε πάντα το πρόγραμμα μέσα στον διορθωτή τότε ανοίγουμε τον meditor από το info αρχείο, που είναι ο παραθυρικός διορθωτής της Μ2000, και οι εκτελέσεις γίνονται σε νέο περιβάλλον (μέσα από το μενού επιλογών του παραθυρικού διορθωτή επιλέγουμε τι θα εκτελεστεί από το πρόγραμμα και πώς).

Στην γραμμή 352 ξεκινάει ένα μπλοκ Κάθε 1000/30  { } όπου το δευτερόλεπτο (1000ms) το χωρίζουμε σε 30 μέρη, άρα 30 φορές το δευτερόλεπτο ή 30Hz συχνότητα, εκτελείται η επανάληψη του προγράμματος για να διαβάζει τους στόχους και να εκτελεί ανάλογα.

Τα 30 μέρη μπορούν να λιγοστέψουν αν κάτι απαιτεί μεγαλύτερο χρόνο, και πράγματι σε μια επιλογή με την Έλεγχος μπαίνουμε  στο παιχνίδι() όπου εκεί υπάρχει άλλη Κάθε...και η προηγούμενη είναι σε αναμονή!

Αυτό είναι το πρόγραμμα ως σκελετός. Από και κει και πέρα φτιάχνουμε το τι θα κάνει ο κάθε στόχος.

Το  πρόγραμμα έχει δυο αντικείμενα το Κόσμος και το Ρομπότ. Και τα δύο τα έχουμε φτιάξει με γεγονότα. Ο λόγος που έγινε αυτό είναι για να βγάλουμε εκτός πράγματα που δεν ενδιαφέρουν τα αντικείμενα αυτά, όπως το πώς σχεδιάζεται ο Κόσμος και το πώς σχεδιάζεται το Ρομπότ. Αυτά που ενδιαφέρουν είναι τα στοιχεία πχ το Εμπόδιο είναι ένα καθορισμένο στοιχείο και παίζει ένα καθορισμένο ρόλο, ανεξάρτητα το πώς θα φτιαχτεί στην οθόνη. Θα μπορούσαμε να είχαμε μια 3D απεικόνιση χωρίς να αλλάξουμε τα αντιοκείμενα. Η μέθοδος εμφάνισε του αντκειμένου κόσμος στέλνει αιτήματα με την Κάλεσε Γεγονός. Αν δεν έχουμε συνδέσει συναρτήσεις εξυπηρέτησης τότε δεν θα έχουμε λάθος στον κώδικα της μεθόδου. Η μέθοδος δεν ενδιαφέρεται αν υπάρχει ή όχι εξυπηρέτηση! Αυτή είναι η λογική με το προγραμματισμό με γεγονότα, που αυτό το πρόγραμμα εφαρμόζει!

Στις συναρτήσεις εξυπηρέτησης γεγονότων, η θέαση είναι σχεδόν ίδια με αυτή των ρουτινών, αλλά δεν έχουμε κλήση σε ρουτίνες έξω από τη συνάρτηση. Όλες οι μεταβλητές του τμήματος είναι θεατές. Ο σωρός τιμών είναι ξεχωριστός από αυτό του τμήματος (ενώ οι ρουτίνες βλέπουν τον ίδιο). Αν έχουμε ονόματα που ήδη υπάρχουν στο τμήμα θα πρέπει είτε να δημιουργήσουμε με Διάβασε Νέο ή με Τοπική ή Τοπικές αν δίνουμε νέες τιμές απευθείας. Πχ στη 1080 η Συνάρτηση Ρομπότ_σχεδίασεΦόντο (Νέο Χ, Υ)  έχει το Νέο για να φτιαχτούν νέες Χ και Υ, αν βγάλετε το Νέο θα δείτε πρόβλημα στο πρόγραμμα! Αυτό που είναι στην παρένθεση θα πάει σε μια Διάβασε Νέο Χ, Υ.

Δείτε ότι οι συναρτήσεις εξυπηρέτησης για Ομάδες (τα αντικείμενα χρήστη που φτιάχνουμε στη Μ2000) έχουν τη κάτω παύλα (underscore) μεταξύ ονόματος αντικειμένου και ονόματος γεγονότος. 

Εκτός από τα αντικείμενα χρήστη (ομάδες) όπου ορίζουμε τα πάντα για αυτά, υπάρχουν έτοιμα όπως λίστες, πίνακες, σωρούς τιμών και άλλα τύπου COM όπως το ΛίσταJson (τύπος JsonObject), ΠίνακαςJson (τύπος JsonArray), ΣτοιχείαXML (τύπος XmlMono) και άλλα. Τα τύπου COM είναι για τοπική χρήση, ενώ οι πίνακες, λίστες και σωροί τιμών είναι "καταχωρητές" που καταχωρούνται οπουδήποτε (πχ μια λίστα μπορεί να έχει άλλες λίστες, άλλους πίνακες και άλλους σωρούς τιμών) και να δοθεί ως επιστροφή τιμής.


Δείτε στην 851 το Ιδιότητα ΠακέτοJson$  όπου φτιάχνουμε μια ιδιότητα του αντικειμένου Κόσμος, στην οποία δίνουμε το τι θα επιστρέφει και το τι θα παίρνει ως πρόγραμμα! Η Θέσε λέει τι θα παίρνει και η Αξία λέει τι θα δίνει.  Στη Αξία φτιάχνουμε σε Json μορφή τα στοχεία του αντικειμένου. Στην Θέσε διαβάζουμε αλφαριθμητικό, το μεταφράζουμε (parse) σε Json και από αυτό διαβάζουμε και ρυθμίζουμε το αντικείμενο (φορτώνουμε νέα κατάσταση - State). H ΠακέτοJson$ λειτουργεί σαν μεταβλητή. Τα Θέσε και Αξία είναι τα Setter Getter αντίστοιχα της Java. Υπάρχει μια [ΠακέτοJson]$ ιδιωτική που φτιάχνει ο διερμηνευτής αλλά δεν την χρησιμοποιούμε, αντί αυτού χρησιμοποιούμε το ΑΞΙΑ$ που μας φτιάχνει ο διερμηνευτής όταν καλείται η Θέσε (στην εκχώρηση τιμής) και η Αξία (στην ανάγνωση τιμής). Ο τύπος της ΠακέτοJson$ είναι αντικείμενο ομάδα (Group) και μπορούμε να ορίσουμε ότι θέλουμε αν παρακάτω δώσουμε στον ορισμό Ομάδα ΠακέτοJson { }. Επειδή όλες οι ομάδες που έχουν το όνομα  με $ (επειδή επιστρέφουν τιμή αλφαριθμητικό) έχουν και χωρίς το $ για να καλούμε μέλη. Πχ αν ένα μέλος ήταν το Α$ τότε η ΠακέτοJson.A$ θα δούλευε αλλά η ΠακέτοJson$.A$ δεν θα δούλευε (είναι κάτι άλλο για τον διερμηνευτή, το $. υποδηλώνει ότι υπάρχει δείκτης αλφαριθμητικός, πχ αν το A$="OK"  τότε το Α$.Χ++ θα αυξήσει την τιμή στο ΟΚ.Χ, είναι δηλαδή το ΟΚ.Χ++, είναι ένας τρόπος έμμεσης διευθυνσιοδότησης). Δοκιμάστε αυτό σε μια γραμμή: ΟΚ.Χ=10 : Α$="ΟΚ": Α$.Χ++:Τύπωσε Εκφρ(Α$.Χ) 

Καλά Χριστούγεννα!

ΓΚ











Δεν υπάρχουν σχόλια:

Δημοσίευση σχολίου