Rosetta Sugar. J’apprends à coder AVEC mon CPC.

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
  • Expressiveness
  • Debugging
  • 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]

-- 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 '-------------------
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).


2 thoughts on “Rosetta Sugar. J’apprends à coder AVEC mon CPC.

Comments are closed.