Σάββατο 13 Μαΐου 2017

Αναθεώρηση 23 (Έκδοση 8.7)

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

Σε αυτήν την αναθεώρηση βρήκα επιτέλους την τέλεια λύση για τον συλλέκτη σκουπιδιών. Τα αντικείμενα που τα χειριζόμαστε με αναφορά με δείκτη (και σε αυτές υπάρχει μετρητής αναφορών, ως γνήσια αντικείμενα), τα χρησιμοποιώ μέσω ενός αντικειμένου mHandler, το οποίο έχει κάποιες ενδιαφέρουσες δυνατότητες, μια εκ των οποίων είναι ότι τερματίζει πρώτα αυτό και στο terminate (deconstructor) ενώ έκανε απλά αποδέσμευση της αναφοράς στο αντικείμενο, τώρα κοιτάει αν στον συλλέκτη σκουπιδιών έχει αναφορά (δεν έχουν όλα), και αν ναι τότε κοιτάει τον μετρητή, και αν δει ότι είναι δυο, μία του συλλέκτη και μια του mHandler, τότε το καθαρίζει από το συλλέκτη και μετά καθαρίζει και το δικό του στο τέλος. Ο τελευταίος καθαρισμός μπορεί να προκαλέσει καθαρισμούς και σε άλλους mHandler που μπορεί να ήταν αποθηκευμένοι σε αυτό το αντικείμενο. Τα αντικείμενα που έχουν "παρουσία" στο συλλέκτη είναι πίνακες, καταστάσεις, σωροί, και αυτά μπορούν να έχουν αναφορές σε άλλα τέτοια αντικείμενα.
Ο συλλέκτης σκουπιδιών μπήκε για να βρίσκει τις κυκλικές αναφορές, δηλαδή αν ένα αντικείμενο έχει στα περιεχόμενά του αναφορά στο ίδιο, ή έχει αναφορά σε άλλο και το άλλο στο  πρώτο. Η εντολή Λίστα μας δείχνει εκτός από τις τρέχουσες μεταβλητές και τον αριθμό αντικειμένων που έχει ο συλλέκτης (αν έχει δείχνει). Υπάρχει εντολή Άδειασε Σκουπίδια η οποία κάνει το εξής: Πρώτα μαζεύει σε ένα δεύτερο αντικείμενο "συλλέκτη σκουπιδιών" μόνο τους δείκτες χωρίς να είναι "ενεργοί", δηλαδή απλά τους κάνει κλειδιά, και για κάθε αντικείμενο δίνει τον καθαρισμό τους. Μόλις τελειώσει το μάζεμα, κοιτάει τον κανονικό συλλέκτη σκουπιδιών, και καθαρίζει ότι έχει μείνει. Επειδή την εντολή θα την δώσουμε μέσα από τμήμα, ενδέχεται κάποια αντικείμενα να μην μπορούν να καθαρίσουν, γιατί υπάρχει στο χώρο μεταβλητών, ή στο σωρό του τμήματος μια αναφορά τους.  Με την επιστροφή από το τμήμα οι αναφορές από το χώρο μεταβλητών θα διαγραφούν (και όπως το έφτιαξα θα διαγραφεί και η τελευταία αναφορά από το συλλέκτη). Και η Καθαρό (Clear) καθαρίζει τον συλλέκτη σκουπιδιών, αλλά εδώ με ένα πέρασμα, όχι με το διπλό όπως η Άδειασε Σκουπίδια (Flush Garbage). Αν γνωρίζουμε ότι κάποιες Καταστάσεις έχουν αναφορές σε άλλες, τότε μπορούμε να δίνουμε το Καθαρό όνομα_κατάστασης και αυτή καθαρίζει με τρόπο όλα τα στοιχεία. Αυτή η εντολή καθαρίζει στοχευμένα τα αντικείμενα, ενώ η Άδειασε Σκουπίδια και η Καθαρό καθαρίζουν τα αντικείμενα, απ΄όποιο τμήμα και αν φτιάχτηκαν. Όπως και να έχει τα "σκουπίδια" καθαρίζονται στο τερματισμό της εφαρμογής, μια φορά από το συλλέκτη σκουπιδιών (και αυτός είναι αντικείμενο).

