Πέμπτη, 30 Ιουλίου 2020

Αναθεώρηση 52, Έκδοση 9.9

Μια διόρθωση-επέκταση των μέγεθος.χ() ή size.x() και μέγεθος.υ() ή size.y() τα οποία υπολογίζουν τον πλαίσιο μέσα στο οποίο γράφεται ένα κείμενο με την εντολή Επιγραφή ή Legend.. 


\\ set italic for font
italic 1
font$="Arial"
\\ set 80 characters by 50 rows
Form 80,50
\\ extra_space 5 pixels (to twips)
extra_space=twipsX*5
aling_value=3
document g$={M2000 Interpreter
Second line
Third line
Last line
}
lines=doc.par(g$)-1
if lines=0 then lines=1
\\ start rotation angle
number_of_blocks=9
current_angle=pi/3
font_size=17
distance_from_center=300
For i=1 to number_of_blocks {
      aling_value=random(1, 3)
      current_angle+=pi/number_of_blocks*2
      ep=(extra_space, 0)#val(random(0,1))
      ww=Size.X(g$,font$,font_size,0 ,ep)
      hh=Size.Y(g$,font$,font_size, 0,ep)
      w1=Size.X(g$,font$,font_size, current_angle, ep)
      h1=Size.Y(g$,font$,font_size, current_angle, ep)
      move x.twips/2, y.twips/2
      step angle current_angle,ww+distance_from_center
      select case aling_value
      case 2
            step angle current_angle+pi/2, hh/2-hh/lines/2
      case 3
            {
                   step angle current_angle+pi/2, hh/2
                   step angle current_angle, -ww/2
            }
      else case
            {
                   step angle current_angle+pi/2, hh/2-hh/lines
                   step angle current_angle,ww/2
            }
      end select
      pen random(11, 15) {
            legend g$,font$,font_size,current_angle, aling_value,0,ep
            move x.twips/2, y.twips/2
            step angle current_angle,ww/2+distance_from_center
            step angle current_angle+pi/2, hh/2
            draw angle current_angle, ww
            draw angle current_angle-pi/2, hh
            draw angle current_angle, -ww
            draw angle current_angle-pi/2, -hh
            move x.twips/2, y.twips/2
            step angle current_angle,ww+distance_from_center
            step -w1/2, -h1/2
            color {polygon 1, w1, 0, 0,h1, -w1, 0, 0,- h1 }
      }
}
italic 0
kkk$=key$





