Πέμπτη 19 Νοεμβρίου 2015

Ταξινόμηση εγγράφου και αριθμός παραγράφου (Μ200)

Αυτό το θέμα είναι κάπως δύσκολο! Και αυτό γιατί αναφέρεται σε μια διπλή συνδεδεμένη λίστα, που συνδέει παραγράφους και λέγεται έγγραφο στη Μ2000.
Κάθε παράγραφος λαμβάνει έναν αριθμό παραγράφου ως μοναδικό αριθμό. Στην αρχή οι αριθμοί συμπίπτουν με τον αριθμό σειράς εμφάνισης. Αν έχουμε τρεις παραγράφους στο έγγραφο, τότε πάντα η πρώτη παράγραφος θα θεωρείται η πρώτη στη σειρά εμφάνισης. Όμως αν μιλάμε για αριθμό παραγράφου τότε αυτός δεν έχει να κάνει με τη σειρά αλλά με την θέση της παραγράφου κάπου στη μνήμη. Δεν μπορούμε να αλλάξουμε τον αριθμό παραγράφου, ενώ την σειρά έμφάνισης μπορούμε να την αλλάξουμε αν για παράδειγμα διαγράψουμε ιις προηγούμενες παραγράφους, η αν βάλουμε πίσω από αυτην που μας ενδιαφέρει άλλες παραγράφους.

Το  έγγραφο χρησιμοποιεί και ο διορθωτής τμημάτων και συναρτήσεων της Μ2000. Με τα πλήκτρα F6, F7, F8 βάζουμε "σελιδοδείκτη", στην ουσία καταχωρούμε χωρίς να βλέπουμε τον αριθμό παραγράφου. Οπότε αν σβήσουμε κάποια παράγραφο πριν ή αν βάλουμε μερικές, ο σελίδοδείκτης δεν θα χάσει το στόχο του, αφού θα δείχνει πάντα στη παράγραφο που έχουμε δείξει.

Στο πρόγραμμα παρακάτω έχουμε αρκετά κομάτια που  κάτι θέλουν να δείξουν. Το εκτελούμε και πατάμε ένα πλήκτρο κάθε φορά για να δούμε το επόμενο.

Αρχικά θα φτιάξουμε ένα έγγραφο, θα βγάλουμε ένα αντίγραφο, θα κάνουμε μερικές ταξινομήσεις.
Μετά θα διατρέξουμε το έγγραφο με χρήση δείκτη (αριθμό παραγράφου), και με χρήση αύξοντα αριθμού. Η ίδια συνάρτηση που δίνει μια παράγραφο, μπορεί να δώσει μια για αύξοντα αριθμό ή με έναν τρόπο που δείχνουμε με τον δείκτη. Και ενώ η χρήση του αύξοντα αριθμού φαίνεται και είναι απλή, η χρήση του δείκτη απαιτεί μια γνώση επί του θέματος. Η συγκεκριμένη συνάρτηση Παράγραφος$() όταν ψάχνει για κάποιον αριθμό σειράς εμφάνισης διατρέχει κάποιο άκρο για να το βρεί, ενώ όταν δώσουμε το δείκτη ξέρει επ ακριβώς που είναι και μπορεί να αλλάξει το δείκτη στο επόμενο βάσει της φοράς που θα ορίσουμε με μια από τις Μπροστά() και Πίσω().

Τεχνικά τώρα το πρόγραμμα χρησιμοποιεί χρωματισμό στην εμφάνιση στην οθόνη, τόσο στα γράμματα όσο και στο φόντο. Αντί να βάλω μια ρουτίνα να "κρύψω" την όλη αυτή επεξεργασία προτίμησα να φαίνεται. Υπάρχουν μάλιστα και επεξηγήσεις. Όταν αντιγραφεί στο διορθωτή της Μ2000 θα χρωματιστεί αυτόματα! (με την αναθεώρηση 94 έχουμε εξαγωγή σε Html με αντιγραφή)

Φορμα 60,32
Οθόνη 5, 0
\* Ταξινόμηση εντός περιβάλλοντος  *\
\\ Δηλαδή τα στοιχεία προς ταξινόμηση βρίσκονται σε μεταβλητή εντός περιβάλλοντος
\\ εδώ η μεταβλητή είναι τύπου Έγγραφο. Αυτός ο τύπος είναι πιο γενικός από το αλφαριθμητικό
\\ Εσωτερικά κρατάει σε ξεχωριστό αλφαριθμητικό κάθε παράγραφο. Δεν είναι πίνακας αλλά μια
\\ συνδεδεμένη λίστα, όπου κάθε παράγραφος είναι μια παρουσία. Έτσι η τυχόν μετακίνησή της δεν
\\ αλλάζει τον εσωτερικό αριθμό παρουσίας!
\\ Μπορούμε να αναβαθμίσουμε ένα αλφαριθμητικό σε έγγραφο, ή ένα οποιοδήποτε στοιχείο πίνακα
\\ αλφαριθμητικών σε έγγραφο αλλά όχι ένα  πίνακα σε πίνακα με έγγραφα.
\\ Όλες οι συναρτήσεις για τα αλφαριθμητικά ισχύουν και για τα έγγραφα
\\ Όμως τα έγγραφα έχουν επιπλέον μεθόδους και ιδιότητες! Είναι κατά μια έννοια αντικείμενα!
\\ Στη Μ2000 μπορούμε να δίνουμε αλφαριθμητικά με παραγράφους.
\\ Η θέση του άγγιστρου στο τέλος καθορίζει τα διαστήματα που θα αφαιρεθούν από αριστερά!
\\ Έτσι μπορούμε να έχουμε σε παραγράφους μετακίνηση δεξιά (επιλέγουμε όσες γραμμές θέλουμε και πατάμε TAB)
\\ Με Shift Και TAB, στον ενσωματωμένο διορθωτή, πάμε το κείμενο αριστερά (βγάζουμε διαστήματα).
Έγγραφο α$={One
            Two
            Three
            Four
            Five
            31
            20
            12
            }