Βρήκα επίσης και ένα σφάλμα που είχε να κάνει με τους τελεστές και μέσα σε ένα μπλοκ Για Αυτό {} δεν λειτουργούσαν! Διορθώθηκε και αυτό.

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

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

Επίσης έβαλα και ένα κομμάτι στο τέλος που δείχνει κάτι από δείκτες σε ομάδες! Ένας δείκτης μπορεί να δείχνει οποιαδήποτε ομάδα. Άλλαξα την εντολή Group Alpha { } με την Class Alpha { } οπότε αντί να κάνω αυτό μετά m=a(merge_stack,Alpha) να περάσω την ομάδα, κάνω αυτό m=a(merge_stack,Alpha()) δηλαδή καλώ την κλάση να μου φτιάξει μια ομάδα. Εδώ δίνει το τύπο Alpha στην ομάδα. Οι ομάδες, από την 10η έκδοση έχουν τύπους. Η κλάση αν και διαγράφτηκε, δεν μας πειράζει γιατί οι ομάδες έχουν ήδη ότι χρειάζονται δεν εξαρτιόνται από τον ορισμό της κλάσης. Η beta είναι αντίγραφο και επίσης τύπου Alpha. Στην ουσία η beta είναι ένα αντίγραφο της πρώτης Alpha και όχι ένας δείκτης στην πρώτη άλφα. Μπορούμε σε συναρτήσεις να γυρίσουμε δείκτη σε ομάδα. Αντί του = χρησιμοποιούμε το ->. Αλλά υπάρχει το εξής ζήτημα. Αν το επί του δείκτη αντικείμενο είναι επώνυμη ομάδα ή όχι(πχ η beta είναι επώνυμη, ή delta το ίδιο, όμως η αρχική ομάδα δεν "ονομάστηκε" κάπου, δόθηκε σε μια θέση σε σωρό τιμών, είναι δηλαδή πτητική ομάδα). Η διαφορά τους είναι ότι τα επώνυμα ζουν μέχρι να τερματίσει αυτό που τα δημιούργησε, ενώ τα "πτητικά" χάνονται όταν χάνεται και ο τελευταίος δείκτης σε αυτά. Αν πάρουμε δείκτη σε επώνυμη, στην ουσία δεν είναι κανονικός δείκτης αλλά ισχνή αναφορά. Αν πάρουμε δείκτη σε "πτητική" ομάδα τότε θα κρατάμε ζωντανή την ομάδα ακόμα και αν διαγραφεί αυτό που την κρατάει, πχ ένας πίνακας, μια κατάσταση (λίστα κλειδιών/τιμών) ή ένας σωρός τιμών. Όταν δίνουμε το beta στην m=a(change_item, pos_alpha, beta), στην ουσία εξάγουμε μια πτητική ομάδα ως αντίγραφο της beta, και πάει στη θέση item_pos και αυτή που ήταν εκεί θα διαγραφεί (Δεν υπάρχει άλλος δείκτης να την κρατάει).
Στο τέλος με το παράδειγμα με το δείκτη, έχουμε ισχνή αναφορά και όχι πραγματικό δείκτη, αφού του δώσαμε να δείχνει επώνυμες ομάδες. Αν αλλάξουμε λίγο το κώδικα, πχ pointer_to_deltaXX->(delta10) δηλαδή βάλουμε σε παρένθεση το delta10 τότε ο δείκτης θα δείχνει σε ένα αντίγραφο της delta10. Ο τελεστής -> μπορεί να χρησιμοποιηθεί και ως επισροφή δείκτη σε συναρτήσεις, οπότε εκεί θέλουμε επιστροφή αντίγραφου, διαφορετικά η ισχνή αναφορά δεν θα δουλεύει στη πρώτη ζήτηση, διότι θα έχει χαθεί το "επώνυμο" αντικείμενο που δείχνει! Ο τελεστής υπάρχει και στην μορφή Δείκτης() όπου αν θέλουμε αντίγραφο θα δώσουμε και εκεί πρόσθετες παρενθέσεις. Αν όμως έχουμε συνάρτηση κλάσης δεν χρειάζεται γιατί όπως και να έχει η συνάρτηση κλάσης γυρίζει πτητικό αντικείμενο, και ανάλογα που το οδηγούμε ή μένει ως έχει ή δημιουργεί ένα επώνυμο ή συγχωνεύεται με ένα επώνυμο. Χωρίς παράμετρο η Δείκτης() είναι ο τύπος Null. (που είναι και αυτός Ομάδα). Το ->0& είναι επίσης Null ή Μηδενικός (έχει και ελληνικό όνομα, είναι η ομάδα που δεν έχει μέλη, και ούτε μπορεί να πάρει)


