By Madram / Overlanders.
Here begins a serie of articles dedicated to programming languages, already existing on the CPC (BCPL, Forth, Turbo Pascal, …) or good candidates for ports on the CPC (Smalltalk, Lua, J, …). I don’t plan to investigate BASIC compilers since I find BASIC unattractive. My CuPidCoder standards are pretty high.
Several criteria will be evaluated totally unscientifically (don’t forget my taste has been refined by decades of procrastination). Such as:
- Speed of coding
- Speed of execution
- Integrated help and usefulness of error message (how far we can go without any doc)
- Discovery with minimal doc
- Expanding (calling asm from language)
- Embedding (calling language from asm)
- Or at least, interaction possibilities (e.g. sharing memory, both language and asm would be called from a third glue langage)
Some concrete topics worth investigating:
- Data structures.
- E.g. list with append and iterator.
- 3d mapping (deal with bitmap and computation, some of the favorite subjects for a demomaker. Hopefully. If too slow: still useful for pre-computation.
- Can we easily switch between precise vs fast. I.e. same code, different types.
- 10 lines.
- An impressive thing to do in the language in the less lines possible.
- Advent of code!
With the rigor that characterizes French people in my building, let’s start with something else almost entirely: "Torus defined by some of its surface points, aka John Dot Donut". We’ll obtain the coordinates by rotating points of an initial circle (revolution object). There are most astute ways to generate a dotted torus. The goal here is to exercise several principles, and make fun of the Polish. Also, the 3D rotation and projection are reusable for arbitrary objects.
-- Display dot-donut in pseudo-code (idealized language) -- Hopefully, this is self-explaining. Otherwise, let me know. -- Main parameters to play with. r, r' = 100, 20 -- Major and minor radius dist = 200 -- Distance from observator. Should be greater than major radius zoom = 100 nbdots = 20 -- # of dots in each circle nbcircles = 40 -- # of circles -- Rotation matrice around x axis rotx a = [[1 0 0] [0 c -s] [0 s c]] where c, s = cos a, sin a -- Rotation matrice around y axis roty a = [[c 0 -s] [0 1 0] [s 0 c]] where c, s = cos a, sin a -- Rotation matrice around z axis rotz a = [[c -s 0] [s c 0] [0 0 1]] where c, s = cos a, sin a -- Multiplication of matrices (m rows n cols) * (n rows p cols) A:Mat(m, n) * B:Mat(n, p) = [[ sum (A(i j)*B(j k) for j in range 0 n) for k in range 0 p] for i range 0] -- Abstract the encoding of position (x y z). -- Here, we choose column vector convention. data dot x y z = [[x] [y] [z]] -- 3d to 2d proj x y z = (x/z' y/z') * zoom where z' = z + dist -- List of regularly spaced dots -- from a circle of radius r' at distance x = r in the plane XOY. circle = [dot (cos a)*r'+r (sin a)*r' 0 for a in range 0 tau tau/nbdots] -- Now the torus is a surface of revolution. torus = [roty a * dot for a in range 0 tau tau/nbcircles for dot in circle] -- Let's tilt it. torus' = [rotx 0.5 * rotz 0.7 * dot for dot in torus] -- Display plot [proj x y z for dot x y z in torus']
For a language to be as expressive as this pseudo-code, it requires:
- Literal array definition (granted by all but Locomotive BASIC)
- Let/Where scoping
- List comprehension
- Easy 2d array handling
- Pattern matching (to extract the components of a structure as simply as creating the structure)
A note on the 3d:
setting a shorter distance will exaggerate the perspective.
On the contrary, if both the distance and zoom are great, the z coordinate won’t influence much.
That allows to test parallel-like projection rather than central one.
Yet a simpler way to test that is to replace the projection function
proj x y z = (x y).
That’s another hallmark of a good language: is it easy to change just one component!
As a reference point, you may see below a BASIC version (not quite a literal translation of the pseudocode). C’est pas une locomotive. 42 seconds for 31*16 dots (download).
5 ' Display torus dots 6 '------------------- 7 CLS 8 tic = TIME 10 r1=100:r2=20:dist=210:zoom=250:tiltx=-0.5 20 nb1=31:nb2=16 30 DIM circle(nb2,2):DIM torus(nb1,nb2,3) 40 tau=2*PI 50 ' Rotation coordinate 1, given c=cos(a) and s=sin(a) 60 DEF FN rot1(a,b)=a*c-b*s 70 ' Rotation coordinate 2 80 DEF FN rot2(a,b)=a*s+b*c 100 ' One circle 105 '----------- 110 FOR i%=0 TO nb2-1 115 a = i%*tau/nb2 120 circle(i%,0) = r1+COS(a)*r2 130 circle(i%,1) = SIN(a)*r2 150 NEXT 200 ' Zo torus 202 '--------- 205 LOCATE 1,1:PRINT"Make Torus:" 210 FOR j%=0 TO nb1-1 215 a=j%/nb1*tau 220 LOCATE 12,1:PRINT CINT((j%+1)/nb1*100);"%" 230 c = COS(a) 240 s = SIN(a) 250 FOR i%=0 TO nb2-1 260 x = circle(i%,0) 270 y = circle(i%,1) 300 torus(j%,i%,0)=x*c 310 torus(j%,i%,1)=y 320 torus(j%,i%,2)=x*s 330 NEXT 340 NEXT 400 ' Tilt around x axis 402 '------------------- 405 LOCATE 1,2:PRINT"Tilt Torus:" 407 c=COS(tiltx) 408 s=SIN(tiltx) 410 FOR j%=0 TO nb1-1 420 LOCATE 12,2:PRINT CINT((j%+1)/nb1*100);"%" 450 FOR i%=0 TO nb2-1 460 x = torus(j%,i%,0) 470 y = torus(j%,i%,1) 480 z = torus(j%,i%,2) 500 torus(j%,i%,0)=x 510 torus(j%,i%,1)=FN rot1(y,z) 520 torus(j%,i%,2)=FN rot2(y,z) 530 NEXT 540 NEXT 700 ' Display 702 '-------- 710 ORIGIN 320,200 720 FOR j%=0 TO nb1-1 730 FOR i%=0 TO nb2-1 740 x = torus(j%,i%,0) 750 y = torus(j%,i%,1) 760 z = torus(j%,i%,2) 770 xp = x/(dist+z)*zoom 780 yp = y/(dist+z)*zoom 790 PLOT xp,yp 800 NEXT 810 NEXT 900 ' timing 910 '------- 920 toc=TIME 925 LOCATE 1,3 930 PRINT"Done in:";(toc-tic)/300;"seconds"
Here ends the serie of articles. It has been a good ride! As Einstein said once, “Life is short, yet one minute of mountain climbers is long.” (Giuseppe, not Albert).