\\ θέτουμε Πλάγια την γραμματοσειρά
Πλάγια 1
γραμ$="Arial"
\\ θέτει 80 χαρακτήρες επί 50 γραμμές την κονσόλα
Φόρμα 80,50
\\ εξτρα_κενό 5 σημεία (pixels)
εξτρα_κενό=πλάτος.σημείου*5
τιμή_στοίχισης=3
έγγραφο επ$={Μ2000 Διερμηνευτής
Δεύτερη γραμμή
Τρίτη γραμμή
Τελευταία γραμμή
}
γραμμές=εγγράφου.παρ(επ$)-1
Αν γραμμές=0 Τότε γραμμές=1
αριθμός_μπλοκ=9
τωρινή_γωνία=πι/3
μέγεθος_γραμ=17
απόσταση_από_κέντρο=300
για ι=1 έως αριθμός_μπλοκ {
      τιμή_στοίχισης=τυχαίος(1, 3)
      τωρινή_γωνία+=πι/αριθμός_μπλοκ*2
      εκ=(εξτρα_κενό, 0)#τιμή(τυχαίος(0,1))
      ππ=Μέγεθος.Χ(επ$,γραμ$,μέγεθος_γραμ,0 ,εκ)
      υυ=Μέγεθος.Υ(επ$,γραμ$,μέγεθος_γραμ, 0,εκ)
      π1=Μέγεθος.Χ(επ$,γραμ$,μέγεθος_γραμ, τωρινή_γωνία, εκ)
      υ1=Μέγεθος.Υ(επ$,γραμ$,μέγεθος_γραμ, τωρινή_γωνία, εκ)
      θέση χ.σημεία/2, υ.σημεία/2
      βήμα γωνία τωρινή_γωνία,ππ+απόσταση_από_κέντρο
      επίλεξε με τιμή_στοίχισης
      με 2
            βήμα γωνία τωρινή_γωνία+πι/2, υυ/2-υυ/γραμμές/2
      με 3
            {
                   βήμα γωνία τωρινή_γωνία+πι/2, υυ/2
                   βήμα γωνία τωρινή_γωνία, -ππ/2
            }
      αλλιώς με
            {
                   βήμα γωνία τωρινή_γωνία+πι/2, υυ/2-υυ/γραμμές
                   βήμα γωνία τωρινή_γωνία,ππ/2
            }
      Τέλος επιλογής
      πένα τυχαίος(11, 15) {
            Επιγραφη επ$,γραμ$,μέγεθος_γραμ,τωρινή_γωνία, τιμή_στοίχισης,0,εκ
            θέση χ.σημεία/2, υ.σημεία/2
            βήμα γωνία τωρινή_γωνία,ππ/2+απόσταση_από_κέντρο
            βήμα γωνία τωρινή_γωνία+πι/2, υυ/2
            χαραξε γωνία τωρινή_γωνία, ππ
            χαραξε γωνία τωρινή_γωνία-πι/2, υυ
            χαραξε γωνία τωρινή_γωνία, -ππ
            χαραξε γωνία τωρινή_γωνία-πι/2, -υυ
            θέση χ.σημεία/2, υ.σημεία/2
            βήμα γωνία τωρινή_γωνία,ππ+απόσταση_από_κέντρο
            βήμα -π1/2, -υ1/2
            χρώμα {πολύγωνο 1, π1, 0, 0,υ1, -π1, 0, 0,- υ1 }
      }
}
Πλάγια 0
περίμενε$=κομ$




Δευτέρα, 27 Ιουλίου 2020

Νέο Άρθρο για τον Αντικειμενοστραφή Προγραμματισμό

Ανέβηκε ένα άρθρο 115 σελίδων για τον Αντικειμενοστραφή Προγραμματισμό στη Μ2000. Περιλαμβάνει μια γρήγορη εισαγωγή στην Μ2000, και όλα τα μοτίβα του αντικειμενοστραφή προγραμματισμού με παραδείγματα με ελληνικές εντολές.

Το αρχείο pdf μπορεί να ανοίξει σαν κείμενο στο LibreOffice. Τα προγράμματα μέσα από το LibreOffice μπορούν να αντιγραφούν με τις εσοχές τους.

Αντικειμενοστραφής Προγραμματισμός με τη Μ2000



Τετάρτη, 22 Ιουλίου 2020

Τρίτη, 21 Ιουλίου 2020

A Monad Example (OOP)

See this code (written in a module say Alfa). We want a wrapper Maybe class to hold either a monad of type Nothing or a monad of type Integer. Also we define some functions and operators.

Read comments, while follow the class definitions. This example also make lambda composiitons. Operators for groups (group is the M200 user object type) works on groups. So we want here to make two groups to work through an operator which aren't the same type.  We want a group to act as a lambda function, so we have to wrap a lambda function.