α=Δείκτης()
β->0&
Τύπωσε α είναι τύπος Μηδενικός
Τύπωσε β είναι τύπος Μηδενικός
Κλάση ΚάτιΆλλο {
Ζ=100
}


Ομάδα δ {
Τύπος: ΝΑΣΑ
Χ=12345678
}
Τύπωσε δ είναι τύπος ΝΑΣΑ=Αληθές
δ=δ με α ' δεν γίνεται συγχώνευση με μηδενικό τύπο
Τύπωσε δ είναι τύπος Μηδενικός=Ψευδές
α->ΚάτιΆλλο()
Τύπωσε α=>Ζ
δ=α ' εδώ έγινε συγχώνευση με αντίγραφο από το α. ίδιο με το δ=δ με α
Τύπωσε δ.Ζ=100
Τύπωσε δ είναι τύπος ΚάτιΑλλο=Αληθές
Τύπωσε δ είναι τύπος ΝΑΣΑ=Αληθές ' δεν έχααε τον τύπο που ήδη είχε
κ=ομάδα(β) ' δεν δίνουμε το δείκτη αλλά το αντίγραφο του β (αλλά είναι μηδενικός)
Τύπωσε κ είναι τύπος Μηδενικός=Ψευδής ' δεν υπάρχουν εώνυμες ομάδες με μηδενικό τύπο.
Ομάδα κ {
Τύπος: Πρώτος ' μπορώ να δώσω και τύπο!
κλμ=11 ' στην επώνυμη μπορώ να προσθέσω
}
μ=κ
Τύπωσε μ.κλμ, μ είναι τύπος Πρώτος=Αληθές
Λίστα

Δώστε τελευταία εντολή το Λίστα για να δείτε τι υπάρχει ως μεταβλητή.
Ας πούμε ότι το κώδικα τον έχουμε βάλει στο τμήμα Γ με Σ Γ ανοίγουμε το διορθωτή και κάνουμε επικάλληση τον κώδικα. Θα μας δείξει:
Γ.Α*[Group], Γ.Β*[Group],Γ.Δ[Group], Γ.Δ.Χ = 12345678, Γ.Δ.Ζ = 100, Γ.Κ[Group], Γ.Κ.ΚΛΜ = 11, Γ.Μ[Group], Γ.Μ.ΚΛΜ = 11