Έγγραφο β$=α$
\\ Η εντολή Ταξινόμηση κάνει ταξινόμηση σε έγγραφα και μόνο
\\ Η εντολή Αναφορά δουλεύει για αλφαριθμητικές εκφράσεις, άρα και για έγγραφα
\\ Η Αναφορά εμφανίζει κείμενο με παραγράφους με διάφορους τρόπους στοίχισης και σε διαφορετικά πλάτη
\\ Μπορεί μάλιστα να εμφανίζει το φορμαρισμένο κείμενο από κάποια γραμμή έως κάποια γραμμή
\\ και έτσι να φτιάχνουμε στήλες κειμένου! Αλλά εδώ απλά θα μας δώσει το αποτέλεσμα!
\\ Η Αναφορά στην οθόνη δείχνει τα 3/4 των γραμμών και περιμένει διάστημα ή κλικ με το ποντίκι για να δείξει τα επόμενα
Ν=Εγγράφου.Παρ(α$) \\ θέλουμε τον αριθμό παραγράφων
Τύπωσε Πάνω ~(12,2), {Ταξινόμηση α$,1,5}
Τυπωσε
Ταξινόμηση α$,1,5 ' από το 1 έως το 5
Πένα 14 : Αναφορά α$
γ$=κομ$ \\ περιμένουμε ένα πλήκτρο
Τύπωσε Πάνω ~(12,2),{Ταξινόμηση α$,6,8}
Τύπωσε
Ταξινόμηση α$,6,8 ' από το 6 έως το 8
Πένα 14 : Αναφορά α$
γ$=κομ$ \\ περιμένουμε ένα πλήκτρο
Τύπωσε Πάνω ~(12,2),{Ταξινόμηση α$,6,8,2}
Τύπωσε
Ταξινόμηση α$,6,8,2 ' από το 6 έως το 8 αλλά από το δεύτερο χαρακτήρα
Πένα 14 : Αναφορά α$
γ$=κομ$ \\ περιμένουμε ένα πλήκτρο
Οθόνη \\ καθαρίζουμε τη οθόνη μας!
Μακρύς μΑ=0 ' χρησιμοποιούμε ένα Μακρύ
αν Μπροστά(α$, μΑ) τότε { '  η Μπροστά() γυρίζει αληθές αν δεν είναι άδειο το αλφαριθμητικό
      Ενώ μΑ>0 {
            Τύπωσε μέρος "Άυξων αριθμός παραγράφου και πραγματικός αριθμός παραγράφου ", Αριθμός.Παράγραφου(α$,μΑ), μΑ
            Τύπωσε υπο
            \\ όταν χρησιμοποιούμε την μορφή (μΑ) εδώ είναι μια ειδική περίπτωση για τη Παράγραφο$()
            \\ Δηλώνει ότι είναι η μεταβλητή "περάσματος", το (μΑ) αντιστοιχεί στο Αριθμός.Παράγραφου(α$,μΑ)
            \\ και επιπλέον στο πέρας της εκτέλεσης η μΑ θα έχει τον επόμενο πραγματικό αριθμό, ή το 0
            \\ όπου το 0 δηλώνει το τέλος της δυναμικής λίστας (συνδεμένη λίστα, Linked List, με δυο δείκτες, για μπρος και πίσω
            Αναφορά Παράγραφος$(α$, (μΑ)) '
            γ$=κομ$ \\ περιμένουμε ένα πλήκτρο            
      }
}
Οθόνη
Τύπωσε Πάνω ~(12,2),"Τώρα θα δούμε τη λίστα, να την διατρέχουμε με την Για Εως {} "
Τύπωσε Υπό
Πενα 14
Για ι=1 εως Ν {
      Αναφορά Παράγραφος$(α$, ι) ' εδώ ο αριθμός ι είναι ο αύξων
}
γ$=κομ$ \\ περιμένουμε ένα πλήκτρο
\\ Τώρα θα πάμε προς τα πίσω
Τύπωσε Πάνω ~(12,2),"Τώρα θα πάμε προς τα πίσω"
Τύπωσε Υπό
Πενα 14
Μακρύς μΑ=0 ' χρησιμοποιούμε ένα Μακρύ
αν Πίσω(α$, μΑ) τότε { '  η Πίσω() γυρίζει αληθές αν δεν είναι άδειο το αλφαριθμητικό
      Ενώ μΑ>0 {
        \\    Τύπωσε "Άυξων αριθμός παραγράφου και πραγματικός αριθμός παραγράφου ", Αριθμός.Παράγραφου(α$,μΑ), μΑ
            \\ όταν χρησιμοποιούμε την μορφή (μΑ) εδώ είναι μια ειδική περίπτωση για τη Παράγραφο$()
            \\ Δηλώνει ότι είναι η μεταβλητή "περάσματος", το (μΑ) αντιστοιχεί στο Αριθμός.Παράγραφου(α$,μΑ)
            \\ και επιπλέον στο πέρας της εκτέλεσης η μΑ θα έχει τον επόμενο πραγματικό αριθμό, ή το 0
            \\ όπου το 0 δηλώνει το τέλος της δυναμικής λίστας (συνδεμένη λίστα, Linked List, με δυο δείκτες, για μπρος και πίσω
            Αναφορά Παράγραφος$(α$, (μΑ)) '
      }
}
\\ Ενώ ο αύξων αριθμός είναι ένας υπαρκτός αριθμός για μια παράγραφο αλλά αλλάζει με την εισαγωγή η διαγραφή άλλων παραγράφων, ο πραγματικός αριθμός ακολουθεί μια παράγραφο όσο "υπάρχει", ανεξάρτητα από τη θέση που είναι.
\\ Η τελευταία παράγραφος (με το 9) είναι το κενό αλφαριθμητικό. Βλέπουμε στην ουσία 8 λέξεις και 8 αλλαγές παραγράφου
\\ άρα υπάρχουν 9 παράγραφοι με την τελευταία να είναι κενή!
γ$=κομ$ \\ περιμένουμε ένα πλήκτρο
Οθόνη
Τύπωσε Πάνω ~(12,2),"Έλεγχος"
Τύπωσε Υπό
Πενα 14
Για ι=1 εως Ν {
  Τύπωσε ι, Παράγραφος(α$, ι)
}
      Για ι=1 εως Ν {
      Πένα 11 {
      Αν ι=5 τοτε {
      Τύπωσε μερος ι,Παραγραφος$(α$,ι), ~(13),Παραγραφος$(α$,Αριθμός.Παράγραφου(α$, ι)), ~(11,4,15),Παραγραφος$(β$,Παράγραφος(β$, ι))
      } αλλιώς Τύπωσε μερος ι, Παραγραφος$(α$,ι), ~(13),Παραγραφος$(α$,Αριθμός.Παράγραφου(α$, ι)), ~(11,4),Παραγραφος$(β$,Παράγραφος(β$, ι))
        Τυπωσε
        }
      }    
      Τύπωσε μέρος "Η πρώτη παράγραφος στο α$"
      Τυπωσε υπο
      Ε$=Παράγραφος$(α$,1) \\ αντιγράφουμε τη πρώτη παράγραφο (εδώ ο αριθμός είναι ο πραγματικός)
      Πένα 10 { Αναφορα Ε$ }
      Τύπωσε μέρος "Η παράγραφος με αριθμό παραγράφου 5 στο α$"
      Τυπωσε υπο
      μοναδικός.αριθμός=5 ' το ξέρουμε εδώ - μπορεί σε ένα έγγραφο να μην δίνει παράγραφο, γιατί π.χ. την έχουμε διαγράψει.
      Αν Όχι μοναδικός.αριθμός=Παράγραφος(α$,1) τότε Λάθος "Την πάτησες"
      \\ η συνάρτηση Αριθμός.Παράγραφου() δέχεται μόνο μεταβλητές και όχι εκφράσεις.
      \\ Εδώ δεν έχει νόημα η μαθηματική έκφραση. Ο μοναδικός αριθμός αποδίδεται από το έγγραφο
      Ε$=Παράγραφος$(α$,Αριθμός.Παράγραφου(α$, μοναδικός.αριθμός))
      Πένα 10 { Αναφορα Ε$ }
      Τύπωσε μέρος "Η παράγραφος με αριθμό παραγράφου 5 στο α$, με χρήση δείκτη"
      Τυπωσε υπο
      μοναδικός.αριθμός=5 ' το ξέρουμε εδώ - μπορεί σε ένα έγγραφο να μην δίνει παράγραφο, γιατί π.χ. την έχουμε διαγράψει.
      Ε$=Παράγραφος$(α$,(μοναδικός.αριθμός))
      Πένα 10 { Αναφορα Ε$ }
      Τύπωσε μέρος μοναδικός.αριθμός, "τυπώνει 0 γιατί δεν ορίσαμε φορά!"
      Τύπωσε υπό
      μοναδικός.αριθμός=5 ' θα πάμε μπροστά χωρίς να ξέρουμε τον αύξοντα αριθμό.
      \\ Οι συναρτήσεις Μπροστά() και Πίσω() ορίζουν φορά
      \\ Όταν φθάσουμε στο άκρο τότε η φορά μηδενίζει..(δεν κάνει κύκλο).
      \\ Με την χρήση των μοναδικών αριθμών έχουμε γρηγοτότερη κίνηση
      \\ στο έγγραφο.
      \\ Αν χρησιμοποιούσαμε τον Αύξοντα αριθμό, τότε κάθε φορά θα έπεπε να διατρέξει
      \\ ο διερμηνευτής τις παραγράφους,να τις μετράει και να σταματήσει στο Α/Α που ζητάμε
      \\ ο μοναδικός αριθμός ουσιαστικά είναι δείκτης σε παράγραφο.
      \\ κάθε φορά που τον χρησιμοποιούμε στη Παράγραφος$() δείχνει την επόμενη παράγραφο ή το μηδέν
      αν Μπροστά(α$, μοναδικός.αριθμός) τότε {
            Ενώ μοναδικός.αριθμός> 0 {
                  Ε$=Παράγραφος$(α$,(μοναδικός.αριθμός))
                  Πένα 10 { Αναφορα Ε$ }
            }
      }

Αναθεώρηση 91 - μια μικρή βελτίωση

Επ ευκαιρία έφτιαξα πιο σωστά την ~(), και στο χρωματιστή εντολών στον διορθωτή και για την σωστή εμφάνιση (λόγω αλλαγών σε άλλες αναθεωρήσεις, δεν είχα επισημάνει κάποιες ανακολουθίες). Τώρα είναι ΟΚ. Μπορεί κανείς να αλλάξει το καθολικό πλάτος στηλών στη Τύπωσε $(,8)  (η πρώτη παράμετρος λείπει επίτηδες, είναι αυτή που δηλώνει το τρόπο εκτύπωσης, η Τύπωσε Μέρος και Υπό έχουν το 4 εξ ορισμού, που σημαίνει αναλογική γραφή).
Αν αλλάξουμε την Ανανέωση στο 1000 θα δούμε πιο αργές ανανεώσεις!
Η Θέσε Γρήγορα ! καταργεί τυχόν άλλες δοκιμές για ανανέωση, και έτσι λειτουργεί μόνο αυτή που έχουμε γράψει ως Ανανέωση Δοκιμή.

Το προγραμματάκι αυτό θέλει να δείξει πως φτιάχνουμε νέες στήλες από το 5ο χαρακτήρα, με τοπικό πλάτος (μόνο για αυτές τις εντολές) το 12. Επιπλέον χρωματίζουμε κάποια "κελιά" με το χρώμα που θέλουμε (αλλού βάζω το 2 και αλλού το 14).

Δείτε ακόμα πως μπορώ σε ένα κελί να τυπώσω δυο πράγματα, και το George και το αριθμό Α. Η τύπωσε με όλα αυτά τα πολύπλοκα καλούδια χρησιμοποιείται και για την εκτύπωση! Εδώ όμως λειτουργεί σαν οθόνη επισκόπησης γεγονότων (ας υποθέσουμε πως οι τιμές αλλάζουν από ένα εξωτερικό πρόγραμμα)

Οθόνη 5
Πένα 14
Θεσε Γρηγορα !
Ανανέωση 10
Για A=1 εως 1000 {
      Οθόνη ,5 \\ χωριστή οθόνη από την 5η γραμμή
      Τύπωσε $(,8)
      Τύπωσε Μέρος @(5),$(,12),~(13,2), "George=";A,~(4,14), 5,~(14)
      Τύπωσε Υπό
      Τύπωσε Μέρος @(5),$(,12), "George=";A, 5*A
      Τύπωσε Υπό
      Πένα 14
      Τύπωσε "George", "1"
      Τύπωσε "George",~(12,3),A
      Πένα 14
      Ανανέωση Δοκιμή
}


Κάτι επιπλέον (λειτουργούσε και σε προηγούμενες αναθεωρήσεις).
Ένας τρόπος να επικοινωνήσει με άλλα προγράμματα η Μ2000 είναι να χρησιμοποιείσει τα "αντικείμενα". Οι μεταβλητές a και fs περιέχουν αντικείμενα. Δεν μπορούμε να "αντιγράψουμε" τα αντικείμενα αυτά. Δεν γίνεται αντικατάσταση, αυτό που θα δοθεί θα είναι μια μηδενική τιμή. Όμως μπορούμε να περάσουμε αναφορά σε ρουτίνα, ή σε τμήμα ή σε συνάρτηση!
Εδώ  χρησιμοποιούμε το Scripting.FileSystemObject για να γράψουμε ένα αρχείο. Η Μ2000 έχει άλλες εντολές για να γράφει αρχεία, αλλα εδώ βλέπουμε πως μπορούμε να επικοινωνήσουμε με ένα αντικείμενο που ουσιαστικά είναι ένα άλλο πρόγραμμα και μας δίνει για παράδειγμα εδώ ένα αντικείμενο από την CreateTextFile στο a.
Η εντολή Σύστημα (ή Συς ή Συσ) είναι σαν την την γραμμή εκκίνησης των XP. Ξεκινάει προγράμματα δίνοντας αρχεία. Συστημα calc ανοίγει την αριθμομηχανή.

Όρισε fs "Scripting.FileSystemObject"
Μέθοδος fs, "CreateTextFile", "c:\testfile2.txt", Αληθης ως a
Διαμέσου ΓράψεΚλείσε(&a, "This is a test.")
Όρισε a Τίποτα
Όρισε fs Τίποτα
Σύστημα c:\testfile2.txt


Ρουτίνα ΓράψεΚλείσε(&F, τι$)
      Μέθοδος F, "WriteLine",τι$
      Μέθοδος F, "Close"
Τέλος Ρουτίνας



Εικόνες στην Μ2000 (Μέρος 2ο) - Διαφάνειες και Παίκτες

'Ενα μικρό πρόγραμμα που μας δείχνει πως χρησιμοποιούμε μια διαφάνεια. Η διαφάνεια είναι μια εικόνα σε ένα αλφαριθμητικό που εμφανίζουμε με ορισμό ενός χρώματος με 100% διαφάνεια, μιας γωνίας σε μοίρες, ένα μέγεθος με το 100 για ίδιο μέγεθος με το αρχικό και με ή ένα ποσοστό ολικής διαφάνειας ή με μια άλλη εικόνα που δηλώνει κάθε σημείο πόσο διάφανο θα είναι.
 Για να τρέξουμε το παράδειγμα πρέπει να υπάρχει όπως γράφει το "μάρκο" του περιβάλλοντος, όπως ξεκινάει και γράφει δυο τρεις αράδες στην πάνω γραμμή και εφαρμόζει την χωριστή οθόνη (γίνεται ολίσθηση από μαι γραμμή και κάτω).
Γράφουμε  Σ Α και με enter ανοίγει ο διορθωτής. Αντιγράφουμε το παρακάτω και με Esc βγαίνουμε στη γραμμή εντολών. Γράφουμε Α και βλέπουμε την μάσκα να τυπώνεται και τη διαφάνεια σε μια θέση εμφανισμένη. Ουσιαστικά έχει τυπωθεί πάνω στην οθόνη. Η εντολή Διάφανο Διαφάνεια$ χρησιμοποιείται για να επιστρέψει αυτό που τυπώθηκε (το κρατάει το περιβάλλον μια φορά στην εσωτερική μεταβλητή Διαφάνεια$). Κάθε φορά που πατάμε ένα πλήκτρο, αλλάζει θέση η διαφάνεια.
Αυτού του είδους οι διαφάνειες λέγονται "software sprites", διότι δεν μπορούμε μετά την εμφάνιση να αλλάξουμε το φόντο χωρίς να κάνουμε πάλι την εργασία της εμφάνισης.

\\ μας ενδιαφέρει να μην έχει γίνει καθαρισμός της οθόνης
\\ για να αντιγράψουμε το κομμάτι εκείνο που λέει
\\ ΠΕΡΙΒΑΛΛΟΝ Μ2000
α$=""  \\ εδώ μπαίνει η εικόνα
β$=""  \\ εδώ μπαίνει η μάσκα
θέση 0,0
\\ σηκώνουμε το χρώμα της πάνω αριστερής γωνίας
χρώμα_ολικής_διαφάνειας=σημείο
\\ θα  ορίσουμε μέγεθος 150% δηλαδή και μισή φορά παραπάνω
μέγεθος_διαφάνειας=150
Αντέγραψε 2000,1000 στο α$
θέση 2000,0
\\ δίνουμε χρώμα 7 που είναι το γκρι
\\ θα μπορούσαμε να δώσουμε χρώμα με κωδικό της html
\\ Βαψε 2000,1000, #AACCBB
\\ Βαψε 2000,1000, #777777   \\ ένα γκρι καλύτερα
Βαψε 2000,1000,7
θέση 3000,500
κύκλος γέμισμα 0, 800, 0.5,0
θέση 2000,0
\\ φτιάξαμε μια μάσκα και τη βάζουμε στο β$
\\ με τη μάσκα το μαύρο έχει 100% διαπερατότητα, το γκρί (το
Αντέγραψε 2000,1000 στο β$
Για χ=100 εως 12000 ανά 200 {
      Διάφανο Διάφανεια$ \\ τυπώνουμε το πίσω (αν υπάρχει) που σηκώνει η επόμενη εντολή
      θέση χ,1000
      Διάφανο α$, χρώμα_ολικής_διαφάνειας,χ δια 100, μέγεθος_διαφάνειας, β$
      \\ αντί για το β$ τη μάσκα μπορούμε να ορίσουμε όπως παρακάτω το ποσοστό διαφάνειας εδώ 50%
      \\ Διάφανο α$, χρώμα_ολικής_διαφάνειας,χ δια 100, μέγεθος_διαφάνειας, 50
      ανανεωση
      κ$=κομ$ \\ περιμένουμε πλήκτρο
}
Διάφανο Διάφανεια$




Η Μ2000 διαφθέτει και άλλου είδους διαφάνειες, τους παίκτες, οι οποίοι είναι σε δικό τους επίπεδο, και έτσι δεν "μπλέκονται" με το γραφικό του φόντου. Οι παίκτες μπορούν να έχουν ή όχι ένα χρώμα για 100% διαφάνεια (π,χ, Παίκτης 1 με Α$,0,-1 το -1 κάνει το Α$ να φαίνεται όλο). Το δεύτερο νούμερο κανονίζει την ένταση, δηλαδή πόσα άλλα όμοια χρώματα θα κάνει διάφανα. Με 0 σημαίνει ότι μόνο αυτό που ορίσαμε θα είναι διάφανο. Αν αντί για χρώμα δώσουμε αλφαριθμητικό με εικόνα (μάσκα) τότε θα χρησιμοποιήσει το άσπρο για διάφανο. Εδώ δεν έχουμε ανά εικονοστοιχείο διαφορετικό βαθμό διαφάνειας. Και στην περίπτωση της μάσκας η δεύτερη παράμετρος παίζει το ρόλο του διακόπτη, με -1 δεν χρησιμοποιείται η μάσκα. Το μέγεθος ορίζεται με το 1 ως το ολόκληρο και για το λόγο αυτό διαιρώ το 150 με το 1000.Το ΔΙΑ είναι η ακαίρεα διαίρεση (Div η εντολή στα αγγλικά και MOD ή ΥΠΟΛ ή ΥΠΟΛΟΙΠΟ για το ακέραιο υπόλοιπο). Οι παράμετροι είναι προεραιτικοί. Μάλιστα αν δώσουμε μια φορά το σχέδιο του παίκτη και δεν σκοπεύουμε να αλλάξουμε γωνία ή μέγεθος ή εικόνα ή μάσκα ή ότι άλλο τότε δεν χρειάζεται να τα ορίζουμε σε κάθε κλήση αλλαγή θέσης. Αν δεν δηλώσουμε να κρυφτεί ο παίκτης τότε παραμένει στην οθόνη! Μάλιστα σκιάστε αυτή την τελευταία εντολή (με ένα ή δυο \ ) και μετά βγήτε στη γραμμή εντολών και δώστε Παίκτης 6000, 6000 και δείτε ότι πάει όπου θέλετε χωρίς να το πειράζει τι είναι από κάτω.

Υπάρχουν 32 παίκτες και 32ος είναι πάντα πάνω από τους άλλους!

\\ μας ενδιαφέρει να μην έχει γίνει καθαρισμός της οθόνης
\\ για να αντιγράψουμε το κομμάτι εκείνο που λέει
\\ ΠΕΡΙΒΑΛΛΟΝ Μ2000
α$=""  \\ εδώ μπαίνει η εικόνα
β$=""  \\ εδώ μπαίνει η μάσκα
θέση 0,0
\\ σηκώνουμε το χρώμα της πάνω αριστερής γωνίας
χρώμα_ολικής_διαφάνειας=σημείο
\\ θα  ορίσουμε μέγεθος 150% δηλαδή και μισή φορά παραπάνω
μέγεθος_διαφάνειας=150
Αντέγραψε 2000,1000 στο α$
θέση 2000,0
Βαψε 2000,1000,15
θέση 3000,500
κύκλος γέμισμα 0, 800, 0.5,0
θέση 2000,0
\\ φτιάξαμε μια μάσκα και τη βάζουμε στο β$
\\ με τη μάσκα το μαύρο έχει 100% διαπερατότητα, το γκρί (το
Αντέγραψε 2000,1000 στο β$


       Παίκτης 1,0,0 με α$,χρώμα_ολικής_διαφάνειας,0 Μέγεθος μέγεθος_διαφάνειας/100
      Παίκτης 1 Δείξε
Για χ=100 εως 12000 ανά 200 {
     \\ Παίκτης 1,χ,1000
     \\ Παίκτης 1,χ,1000 με α$ , χρώμα_ολικής_διαφάνειας,0,χ δια 100 Μέγεθος μέγεθος_διαφάνειας/100
     Παίκτης 1,χ,1000 με α$, β$,0,χ δια 100 Μέγεθος μέγεθος_διαφάνειας/100
      κ$=κομ$ \\ περιμένουμε πλήκτρο
}

Παίκτης 1 κρύψε


Σχέδιο Νημάτων (thread plan) και η αναθεώρηση 90

Στην αναθεώρηση 90 διόρθωσα ένα μικρό λαθάκι, και τώρα μπορεί να λειτουργήσει σωστά το παρακάτω παράδειγμα.

\\ Σχέδιο.νημάτων Διαδοχικό
Σχέδιο.νημάτων Ταυτόχρονο
Οθονη,0
Ανανέωση 3000
ι=0
Νήμα {
      Δρομέας 0,0
      Τύπωσε Πάνω $(4,8), ι, Γραφή$(τώρα,"hh:ss"),"Παράδειγμα με την Ανανέωση και Νήμα"
      Τύπωσε Υπο
      Ανανέωση
} Ως κ Κάθε 1000


Κύριο.Έργο 10 {


      Για ι=ι έως ι+100 {
            Θεση Τυχαίος(0,Χ.σημεία), Τυχαίος(0,Υ.σημεία)
            Χάραξε εως Τυχαίος(0,Χ.σημεία), Τυχαίος(0,Υ.σημεία), Τυχαίος(0,15)
            ι++
      }
      Αν Πατημένο(2) Τότε Έξοδος
      Αν Πατημένο(32) Τότε Έξοδος
}       
Νήματα Σβήσε




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

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

Στο σχέδιο ταυτόχρονο ότι είναι σε αγκύλες θα εκτελεστούν χωρίς διακοπή. Στο νήμα Κ δεν έχουμε αγκύλες (αυτές που βλέπουμε όρισαν το νήμα, και στο κώδικα που αντιγράφεται στο νήμα  δεν υπάρχουν). Θα εκτελεστεί η "τύπωσε πάνω" αλλά μέχρι να εκτεστεί η ανανέωση, το πιθανότερο είναι ότι θα εκτελεστεί κάποιο από τα τρία κομμάτια του Κύριου Έργου και ίσως το Για { } που θα ρίξει εκατό γραμμές, και πιθανόν μερικές από αυτές να περνάνε από την γραμμή στο ύψος 0, (την πιο πάνω γραμμή χαρακτήρων στην οθόνη). Πράγματι θα δείτε να βγαίνουν γραμμές πάνω στο τίτλο!

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

{
      τύπωσε πάνω $(4,8), ι, γραφη$(τώρα,"hh:ss"),"Παράδειγμα με την Ανανέωση και Νήμα"
      τυπωσε υπο
      ανανεωση
}

Ο προγραμματισμός είναι ένα "παιχνίδι" διάγνωσης αλλαγής καταστάσεων και εδώ με την επιλογή ταυτόχρονο στο  σχέδιο.νημάτων μπερδεύονται τα πράγματα. Πάντως έχω και άλλα παραδείγματα πιο πολύπλοκα που φαίνεται η  καλή χρήση της "ταυτόχρονο " ή Thread.plan concurrent  (Thread.plan sequential το αντίστοιχο διαδοχικό). 

Μια παραλλαγή είναι με την χρήση της Για Επόμενο, η οποία όπως βλέπουμε δεν έχει μπλοκ που σημαίνει ότι μπορεί να εκτελεστεί με το σχέδιο ταυτόχρονο:
      για ι=ι εως ι+100
            θεση τυχαιος(0,χ.σημεια), τυχαιος(0,υ.σημεια)
            χαραξε εως τυχαιος(0,χ.σημεια), τυχαιος(0,υ.σημεια), τυχαιος(0,15)
            ι++
επόμενο ι

Η Για Εως Επόμενο είναι πιο αργή από την Για Εως {} αλλά μπήκε για δυο λόγους, για τη χρήση αυτή που μόλις περιέγραψα και επειδή μοιάζει με την ίδια εντολή της BASIC/ Υπάρχουν διαφορές με κύριες δύο ότι και να αλλάξουμε την τιμή στη μεταβλητή ελέγχου μέσα στην επανάληψη, αυτή δεν θα αλλάξει από την προγραμματισμένη για κάθε επανάληψη, που σημαίνει ότι στο επόμενο βήμα θα έχει την τιμή που πρέπει! Το δεύτερο είναι ότι το πρόσημο στο βήμα (μετά την εντολή ΑΝΑ, π.χ. Για Ι =1 έως 10 ανά 2  ) το τυχόν πρόσημο χρησιμεύει μόνο σε περίπτωση που η αρχή και το τέλος είναι ίδια, για να αποφασίσει ο διερμηνευτής τι τμή θα αφήσει μετά την επανάληψη. Ποτέ δεν αφήνει την ίδια τιμή με αυτή που ξεκινάει, και ποτέ δεν υπάρχει περίπτωση να μην εκτελέσει τουλάχιστον μια φορά την επανάληψη. (αυτά ισχύουν και για τις δυο ΓΙΑ). Στην Για { } βγαίνουμε πριν τελειώσουν όλες οι επαναλήψει με Έξοδος ή με ΠΡΟΣ μια ετικέτα εκτός μπλοκ, ενώ στην Για Επόμενο βγαίνουμε με την Έξοδος Για.

Η επόμενο μπορεί να υπάρχει περισσότερες από μια φορές. Δοκίμασε το παρακάτω. Δοκίμασε με ι<10 και με ι>10. Η έξοδος Για ή βρίσκει το τελευταίο Επόμενο ι αν δεν έχει γίνει μια πλήρη επανάληψη ή χρησιμοποιεί το τελευταίο επόμενο.ι. Αν αφαιρέσουμε την Προς 120 και βάλουμε Αν ι<10....τότε θα τυπωθεί το Οκ2, το 441, το Οκ και το 21. Αν βάλουμε το Προς 120 τότε θα δούμε το Οκ2 και το 21 μόνο. Η τελευταία Επόμενο ι δεν θα πειράξει το Ι, επειδή τελικά δεν πρόκειται να κάνει κάτι, η επανάληψη έχει τελειώσει, με την Έξοδος Για.

Για ι=1 Έως 100
Αν ι>20 τότε Έξοδος Για
\\Αν ι<10 τότε προς 100
Αν ι>10 τότε προς 100
Τύπωσε ι
Επόμενο ι
Τύπωσε "Οκ2"
Προς 120


100 Τύπωσε ι**2
110 Επόμενο ι
Τύπωσε "Οκ"
120
Τύπωσε ι

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

Μια επιπλέον αλλαγή είναι η "αποφόρτιση" του υπολογιστή κατά τη χρήση νημάτων με την εισαγωγή ανά 50 msec μιας εντολής sleep 1 όπου για δίνεται χρόνο στο σύστημα να κάνει ότι άλλη εργασία έχει να κάνει (ίσως πάρει περισσότερο χρόνο). Αν ανοίξουμε τον TaskManaget των Windows 7 θα δούμε την "κατανάλωση" ή φόρτο της CPU για την Μ2000. Αν δεν έχουμε νήματα να τρέχουν και δεν περιμένει το σύστημα να πληκτρολογήσουμε κάτι, τότε το περιβάλλον παίρνει το 100% του επεξεργαστή (αν έχουμε δύο τότε παίρνει το 50, αν έχουμε τέσσερις το 25, δηλαδή παίρνει έναν επεξεργαστή). Τα νήματα είναι κλήσεις από το Kernel σε ένα σύστημα "χώρου νημάτων σε αναμονή", απ΄όπου βγαίνει ένα νήμα, εξετάζεται αν θα τρέξει, και αν ναι μπαίνει σε ένα χώρο εκτέλεσης. Οπότε το σύστημα που εξετάζει αν κάτι θα εκτελεστεί δεν βρίσκει ποτέ αυτό που εκτελείται! Εκτός από τα νήματα που χρησιμοποιούμε για τα τμήματα υπάρχουν δυο τύποι ακόμα, που δουλεύουν ανεξάρτητα, και είναι τα νήματα μουσικής (οι δεκαέξι φωνές) και θα βρείτε εδώ ένα παράδειγμα  και οι σωληνώσεις, ο τρόπος να περνάμε δεδομένα από μια εφαρμογή της Μ2000 σε μια άλλη (για να φτιάχνουμε συστήματα Πελάτη Εξυπηρετητή, σε ένα τοπικό δίκτυο και όχι μόνο)

Μια προσθήκη ακόμα. Και εδώ παρουσιάζεται η τελική μορφή της εντολής Ανανέωση
Η αναθεώρηση 90 κλείνει το θέμα εδώ! 

\\ δεν μπορούμε να βάλουμε σημειώση στη γραμμή της θέσε
\\ η Θέσε στέλνει την γραμμή στον διερμηνευτή γραμμής
\\ εκεί δηλαδή που δίνουμε έξω από τμήματα εντολές
\\ η εντολή γρήγορα δεν ανήκει στις εντολές των τμημάτων
θέσε γρήγορα !
\\ θέσε γρήγορα
\\ θέσε αργά
ι=0
ανανέωση 200
{
      τυπωσε ι
       ανανέωση δοκιμή '' δεν χρειάζεται αν είμαστε σε ΑΡΓΑ ήγ ΓΡΗΓΟΡΑ, μόνο σε ΓΡΗΓΟΡΑ !
      \\ Επιλογές για ανανέωση
      \\ ανανέωση    - κάνει ανανέωση και μηδενίζει το μετρητή
      \\ ανανέωση 0 - μηδενίζει τον μετρητή  - άρα δίνει πρόσκαιρα χρόνο όσο το βήμα ανανέωσης
      \\ ανανέωση 100 - βάζει βήμα ανανέωησης τα 100 msec, και κάνει ανανέωση
      \\ Παρακάτω είναι το καινούργιο στην αναθεώρηση 90
      \\ ανανέωση δοκιμή  - κάνει ανανέωση αν είναι οκ ο μετρητής
      \\ Αυτό είναι χρήσιμο στο θέσε Γρήγορα ! όπου "αχρηστεύονται" οι δοκιμές για ταχύτητα
      \\ αλλά μπορούμε να βάλουμε μια εκεί που θέλουμε αντί για μια απλή ανανέωση
      \\ ώστε να μαζέψουμε αυτά που θέλουμε για ανανέωση.
      ι++
      Αν ι>1000 τότε έξοδος
      Κυκλικά
}




Τετάρτη 18 Νοεμβρίου 2015

Απλό Παράδειγμα με Νήμα (Μ2000)

Σήμερα έχει και ένα ελαφρύ θέμα. Θέλουμε να φτιάξουμε έναν απλό screen saver, που θα δείχνει γραμμές, και την ώρα!

Υπάρχει ένας απλός τρόπος όπως αυτός:

οθονη,0
ανανεωση 1000
ι=0
{
      θεση τυχαιος(0,χ.σημεια), τυχαιος(0,υ.σημεια)
      χαραξε εως τυχαιος(0,χ.σημεια), τυχαιος(0,υ.σημεια), τυχαιος(0,15)
      Δρομεας 0,0
      \\  τύπωσε πάνω   \\ καθαρίζει την γραμμή και βάζει μια στήλη όλη τη γραμμή
      \\ τύπωσε μέρος ι, γραφη$(τώρα,"hh:ss")
      \\ αν το έχουμε χωριστά ενδέχεται να γίνει ανανέωση πριν γράψουμε με την τύπωσε μέρος
      \\ οπότε τα συγχωνεύουμε με δήλωση πλάτος στηλών 8, και αναλογική γραφή, νορμάλ, 4
      τύπωσε πάνω $(4,8), ι, γραφη$(τώρα,"hh:ss"),"Παράδειγμα με την Ανανέωση"
      τυπωσε υπο \\ αλλάζει γραμμή αφού κάνει υπογράμμιση πρώτα
      ι++
      αν πατημενο(2) τοτε έξοδος
      αν πατημενο(32) τοτε έξοδος
      κυκλικα
}


Κάθε 1000 msec γίνετι ανανέωση της οθόνης. Η συνάρτηση πατημένο() γυρίζει αληθές αν κάποιο πλήκτρο έχει πατηθεί. Το 2 είναι το δεξί πλήκτρο  του ποντικιού, το 32 είναι το διάστημα (space bar).
Το πρόβλημα του προγράμματος είναι ότι για κάθε γραμμή τυπώνει την ώρα! Μάλιστα αν αλλάξουμε την ανανέωση σε 500 θα βλέπουμε μαζεμένες γραμμές κάθε μισό δευτερόλεπτο.

Ο άλλος τρόπος είναι να χρησιμοποιήσουμε ένα νήμα (ή για την περίπτωσή μας δυο νήματα, αφού το Κύριο.Έργο είναι ένα νήμα και αυτό).

οθονη,0
ανανεωση 3000
ι=0
Νημα {
      δρομεας 0,0
      τύπωσε πάνω $(4,8), ι, γραφη$(τώρα,"hh:ss"),"Παράδειγμα με την Ανανέωση και Νήμα"
      τυπωσε υπο
      ανανεωση
} ως κ κάθε 1000


Κύριο.Έργο 10 {
      για ι=ι εως ι+100 {
            θεση τυχαιος(0,χ.σημεια), τυχαιος(0,υ.σημεια)
            χαραξε εως τυχαιος(0,χ.σημεια), τυχαιος(0,υ.σημεια), τυχαιος(0,15)
            ι++
      }
      αν πατημενο(2) τοτε έξοδος
      αν πατημενο(32) τοτε έξοδος
}       
Νήματα Σβήσε



Ο χρόνος για να βλέπουμε τη ανανέωση της οθόνης καθορίζεται από το χρόνο του νήματος με χειριστή τον κ (εδώ δεν κάνουμε κάποια ειδική ενέργεια στο νήμα κ, οπότε το κ δεν το χρησιμοποιούμε).
Επιπλέον στο κύριο έργο δίνουμε ένα μικρό χρονικό διάστημα, αλλά δεν αφήνουμε να κάνει μια γραμμη αλλά 100 κάθε φορά. Επίσης σε αυτό το κύριο έργο ελέγχουμε την έξοδο. Όταν τερματίσει το Κύριο.Έργο έχουμε μεν το νήμα "εν ζώη"...αλλά τερματίζοντας το τμήμα που τρέχει, το νήμα τερματίζει και αυτό. Ενδέχεται όμως να τερματίσει κάποιο λίγο πιο μετά γιατί την ώρα που τερματίζει το τμήμα, το νήμα να είναι προς εκτέλεση! Οπότε θα εκτελεστεί και μετά θα "πεθάνει". Για το λόγο αυτό η Νήματα Σβήσε σβήνει όλα τα νήματα, πριν βγούμε από το τμήμα.
Αν πατήσουμε Esc τότε σταματάει το τμήμα και κάθε νήμα.

Παρατηρούμε ότι τα νήματα διαβάζουν και αλλάζουν τις μεταβλητές του τμήματος. Αυτό συμβαίνει διότι τα νήματα δεν έχουν όνομα, αλλά έναν αριθμό (ακόμα και το Κύριο.Έργο έχει έναν αριθμό), και οι μεταβλητές ανήκουν στο χώρο ονομάτων (namespace) του τμήματος. Διαφέρουν ως προς το τμήμα στο Σωρό τιμών. Κάθε Νήμα έχει δικό του σωρό. Έτσι αν τυχόν ένα νήμα καλέσει ένα τμήμα και το τμήμα γυρίσει στο σωρό τιμές τότε ο σωρός αυτός δεν μπλέκεται με σωρό άλλου νήματος (που θα συνέβαινε αν είχαν κοινό σωρό).

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

Συνοψίζοντας: Με την χρήση νήματος η ώρα τυπώνεται μια φορά ενώ οι γραμμές πολλές φορές ανά δευτερόλεπτο. Αν ρυθμίσουμε το χρόνο του Κύριου 'Εργου και το πόσες γραμμές θα τυπώνονται κάθε φορά θα πετύχουμε το μέγιστο αριθμό γραμμών ανά δευτερόλεπτο!






Διερεύνηση ρουτίνας ταξινόμησης!

Μια αναθεώρηση ακόμα, η 89, όπου άλλαξα την ρουτίνα με άλλη, για να αποφύγω το τυχαίο πρόβλημα "κολλήματος" κατά το σώσιμο των προγραμμάτων. Παλιά έκανα το εξής..έσβηνα το όνομα.bck,  μετά έκανα αλλαγή ονόματος από όνομα.gsb σε όνομα.bck και τέλος δημιουργούσα ένα νέο  όνομα.gsb όπου έγραφα τα νέα στοιχεία. Και τα τρία στάδια γίνονταν με διαφορετικές βιβλιοθήκες, και ενώ στη τρίτη φάση διόρθωσα το πρόβλημα, την ενδιάμεση, στην αλλαγή ονόματος, όπως διαπίστωσα...περιστασιακά έφερνε κολλήματα. Τώρα τα βήματα είναι δυο, και η βιβλιοθήκη μία, ίδια δηλαδή για τα δύο βήματα. Το πρώτο βήμα κάνει αντιγραφή το όνομα.gsb στο όνομα.bck, και αν βρει το όνομα.bck, το αλλάζει με το αντιγραμμένο. Έτσι σε κάθε περίπτωση έχω το αντιγραμμένο με μια κίνηση! Το επόμενο βήμα είναι το παλιό! Το οποίο είχα διορθώσει. Προς το παρόν δεν βλέπω πρόβλημα!
Σε αυτήν την αναθεώρηση διόρθωσα και άλλα πράγματα, που έχουν σχέση με την ανανέωση των γραφικών. Με την εντολή ΑΝΑΝΕΩΣΗ μπορούμε πια και τις εντολές γραφικών ΧΑΡΑΞΕ, ΚΑΜΠΥΛΗ, ΠΟΛΥΓΩΝΟ, ΚΥΚΛΟΣ, κ.α. να τα κάνουμε να εμφανίζουν το "σύνολο" της δουλειάς σε χρόνο που ορίζουμε με την Ανανέωση. Το Ανανέωση 5000 κάνει το χρόνο εμφάνισης τα 5 δευτερόλεπτα, ενώ δίνει άμεσα μια εμφάνιση. Η εντολή Ανανέωση δίνει άμεσα μια εμφάνιση και ξεκινάει τον μετρητή ξανά. Η εντολή Ανανέωση 0 ξεκινάει πάλι τον μετρητή χωρίς να εμφανίσει. Η Εντολή Κάθε τώρα πια περιλαμβάνει μια "Ανανέωση 0" εσωτερικά. Οι μεταβλητές μόνο ανάγνωσης Ενκομ$ (ένα κομβίο) και Δείκτης, γυρνάνε τιμές για το πληκτρολόγιο και το ποντίκι, με πρόκληση ανανέωσης εκτός μετρήματος. άρα πρέπει να χρησιμοποιούνται σε φάσεις που η ανανέωση δεν μας πειράζει. Αν θέλουμε μπορούμε να χρησιμοποιούμε την ειδική συνάρτηση πατημένο() που στο 1 και 2 μας δίνει τα πλήκτρα του δείκτη (όπως η Δείκτης) χωρίς αν προκαλεί ανανέωση, ενώ η πατημένο(32) για παράδειγμα δίνει -1 αν πατάμε το διάστημα. Όλα τα πλήκτρα του πληκτρολογίου, έχουν νούμερο και μπορούμε να κοιτάμε την κατάστασή τους ανεξάρτητα! Έτσι σε περιπτώσεις που δεν θέλουμε ανανέωση -ανεξέλεγκτη- έχουμε τρόπο. Ορισμένες φορές αντί να βάλουμε μια Ανανέωση βάζουμε μια Αν ενκομ$=" " Τότε Έξοδος και έχουμε δυο σε ένα!



Ένα παράδειγμα-άσκηση-ασχολία στη Μ2000. 
Περιέχει μια ρουτίνα ταξινόμησης που πρόσφερε στο Vbforoums ένα παλιός προγραμματιστής (60+), δείτε εδώ τον κώδικα που είχε παρουσιάσει, και όπως λέει ήταν από το PDP-11
minicomputer. (σε εκείνο το φόρουμ δημοσιεύω ως GeorgeKar μια επέκταση της quicksort, και γίνεται σύγκριση ρουτινών, κόντρα με την καλή έννοια).

Η ρουτίνα είναι μια Shell Sort με υλοποίηση κάπως μυστήρια. Τα αλφαριθμητικά βρίσκονται όλα σε ένα και δεν μπορούν να μετακινηθούν. Υπάρχει ένας αρχικός πίνακας (δίνεται ως σειρά σε σωρό, η Σειρά στη Μ2000 χρησιμοποιεί το σωρό - εσωτερική ειδική στοίβα- ως FIFO. Τα στοιχεία τα "σηκώνουμε" με τη διάβασε. Έχω δημιουργήσει ένα μπλοκ με νέο σωρό -αλλά δεν χρειάζεται λογικά, εκτός και αν παραμένουν στοιχεία στον υπάρχον σωρό, οπότε ο νέος παρεμβάλλεται και στο πέρας επιστρέφει τον παλιό- κάτι σαν stack frame.

Για κάθε αλφαριθμητικό υπάρχει η αρχή και το τέλος, σε δυο μονοδιάστατους πίνακες. Επιπλέον υπάρχει ξεχωριστός πίνακας για τους δείκτες στους δυο προηγούμενους, που κρατάει την σειρά, και την οποία θα την ταξινομήσουμε.
Έτσι το ν στοιχείο του πίνακα sortptrs() δίνει ένα δείκτη για τους άλλους δυο πίνακες, απ΄όπου θα πάρουμε την αρχή και το τέλος ενός αλφαριθμητικού, σε ένα μοναδικό αλφαριθμητικό που περιέχει όλα τα άλλα (ας πούμε την μνήμη), το strSearch$

Φτιάχνουμε μια οθόνη με χρώμα Magenta (το 5), χωρίς χωριστή οθόνη (το μηδέν μετά το πέντε) και πλάτος 60 χαρακτήρες και γραμμές (ή ύψος σε χαρακτήρες) 30. Χρώμα πένας το κίτρινο.
Φτιάχνω δυο γενικές μεταβλητές τον αριθμό των συγκρίσεων και τον αριθμό αλλαγών. Θέλω να διερευνήσω, πόσες συγκρίσεις και πόσες αλλαγές κάνει ο αλγόριθμος σε διάφορες περιπτώσεις.
Έχω καταγράψει κάποια αποτελέσματα σε δεδομένα που έχω πια σκιάσει - ως σημειώσεις.
Με ενδιαφέρει από ένα σημείο και μετά να δω τι γίνεται όταν κάνω προσθήκες.
Οι πίνακες στη Μ2000 μπορούν να οριστούν ξανά (και να αλλάξουν διάσταση) χωρίς να χάσουν τα στοιχεία τους (εκτός αν βάλουμε ένα π.χ. Πίνακας Α$(10)="" οπότε το μηδενίζουμε, βάζουμε "" σε κάθε στοιχείο).



Έχω κάνει μερικά στοιχεία βοηθητικά, όπως μια συνάρτηση η Getone$(). Εκεί δίνω με αναφορά το strSearch$ για να μην το αντιγράψω, αν και το Μεσ$() θα πάρει αντίγραφο, αφού δουλεύει με εκφράσεις! Το ίδιο κάνω και στην mxstrcmp(), αλλά εκεί τουλάχιστον η σύγκρινε δουλεύει με μεταβλητές και κάνει σύγκριση χωρίς αντιγραφές (δεν παίρνει εκφράσεις).
Επίσης χρησιμοποιώ ένα τμήμα γενικής χρήσης, για να γεμίσω τιμές σε ένα πίνακα (ο sortptrs()), και περνάω τον πίνακα με αναφορά, και εκεί μέσα διαβάζω το μέγεθός του.

Τον αλγόριθμο ταξινόμησης τον μετέφερα σε μια ρουτίνα απλή. Οι απλές ρουτίνες είναι μέρη του τμήματος, σαν να ήταν σε ένα οποιοδήποτε μέρος του. Έχουν ένα όνομα και χρειάζεται η εντολή επιστροφή για να γυρίσουν. Έτσι με την μεταφορά του τον χρησιμοποιώ μερικές φορές ακόμα. Χρησιμοποιώ μια ρουτίνα με παράμετρο. Εδώ οι ρουτίνες έχουν το Ρουτίνα Όνομα() και στο τέλος το Τέλος Ρουτίνας. Η διαφορά τους από τις απλές ρουτίνες είναι ότι κάθε νέο εντός τους θα χαθεί μετά - εκτός από την αλλαγή τιμών και διαστάσεων σε πίνακες...και τιμών σε μεταβλητές γενικές και άλλε του τμήματος. Επειδή ουσιαστικά και η ενισχυμένη ρουτίνα είναι μέρος του τμήματος, τα ονόματα των μεταβλητών που δίνουμε για εισαγωγή, δεν πρέπει να υπάρχουν σαν ονόματα μεταβλητών στο τμήμα - αλλιώς θα γυρίσει ο διερμηνευτής λάθος. Η strAdd θα χαθεί μετά την διαμέσου ΠρόσθεσεΈνα().


Σε αυτό το πρόγραμμα "διερεύνυσης" έχει χρησιμοποιηθεί Συνάρτηση, Τμήμα, Ρουτίνα, Απλή Ρουτίνα, Προς. Έχουν χρησιμοποιηθεί τα Για και Επανέλαβε Πάντα και Επανέλαβε Μέχρι. Επίσης τα Αν Τότε και Αν Τοτε Αλλιώς.
Βλέπουμε επίσης μεγάλη χρήση ετικετών (αναγνωριστικά με άνω κάτω τελεία στο τέλος τους, και μόνα τους στη γραμμή).

Επίσης χρησιμοποιείται η εντολή Άλλαξε (Swap) που δουλεύει μόνο για μεταβλητές, αλλάζοντας έναν εσωτερικό μοναδικό δείκτη. Επίσης το ++ και -=. Τις γενικές μεταβλητές τις καθαρίζουμε με μια εντολή την Καθαρό (προσοχή χωρίς μεταβλητές ως παραμέτρους..σβήνει όλες τις μεταβλητές, επίσης μπορεί να καθαρίσει και πίνακες..με μηδέν διάσταση)



Οθόνη 5, 0
Φόρμα 60,30
Πένα 14
Γενικές συγκρίσεις, αλλαγές
Συνάρτηση Getone$ {
      Διάβασε &buffer$, start1, end1 
\\    :  ? start1, end1      end1-=start1-1
      =Μεσ$(buffer$,start1,end1)
}
Συνάρτηση mxstrcmp {
      Διάβασε &Cmp$, start1,end1, start2,end2
      end1-=start1-1 \\ end=end-start+1
      end2-=start2-1
      hlp1$=Μεσ$(Cmp$,start1,end1)
      hlp2$=Μεσ$(Cmp$,start2,end2)
      =σύγκρινε(hlp1$,hlp2$) \\ μόνο μεταβλητές
      συγκρίσεις++
}
\\ Σε τυχαία σειρά, κανένα δεν είναι στη θέση του
\\ 10 συγκρίσεις - 7 αλλαγές
\\strSearch$ = "OneTwoThreeFourFive*"
\\Σειρά 1,4,7,12,16,20,0


\\ Είναι σε σωστή σειρά - 0 αλλαγές
\\ 8 συγκρίσεις - 0 αλλαγές
\\strSearch$ = "*FiveFourOneThreeTwo"
\\Σειρά 1,2,6,10,13,18,0
\\  Είναι σε φθίνουσα σειρά!
\\ 12 Συγκρίσεις - 9 αλλαγές
strSearch$ = "TwoThreeOneFourFive*"
Σωρός Νέος {
      Σειρά 1,4,9,12,16,20,0
   
      i=1 ' χρησιμοποιούμε πίνακες με βάση το 0 αλλά εδώ ξεκινάμε από το 1
      k=0
      Διάβασε startKeyWord
      Επανέλαβε {
            Πίνακας smarkerskt(i) \* αλλάζουμε μέγεθος χωρίς να σβήσουμε στοιχεία
            smarkerskt(k)=startKeyWord : i++
            Πίνακας emarkerskt(i) : Διάβασε startKeyWord
            Αν startKeyWord = 0 Τότε Έξοδος
            emarkerskt(k)=startKeyWord-1 : k++
      } Πάντα
}
emarkerskt(k)=len(strSearch$)
nKeywordskt=6
Πίνακας sortptrs(nKeywordskt) 'έχουμε ένα παραπάνω στοιχείο στη θέση 0
\* general form to fill array with a variable value
Τμήμα fillme {
      Διάβασε &ar()
      k=διάσταση(ar(),1) : i=0 : Επανέλαβε { ar(i)=i : i++ : k-- } Μέχρι k=0
}
fillme &sortptrs()
\\Διαμέσου αταξινόμητα
Διαμέσου στη_τάξη
Διαμέσου εδω_τυπώνουμε
\\ θα προσθέσουμε ένα στοιχείο
Διαμέσου ΠρόσθεσεΈνα("George")
Καθαρο συγκρίσεις , αλλαγές
Διαμέσου στη_τάξη
Διαμέσου εδω_τυπώνουμε
Διαμέσου ΠρόσθεσεΈνα("Hello")
Καθαρο συγκρίσεις , αλλαγές
Διαμέσου στη_τάξη
Διαμέσου εδω_τυπώνουμε
Διαμέσου ΠρόσθεσεΈνα("1")
Καθαρο συγκρίσεις , αλλαγές
Διαμέσου στη_τάξη
Διαμέσου εδω_τυπώνουμε
Διαμέσου ΠρόσθεσεΈνα("Zero")
Καθαρο συγκρίσεις , αλλαγές
Διαμέσου στη_τάξη
Διαμέσου εδω_τυπώνουμε
Διαμέσου ΠρόσθεσεΈνα("Mark")
Καθαρο συγκρίσεις , αλλαγές
Διαμέσου στη_τάξη
Διαμέσου εδω_τυπώνουμε
\*

Έξοδος
αταξινόμητα:
      για i=1 έως nKeywordskt {
           Πένα 15 { Τύπωσε getone$( &strSearch$, smarkerskt(sortptrs(i-1)), emarkerskt(sortptrs(i-1))) }
      }
      Τύπωσε "Στοιχεία:";nKeywordskt
Επιστροφή
εδω_τυπώνουμε:
      \* Εδώ τυπώνουμε
      for i=1 to nKeywordskt {
      Πένα 15 { Τύπωσε getone$( &strSearch$, smarkerskt(sortptrs(i-1)), emarkerskt(sortptrs(i-1))) }
      }
      Τύπωσε "Έγινε"
      Τύπωσε "συγκρίσεις:";συγκρίσεις
      Τύπωσε "αλλαγές:";αλλαγές
      Τύπωσε "Πάτα Ένα Πλήκτρο, για να συνεχίσω"
      π$=κομ$
Επιστροφή
στη_τάξη:
      \* Εδώ είναι ο παλιός κώδικας - έχω βάλει την Άλλαξε για ευκολία!
      \* s5 και s6 είναι δείκτες για τον πίνακα που έχει τους δείκτες για την "μνήμη"
      \* όλες οι λέξεις είναι σε μια μνήμη (ένα αλφαριθμητικό) και παραμένουν ως έχουν
      s1 = nKeywordskt
      s2 = s1
      s3 = 0 : s4 = 0 : s5 = 0 : s6 = 0
      a = 0
   
      GP_SP_S1:
   
      s1 = int(s1 / 2)
      Αν s1 = 0 Τότε {
            Προς GP_SP_S5
      }
   
      s3 = s2 - s1
      s4 = 1
   
      GP_SP_S2:
      s5 = s4
   
      GP_SP_S3:
      s6 = s5 + s1
      \\? s1, s2,s3,s4
      \\? s5-1,s6-1
      a = mxstrcmp( &strSearch$, smarkerskt(sortptrs(s5-1)), emarkerskt(sortptrs(s5-1)), smarkerskt(sortptrs(s6-1)), emarkerskt(sortptrs(s6-1)))
      Αν a = 0 Τότε {
            Αν sortptrs(s5-1) < sortptrs(s6-1) Τότε {
                  a = -1
            } Αλλιώς {
                  a = 1
      }
      }
      Αν a <= 0 Τότε {
            Προς GP_SP_S4
      }
      Άλλαξε sortptrs(s5-1), sortptrs(s6-1)
      Αλλαγές++
      s5 = s5 - s1
   
      Αν s5 >= 1 Τότε {
            Προς GP_SP_S3
      }
   
      GP_SP_S4:
      s4 = s4 + 1
      Αν s4 > s3 Τότε {
            Προς GP_SP_S1
      }
      Προς GP_SP_S2
   
      GP_SP_S5:
      s1 = 0 \* απλά υπήρχε αυτό στο κώδικα!
Επιστροφή
Ρουτινα ΠρόσθεσεΈνα(strAdd$)
      Πένα 11 { Τύπωσε :Τύπωσε "Νέα λέξη:";strAdd$ }
      Πίνακας smarkerskt(nKeywordskt+1), emarkerskt(nKeywordskt+1) \\ αυξάνουμε τα στοιχεία χωρίς να σβήνουμε
      smarkerskt(nKeywordskt)=μήκος(strSearch$)+1
      emarkerskt(nKeywordskt)=smarkerskt(nKeywordskt)+μήκος(strAdd$)-1
      strSearch$=strSearch$+strAdd$
      Πίνακας sortptrs(nKeywordskt+1)
      sortptrs(nKeywordskt) =nKeywordskt
      nKeywordskt++
Τέλος Ρουτίνας