\\ the base class for Monad, we make it like Abstract class return an Error if not implemented
Class Monad {
      Operator "+" {
            Error "Abstract"
      }
      Function ToString$ {
            Error "Abstract"
      }
      Function Just {
            Error "Absract"
      }
}
\\ Nothing from base Monad
\\ we don't have a val variable here
Class Nothing as Monad {
      Function ToString$ {
            ="Nothing"
      }
      Operator "+" {
            drop
      }
      \\ we make the set member to use this
      \\ as singleton
      Set {
            drop
            \\ nothing change nothing;
      }
      \\ Always return the global object
      value {
            ->Nothing
      }
      Function Just {
            Error "Nothing"
      }
}
\\ From now on we use monads as pointers
\\ We want to use Nothing as a global variable
\\ of type pointer to group, and a specific Nothing type group
Global Nothing=Pointer(Nothing())
\\ Integer from Monad, wrapping in a lambda to return pointer
mInteger=Lambda ->{
      Class Integer as Monad {
      Private:
            val
      Public:
            Operator "+" (a as monad) {
                  if a is type Nothing then
                        .val<=Nothing
                  Else
                        .val+=a.val
                  End if
            }
            \\ this function return a lambda
            function just {
                   =lambda x=.val -> {
                        =x
                  }
            }
            Function Add(m as *monad) {
                  if m is type Nothing then =m : exit
                  k->(This) ' get a pointer of a copy of this
                  \\ val is private but not in a member of same type
                  \\ and this includes m which is a pointer to a monad
                  k=>val=.val+m=>val
                  =k
            }
            Function ToString$ {
                  =format$("{0}", .Val)
            }
      Class:
            Module Integer (T as Decimal) {
                  .val<=Int(T)
            }
      }
      \\ passing current stack [] to Integer()
      \\ a cascade pass of a parameter list to another function
      \\ so we pass values to constructor of Integer class
      ->Integer(![])
}
\\ Now we make the Maybe Class, with a val as a Null pointer,
\\ but with a constructor which replace the pointer with a Monad pointer
Class Maybe {
Private:
      val=Pointer()
Public:
      \\ this is the Just function on a Maybe
      \\ this return a pointer from a copy of a This.val
      \\ we don't want to export the pointer of .val
      Function Just {
            ->Group(.val)
      }
      \\ export to string using monad's  ToString$()
      Function ToString$ {
            =.val=>ToString$()
      }
      \\ replace the monad inside
      Module Bind (a as *Monad) {
            .val<=a
      }
      \\ get and return a Maybe type
      Operator "+" (a as Maybe) {
            if a.val is type Nothing then
                  .val<=Nothing
            Else
                    \\ Pointer  need ( ) to get the expression
                  .val<=Pointer((.val + a.val))
            End if
      }
      Operator "^*" (f as λ) {
            if not .val is type Nothing then
                  This<=f.x(.val)
            End if
      }
      \\ return a pointer to a Monad
      Function Add(a as Maybe) {
            if .val is type Nothing then
                  =Nothing
            Else
                  =.val=>Add(a.val)
            End if
      }
Class:
      \\ used once, then excluded from final object
      \\ pass parameter list to This.Bind
      module Maybe {
            .Bind
      }
}
Class λ {
}
Class  λ1 as λ {
      \\ remove right to see what happens
      Operator right "^*"  ( f as λ) {
Rem            Print "Inside ^* λ"
            .x<=lambda a=.x, b=f.x -> {
                  \\ each function return a maybe type
Rem                  print "call me"
                  m=b(![])
                  =a(m.just())
            }
      }
      x = lambda ( T as *Integer ) ->{
            T=Pointer((T + T))
Rem            Print "Call Maybe"
            =Maybe(T)
      }
}
\\ K, L and M are static objects for this module
λ=λ1()
K=Maybe(mInteger(100))
M=Maybe(Nothing)
\\ Remove Rem clause from lines above
\\ Then remove clause "right" from λ operator "^*" so this happen:
\\  L=(K ^* λ) ^* λ so we never call operator "^*" in λ
\\ but using "right" from start we do this
\\  L=K ^* (λ ^* λ)  which (λ ^* λ) combine lambda functions
L=K ^* λ ^* λ
Print L.ToString$()                  '="400"
L=K ^* λ ^* λ ^* λ ^* λ
Print L.ToString$()                  '="1600"
\\ Lets do the same but now with M which is Nothing
L=M ^* λ ^* λ ^* λ ^* λ
Print L.ToString$()                  '="Nothing"
Z=Maybe(Nothing)
\\ L is a Maybe class which now binding a Monad of type Nothing
Z.Bind K.Add(L)
\\ so we get nothing
Print Z.ToString$()                  '="Nothing"
\\ Change binding to L to a Monad of type Integer with value 2000
L.Bind mInteger(2000)
Z.Bind K.Add(L)
Print Z.ToString$()                  '="2100"
\\ creating M1 to point to a copy of Z's monad
M1=Z.Just()
\\ createing F1 as a lambda function which hold a copy of monads value
If not M1 is type Nothing then F1=M1=>Just()
Print F1()=2100
\\ Now M1 points to a copy of L monad
M1=L.Just()
\\ F1() has a closure (as a copy) of value of Z monad
Print F1()=2100
\\ We can replace F1 (is a lambda) with the current monad which M1
If not M1 is type Nothing then F1=M1=>Just()
Print F1()=2000
\\ lets get M1 from M which has Nothing as Monad
M1=M.Just()
\\ Lets try to execute the M1=>just()
Try Ok {F1=M1=>Just()}
If not Ok Then Print Error$
\\ Lets check if we can add nothing monad with an integer monad
Z=L+M
\\ yes we can do and we get Nothing
Print Z.ToString$()                  '="Nothing"
\\ yes we can do at reverse order and we get Nothing
Z=M+L
Print Z.ToString$()                  '="Nothing"
M1=Z.Just()
If not M1 is type Nothing then F1=M1=>Just()