Δηλαδή θα δείξει ότι έχουμε δυο δείκτες σε ομάδες, τα Α και Β, και τρεις επώνυμε ομάδες, τα Δ, Κ και Μ. Η Α έχει μια μεταβλητή, τη Ζ αλλά δεν φαίνεται γιατί δεν υπάρχει στο σύστημα μεταβλητών. Οι πτητικές ομάδες κρύβουν πραγματικά τα μέλη τους μέχρι να χρησιμοποιηθούν. Οι επωνυμες έχουν μέλη που όχι μόνο έχουν το γράμμα τους, πχ το ΚΛΜ του Κ έχει το Κ πρόθεμα μαζί με το Γ όμως, το οποίο εδώ μας το έχει φτιάξει ο διερμηνευτής γιατί το πραγματικό πρόθεμα πιθανόν δεν θα είναι αυτό! Πριν χρησιμοποιηθεί μια πτητική ομάδα πρέπει να "ονομαστεί" να γίνει δηλαδή επώνυμη πρόσκαιρα, και μετά να γυρίσει στην "πτητική" της κατάταση. Αν υπάρχουν δείκτες στην πτητική ομάδα, δεν την χάνουν την αλλαγή σε επώνυμη, οι δείκτες βρίσκουν ότι έχει γίνει η αλλαγή και την ακολουθούν. Αυτό το ζήτημα προέκυψε γιατί στην ουσία ο διερμηνευτής στη βάση του (εκεί που κάνει πράξεις) δεν ξέρει ότι υπάρχουν μέλη αντικειμένων αλλά μόνο ότι υπάρχουν μεταβλητές! Οι ομάδες ξεκίνησαν σαν λίστες μεταβλητών για να δίνουμε το όνομα της ομάδαςσε κλήση για να περάσουν όλες μαζί ή με τιμή ή με αναφορά. Μετά μπήκανε και οι μέθοδοι (τμήματα και συναρτήσεις), οι τελεστές, οι ιδιότητες (ομάδες που είτε θέτουν εσωτερικά τιμές -ελέγχοντας τον τελεστή εκχώρησης, είτε δίνουν τιμή - τη λεγόμενη Αξία ή και τα δύο), γεγονότα (κλήσεις συνδεμένων συναρτήσεων, άγνωστων στο αντικείμενο), ομάδες μέσα σε ομάδες, δείκτες σε ομάδες, δείκτες σε ομάδες μέσα σε ομάδες, και πολλά άλλα! Δείτε τα βιβλία πάνω στα αντικείμενα της Μ2000.




Clear  \\ clear variables
Flush  \\ empty stack of value
\\ using Stack to process data in Lambda function
a=Lambda st (cmd as stackop) -> {
      \\ Select case need one statement in next line from a Case
      \\ (no second in row allowed), otherwise use { } for any code
      Select Case cmd
      Case 0
            st=Stack
      Case 1 ' is empty
            =Len(st)=0
      Case 2 ' len
            =Len(st)
      Case 3 ' merge To bottom
            {
                  N=[] \\ get current Stack, and leave it empty
                  Stack st {
                         Stack N
                  }
                  =True
            }
      Case 4
            =Stackitem(st, Number) \\ second parameter passing to lambda, read from function stack.
      Case 5
            Stack st {=[] } \\ return a Stack object by swaping  st and an empty one.
      Case 6
            Stack st { Stack } : =True \\ display Stack (current, is st)
      Case 7 '' change item  (we can put one line of code or a block of code only)
            Stack st : Read Where:Shift Where+1 : Drop:Shiftback Where:st=[]
      Case 8
            Stack st {Flush}
      Case 9 ' copy2new
            st=Stack(st)
      Case Else
            =False
      End Select
}
Enum stackop {
      new_stack=0
      is_empty, show_len, merge_stack, show_item
      get_stack, show_stack, change_item, empty_stack
      copy2new
}
m=a(new_stack)
m=a(merge_stack,1,2,3,4,5)
m=a(merge_stack,11,12,13,14,15)
m=a(show_stack)
For i=1 To a(show_len)
      Print a(show_item, i),
Next
Print
For This {
      \\ block for temporary definitions
     Class Alpha {
            x=1, y=2
            Operator "<>" (N) {
                  Push N.x<>.x or N.y<>.y
            }
            Operator "++" {
                  .x++
                  .y++
            }
      }
      m=a(merge_stack,Alpha())
}
pos_alpha=a(show_len)


Print "position of alpha", pos_alpha
beta=a(show_item, pos_alpha)
Print Type$(beta)
Print beta.X, beta.y
beta.x+=100
m=a(change_item, pos_alpha, beta)
For i=9 To a(show_len)
      For this {
            Local N=a(show_item, i)
            Print Type$(N), i
      }
Next
For beta {.x=0 : .y=0}
delta=a(show_item, pos_alpha)
Print Type$(delta)
For delta {
      Print .x, .y
}
a2=a
\\ now [a2] and [a] reference same Stack
m=a2(copy2new)
\\ but not now.
Print a2(show_len), a(show_len)
\\m=a(empty_stack)
\\Print a2(show_len), a(show_len)
m=a(change_item, pos_alpha, beta)