Κυριακή, 19 Ιουλίου 2020

Revision 49, Version 9.9

Revision 49:
A bug from last 2 revisions fixed.

Revision 48:
Now we can use  This with dots to get the opened object in a For object structure.

Here is the version with pointers

class beta {
      x=500000
      module beta {
            Module Check (&z) {
                  Print z.x
            }
            class alfa {
                  x=10
            }
            dim k(10)<<pointer(alfa())
            K(1).x=500
            For K(1), k(3) {
                  Print this.x, .x, ..x
                  Check &.This
                  Check &..This
            }
      }
}
m=beta()
m.beta

Or this version

class beta {
      x=500000
      module beta {
            Module Check (&z) {
                  Print z.x
            }
            class alfa {
                  x=10
            }
            dim k(10)<<pointer(alfa())
            K(1).x=500
            For K(1), k(3), this {
                  Print ...x, .x, ..x
                  Check &.This
                  Check &..This
            }
      }
}
m=beta()
m.beta

And for normal objects (not pointers used, these are just unnamed groups, or float groups)

class beta {
      x=500000
      module beta {
            Module Check (&z) {
                  Print z.x
            }
            class alfa {
                  x=10
            }
            dim k(10)=alfa()
            K(1).x=500
            For K(1), k(3) {
                  Print this.x, .x, ..x
                  Check &.This
                  Check &..This
            }
      }
}
m=beta()
m.beta

And another version

class beta {
      x=500000
      module beta {
            Module Check (&z) {
                  Print z.x
            }
            class alfa {
                  x=10
            }
            dim k(10)=alfa()
            K(1).x=500
            For K(1), k(3), this {
                  Print ...x, .x, ..x
                  Check &.This
                  Check &..This
            }
      }
}
m=beta()
m.beta

And two versions using a module which isn't member of a group (object)

with pointers

module beta {
      x=6000
      Module Check (&z) {
            Print z.x
      }
      class alfa {
            x=10
      }
      dim k(10)<<pointer(alfa())
      K(1).x=500
      For K(1), k(3), this {
            Print ...x, .x, ..x
            Check &.This
            Check &..This
      }
}
beta



and without pointers

module beta {
      X=6000
      Module Check (&z) {
            Print z.x
      }
      class alfa {
            x=10
      }
      dim k(10)=alfa()
      K(1).x=500
      For K(1), k(3), this {
            Print ...x, .x, ..x
            Check &.This
            Check &..This
      }
}
beta




Παρασκευή, 17 Ιουλίου 2020

Finding π

Finding the pi using random point set in a square with a circle inside.










\\ finding π with monte carlo method
\\ Using internal random generator
cls 0, 0
Gradient 1, 5
Double : Report 2, "Finding π" : Normal
dx=(scale.x/3 div twipsX)*twipsX
radius=(scale.x/6 div twipsX)*twipsX
minX=dx
maxX=minX*2
maxY=(scale.y*2/3 div twipsY) *twipsY
minY=maxY-minX
white=#FFFFFF
red=#FF0000
Flush
N=10
MM=3000
profiler
for k=1 to N {
      Refresh 500
      cls 5, -height div 7
      Print format$("Try {0}/{1}", k, N)
      move dx, maxY
      Pen 5 {Polygon 5, dx, 0, 0, -dx, -dx, 0, 0, dx}
      move scale.x/2, minY+radius
      circle fill 15, radius, 1, 15
      countwhite=0 : counttotal=0
      For i=1 to MM {
            move rnd*dx+minX, rnd*dx+minY
            if point=white Then countwhite++ else.if point=red Then continue
            counttotal++ :      pset red
      } : Push 4*countwhite/counttotal
}
Print TimeCount
Refresh 100
N=stack.size
If N=0 then exit
\\ get all data from stack using [] converting stack object to array object using array()
Print  "π=";array([])#sum()/N




Second variation using external random generator


\\ finding π with monte carlo method
\\ Using external random generator: CryptGenRandom from advapi32.dll
Declare CryptAcquireContext Lib "advapi32.CryptAcquireContextW" {Long &hProv, pszContainer$,pszProvider$, long dwProvType, long dwFlags}
Declare CryptReleaseContext Lib "advapi32.CryptReleaseContext" {Long hProv, Long dwFlags}
Declare CryptGenRandom Lib"advapi32.CryptGenRandom" {Long hProv, Long dwLen, Long ByPointer}
Const PROV_RSA_FULL As Long = 1
Const VERIFY_CONTEXT As Long = 0xF0000000&
Long hProv=0
Cls 0, 0
Gradient 1, 5
Double
Report 2, "Finding π"
Normal
dx=(scale.x/3 div twipsX)*twipsX
radius=(scale.x/6 div twipsX)*twipsX
minX=dx
maxX=minX*2
maxY=(scale.y*2/3 div twipsY) *twipsY
minY=maxY-minX
white=#FFFFFF
red=#FF0000
N=20
MM=2000
\\ we need 2 values for MM*N points
buffer clear rdata as integer*MM*N*2
\\  len(rdata) is equal to MM*N*4, because integer is 2 bytes unsigned value
Call void CryptAcquireContext(&hProv, "", "", PROV_RSA_FULL, VERIFY_CONTEXT)
\\ with one call we get all the random numbers
Call Void CryptGenRandom( hProv, len(rdata), rdata(0))
Call Void CryptReleaseContext(hProv, 0&)
group one {
Private:
      \\ a now is a pointer to rdata
      a=rdata, c=0
      d=dx/0x10000
Public:
      value {
            =eval(.a,.c)*.d : .c++
      }
}
\\ flush the current stack
Flush
Profiler
for k=1 to N {
      Refresh 500
      Cls 5, -height div 7
      Print format$("Try {0}/{1}", k, N)
      move dx, maxY
      Pen 5 {Polygon 5, dx, 0, 0, -dx, -dx, 0, 0, dx}
      move scale.x/2, minY+radius
      circle fill 15, radius, 1, 15
      countwhite=0 : counttotal=0
      For i=1 to MM {
            move one+minX, one+minY
            if point=white Then countwhite++ else.if point=red Then continue
            counttotal++ :      pset red
      }
      \\ send result to stack
      Push 4*countwhite/counttotal
}
Print timecount
Refresh 100
N=stack.size
If N=0 then exit
\\ get all data from stack using [] converting stack object to array object using array()
Print  "π=";array([])#sum()/N