For This {
       \\ block for temporary variables/modules/functions
      delta10=a2(show_item, pos_alpha)
      delta20=a(show_item, pos_alpha)
      Print delta10 is type Alpha ' true
      Print delta20 is type Alpha ' true
      Print delta20 is delta10 ' false
      Print delta20<>delta10 ' true
      \\ Also now work for items in evaluator only
      Print a2(show_item, pos_alpha)<>a(show_item, pos_alpha) ' true
      delta10++
      delta20++
      Print delta10.x, delta10.y
      Print delta20.x, delta20.y
      delta10=delta20
      Print delta20 is delta10 ' false
      Print delta20<>delta10 ' false
      // Pointers to groups (Version 9 and 10)
      pointer_to_deltaXX->delta10
      Print pointer_to_deltaXX is delta10 ' true
      pointer_to_deltaXX->delta20
      Print pointer_to_deltaXX is delta10 ' false
      Print pointer_to_deltaXX <> delta10 ' false
      delta10++
      Print pointer_to_deltaXX <> delta10 ' true
      Print delta20<>delta10 ' true
      pointer_to_deltaXX=>++
      Print pointer_to_deltaXX <> delta10 ' false
      Print delta20<>delta10 ' false
      Print pointer_to_deltaXX is delta20 ' true
}





.
Το δεύτερο λέγεται Funny Loops. Και εδώ έχουμε λάμδα συναρτήσεις, και κάνουμε το εξής: Θέλουμε κώδικας από λάμδα συνάρτηση να τρέξει σε μια άλλη λάμδα συνάρτηση μαζί με μια τρίτη που θα κανονίζει το πόσες φορές θα τρέχει (με αρχική τιμή, τελική και βήμα, το βήμα προαιρετικό). Δεν μιλάμε για απλές επαναλήψεις. Είναι τέσσερις "ειδικές". Στην πρώτη έχουμε μια διακοπή βάσει ενός ορίου (ας το θεωρήσουμε ως γεγονός), και μετά συνέχιση από το σημείο που σταμάτησε, συνεχίζοντας να χρησιμοποιούμε το αντικείμενο επανάληψης (τη λάμδα για τον σκοπό αυτό). Η δεύτερη πάλι με το όριο, το αναπρογραμματίζει σε κάθε εκτέλεση και έτσι κάνει βηματική εκτέλεση. Η τρίτη δεν ενδιαφέρεται για την μεταβλητή που απαριθμεί το αντικείμενο επανάληψης, αλλά έχει μια εσωτερική στατική μεταβλητή και αυτή αλλάζει σε κάθε επανάληψη. Στην τέταρτη περίπτωση έχουμε ένα αντικείμενο που δίνει μια δική του συνάρτηση με αναφορά και σε κάθε χρήση της εσωτερικά στην λάμδα "μηχανή επανάληψης", αλλάζει μια μεταβλητή του αντικειμένου που ανήκει η συνάρτηση. Ταυτόχρονα όπως είναι η δομή While (Ενώ) σε κάθε επανάληψη εκτελείται και το μπλοκ εντός της While (ενώ ο κώδικας που εκτελείται για να βγάλει το τι θα κάνει η While, εκτελεί το κώδικα της συνάρτησης του αντικειμένου). Οπότε σε αυτό το μπλοκ έβαλα να περιστρέφεται ένα αντίγραφο που βγάζει άμεσα ο διερμηνευτής της εικόνας με διαφάνεια στο ματζέντα (5) 100% και μερική διαφάνεια στο υπόλοιπο, και μπορούμε με το ποντίκι καθώς περιστρέφεται να το μετακινήσουμε ενώ το νούμερο από το μετρητή τον βλέπουμε σε μια "μπάρα πλήρωσης" όπου το φωτεινό μέρος θα καλύψει το σκούρο στο 100%.



Clear \\ clear static too
FKey 1, "Cls, 0 : Edit "+module$
FKey 5, module$
Font "Verdana"
Form 70,35
Cls 3
Pen 14
Double
Report 2, "Funny Loops.."
Normal
Cls 5,2
old_italic=Italic
Italic 1
Pen 15 {Report 1, {Look how we can mix proportional font with same font  as monospace font} }
Italic old_italic ' restore italic to old value
\\ iterator
ForEach=lambda (x, x1) -> {
      st=1 \\ this is optional
      read ? st
      =lambda x ,x1, st (&n) -> {
            =true
            if x<=x1 then {
                  n=x : x+=st
            }  else =false
      }
}
\\ execution of a lambda function by iterator
\\ get more parameters, from stack (using call statement)
Lcode=lambda i (&m) -> {
\\ choose to use  a lambda by value
\\ or any function by reference, using islet (is letter)
\\ check head of stack if is string (function references in M2000 are strings)
      If islet then { read &cd() } else read cd
      =false
      if m(&i) then {
            Try ok {
                  call cd(i)
            }
            if not ok then exit
            =true
       }
}
Z=Foreach(60,80,2)
CodeW=lambda (i) -> {
      Let limit=1 \\ this is optional
      Read ? limit
      Print i, limit
      if i>limit then =i ' error
}
\\ print prints with transparent background for fonts
\\ Print Over erase a line before, and set all line one field (temporary)
Print Over "Try iterate code using an iterator and  a secondary limit, if limit break then recalibrate iteration using other data, here other limit"
\\ but Print Over leave one line, so we can fill this line with Print Unter (also change line)
Print Under
\\ Print Over, Print Part and Print Under can be used for making columns with diffrent width
\\ Here is the first loop (empty block)
While Lcode(&z, CodeW,75) {}
n=error
If n>75 then {
      Print "out of scope...recalibrate"
      while Lcode(&z, CodeW,100 ) {}
}
Print Under
Print Over "Example of step by step execution"
Print Under
Z=Foreach(10,15)
n=0
\\ Pen { } change temporary pen to black
\\ using loop we mark block for loop at the end of block execution
\\ Calling a function with Call return error if function return non zero value.
\\ so here we get Error and if is not zero then we do next loop
Pen 0 {
     Print Over ~(0,7,14),$(0,8), "Step"+str$( n+1),@(tab),
     \\ also here we have an empty block
      while Lcode(&z, CodeW,n) {}
      n=error
      if n<>0 then loop
}
\\ here is the lambda with static variable
\\ static variables are per execution object (attached to parent object), no per function (as code)
\\ so if this lambda ...moved to another execution object, passing as parameter
\\ then static i get 1 and start new count.
CodeW=lambda -> {
      Static i=1
      Print Over ~(14,8),$(4,8),"just run, no need iteration number ", i
      i++
}
Z=Foreach(1,5)
Print Over "Simple iteration , using static counter inside code"
\\ Here we have a repeat {} until block
Repeat {Print Under} Until Not Lcode(&Z,Codew)
Print Over "Iteration using group's function, passing by reference, altering group member counter"
Print Under \\ print underline and change line too
Group Alfa {
      counter
     Function M {
            .counter++
      }
}
Z=Foreach(200,499)
y=row
\\ we use a$ for image holder
a$=""
Mouse.icon Hide
Print $("0.00%"),
\\ and here is the "game"
While Lcode(&Z, &Alfa.M()) {
    FeedBack(y, Alfa.counter/300, "  press space to exit early")
    Move 0, 0
    copy scale.x,scale.y to a$
    Move mouse.x, mouse.y
    Sprite A$,, Alfa.counter,40,80 \\ leaving 2nd parameter, to automatic  match the paper color for 100% transparent
    If keypress(32) then exit
    Refresh 5000 \\ rfefresh now and reset counter for next refresh  5 sec later (never happen)
    Sprite Sprite$ \\ when Sprite write, altered background saved to Sprite$, so now sprite erased
    \\ Hold take all screen, and Release restore screen to that we take with Hold. But here we use Sprite Sprite (we have only one)
    Wait 5+Random(1,11-Alfa.counter/30)*2
}
Print
Print $(""),
Print "Counter:";Alfa.counter
Cls ,Row
Mouse.Icon Show
Sub FeedBack(y, val, msg$)
     local N
     Pen 15 {
          Cursor 0, y
          N=round(val*100,0)
          Print Over $(0,8), val, @(tab),$(4), ~(7);string$("[]",50);msg$;@(tab), ~(11),string$("[]", N div 2)+string$("[", N mod 2);
    }
End Sub

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

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