Recursion is your friend

This started out as a series of Advent challenges a couple of Christmases ago, but is now open for anyone to post challenges on any topic!
DDRM

Recursion is your friend

Post by DDRM »

Can you draw something using these rules:
a) Starting from a central point, draw a line of length L = 243 in each of 6 equally spaced directions (like spokes on a wheel).
b) At the end of each spoke, repeat the process, but using a line length of L/3
c) Repeat step b until the length drops to 1, or for a controlled number of generations

Hint: write a subroutine that calls itself recursively. Don’t try to do it in the order suggested above (i.e. don’t draw all the first-level spokes, then the second level ones, etc).

Extensions: can you generalise the routine to handle different numbers of branches, different ratios between the lengths, different numbers of generations? Can you make it scale gracefully to whatever mode you choose? Can you add colour, and maybe changing line thicknesses? What happens if you plot circles of the given radius instead of lines? What happens if you allow lines to get LONGER with each generation

Comment: This is heading towards some programs I did to generate biomorphs, similar to those described by Richard Dawkins in his book “the blind watchmaker”. I allowed lengths to change by different ratios in horizontal and vertical directions, and allowed the angle between branches to change (at a controllable rate) between generations. It’s amazing what a variety of shapes you can generate that way.
DDRM

Re: Recursion is your friend

Post by DDRM »

Let it snow!

Here's my version. Feel free to play with the parameters for the number of branches, generations, etc! The ldivisor parameter determines how fast the branches shorten - changing it to 2 will mean each successive generation of branches will be half the previous one, for example.

If you want the "minimal" version, uncomment the second version of PROCDraw (and comment out the first one), and uncomment the line forcing the length to 243.

Code: Select all

      MODE 23
      ORIGIN 1024,768
      px=0
      py=0
      branches%=6
      gens%=5
      ldivisor=3
      totallength=1
      FOR x%=1 TO gens%-1
        totallength+=(1/ldivisor)^x%
      NEXT x%
      length=INT(768/totallength)
      REM length=243
      PROCDraw(px,py,length,gens%,ldivisor,branches%,360/branches%)
      REMPROCDraw(px,py,length,gens%)
      END
      :
      :
      DEFPROCDraw(px,py,l%,gen%,ldiv,branches%,da)
      LOCAL x%,nx,ny
      IF gen% = 0 THEN ENDPROC
      FOR  x%=0 TO (branches%-1)
        VDU 23,23,3*(gen%-1)+1;0;0;0;
        GCOL gen%
        nx=px+l%*COSRAD(x%*da)
        ny=py+l%*SINRAD(x%*da)
        LINE px,py,nx,ny
        REM CIRCLE px,py,l%
        PROCDraw(nx,ny,l%/ldiv,gen%-1,ldiv,branches%,da)
      NEXT x%
      ENDPROC
      :
      REM DEFPROCDraw(px,py,l%,gen%)
      REM REM Simple version: assumes 6-fold symmetry and divide length by 3
      REM LOCAL x%,nx,ny
      REM IF gen% = 0 THEN ENDPROC
      REM FOR  x%=0 TO 5
      REM nx=px+l%*COSRAD(x%*60)
      REM ny=py+l%*SINRAD(x%*60)
      REM LINE px,py,nx,ny
      REM PROCDraw(nx,ny,l%/3,gen%-1)
      REM NEXT x%
      REM ENDPROC
Pete
Posts: 96
Joined: Wed 10 Apr 2019, 17:36

Re: Recursion is your friend

Post by Pete »

That was good to see the computer draw that. Initially I encountered the error "Invalid arguments" as I hadn't REMed out the first PROCdraw in the program. I learnt a bit more about recursion tonight when I looked up "what is recursion?". Wikipedia said: "Recursion occurs when a thing is defined in terms of itself or of its type. Recursion is used in a variety of disciplines ranging from linguistics to logic. The most common application of recursion is in mathematics and computer science, where a function being defined is applied within its own definition." Will be interesting to see the biomorph programs.
Hated Moron

Re: Recursion is your friend

Post by Hated Moron »

Pete wrote: Sun 12 Dec 2021, 19:03 Wikipedia said: "Recursion occurs when a thing is defined in terms of itself or of its type..."
I'm surprised it didn't say: "Recursion: see Recursion". :lol:
Hated Moron

Re: Recursion is your friend

Post by Hated Moron »

Pete wrote: Sun 12 Dec 2021, 19:03 Will be interesting to see the biomorph programs.
From the April 1987 edition of The Micro User magazine (via mdfs.net):

Code: Select all

  100 REM > Biomorphs 1.02
  110 REM  by Mike Cook
  120 REM (c) Micro User
  125 REM Tweaked by JGH
  130 MODE1
  140 DIM morph(5,12),parent(5)
  150 DIM gi(5,2),px(12),py(12)
  160 REM READ IN INCREMENTS AND LIMITS (MIN & MAX) OF EACH GENE
  170 RESTORE 200
  180 FOR A%=0 TO 2:FOR B%=0 TO 5
  190     READ gi(B%,A%):NEXT:NEXT
  200 DATA 1,4,0.16,0.2,0.16,2       :REM GENE INCREMENTS
  210 DATA 1,-36,-3.14,0.1,-3.14,-18 :REM GENE MIN
  220 DATA 9,36,3.14,10,3.14,18      :REM GENE MAX
  225 ON ERROR:REPORT:IFERR<>17:PRINT" at line ";ERL:A%=GET
  226 MODE1
  230 PROC_INTPOS :REM INITIALISE DISPLAY POSITION
  240 PROC_INTP   :REM INITIALISE PARENT
  250 gen=0
  260 MODE 0
  270 REPEAT
  280   gen=gen+1
  290   PROC_MUTATE
  300   PROC_DISPLAY
  310   PROC_CHOSE
  320 UNTIL FALSE
  330 DEF PROC_INTP
  340 IF A$="C" THEN ENDPROC
  350 parent(0)=1
  360 parent(1)=4
  370 parent(2)=.785
  380 parent(3)=1
  390 parent(4)=0
  400 parent(5)=0
  410 IF A$="A" THEN ENDPROC
  420 FOR A%=0 TO 5
  430   parent(A%)=(RND(5)+1)*gi(A%,0)
  440 NEXT
  450 parent(0)=RND(3)+1
  460 ENDPROC
  470 DEF PROC_MUTATE
  480 FOR B%=1 TO 12
  490   FOR A%=0 TO 5
  500     morph(A%,B%)=parent(A%)
  510     IF (B%MOD2) D%=-1 ELSE D%=1
  520     C%=(B%-1)DIV2
  530     IF C%<>A% THEN 560
  540     IF morph(A%,B%)+D%*(gi(A%,0))<gi(A%,1) OR morph(A%,B%)+D%*(gi(A%,0))>gi(A%,2) THEN 560
  550     morph(A%,B%)=morph(A%,B%)+D%*(gi(A%,0))
  560   NEXT:NEXT:ENDPROC
  570 DEF PROC_DISPLAY
  580 PROC_LINES
  590 PROC_TREE(parent(0),parent(1),parent(2),parent(3),parent(4),parent(5),640,500)
  600 FOR A%=1 TO 12
  610   PROC_TREE(morph(0,A%),morph(1,A%),morph(2,A%),morph(3,A%),morph(4,A%),morph(5,A%),px(A%),py(A%))
  620 NEXT:ENDPROC
  630 DEF PROC_INTPOS
  640 RESTORE 840
  650 FOR A=1 TO 12
  660   READ px(A),py(A):NEXT
  670 PRINT'SPC13;"Biomorph"
  680 PRINT"An exercise in Darwinian Evolution"
  690 PRINTSPC11;"By Mike Cook"
  700 PRINT'"Based on an idea by Richard Dawkins"
  710 PRINTSPC2"Author of THE BLIND WATCHMAKER"
  720 PRINT''"Options to start evolving from:"'
  730 PRINT"A - A microbe."
  740 PRINT"B - Some random point."
  750 PRINT"C - A defined point."
  755 PRINT"Q - Quit."
  760 PRINT'"Press the key of your choice:";:*FX15
  770 A$=CHR$(GET AND &DF):IFINSTR("ABCQ",A$)=0 THEN 770
  775 PRINTA$:IF A$="Q":END
  780 PRINT:IF A$<>"C" ENDPROC
  790 FOR A%=0 TO 5
  800   PRINT"Gene number ";A%;" (";INT(gi(A%,1)/gi(A%,0));" to ";INT(gi(A%,2)/gi(A%,0));")";
  810   INPUT ": "parent(A%):parent(A%)=parent(A%)*gi(A%,0)
  820   IF parent(A%)<INT(gi(A%,1)/gi(A%,0)) OR parent(A%)>INT(gi(A%,2)/gi(A%,0)):GOTO 800
  830 NEXT:ENDPROC
  840 DATA 160,860,480,860,800,860,1120,860,160,604,1120,604,160,348,1120,348
  850 DATA 160,92,480,92,800,92,1120,92
  860 DEF PROC_LINES
  870 VDU 12,23,1,0;0;0;0;5
  880 PRINT
  890 FOR X%=320 TO 960 STEP 320
  900   FOR Y%=256 TO 800 STEP 256
  910     MOVE X%,0:DRAW X%,1023
  920     MOVE 0,Y%:DRAW 1259,Y%
  930   NEXT:NEXT
  940 MOVE 640,260:PLOT 7,640,764
  950 MOVE 324,512:PLOT 7,958,512
  960 FOR A%=1 TO 12
  970   MOVE px(A%)-150,py(A%)-60
  980   VDU&40+A%:NEXT
  990 MOVE 536,338+16
 1000 PRINT"PARENT BIOMORPH"
 1010 MOVE 504,755
 1020 PRINT"GENERATION NUMBER ";gen
 1030 VDU4:ENDPROC
 1040 DEF PROC_CHOSE
 1042 VDU5:MOVE 368,322
 1045 FOR A%=0 TO 5:PRINT;A%;":";LEFT$(STR$INT(parent(A%)/gi(A%,0))+"   ",5);:NEXT
 1050 MOVE 336,290
 1060 PRINT"A-L: Breed from child, R: Random child":*FX15
 1070 A$=GET$
 1080 C%=(ASC(A$)AND&DF)-&40:IF C%=18:C%=RND(12)
 1090 IF C%<1 OR C%>12 PROC_REVIEW:ENDPROC
 1100 FOR A%=0 TO 5
 1110   parent(A%)=morph(A%,C%)
 1120 NEXT:VDU4:ENDPROC
 1130 DEF PROC_REVIEW
 1140 VDU22,1
 1150 PRINT''"Current Biomorph has:"
 1160 FOR A%=0 TO 5
 1170   PRINT"GENE ";A%" VALUE ";INT(parent(A%)/gi(A%,0))
 1180 NEXT
 1190 PROC_TREE(parent(0),parent(1),parent(2),parent(3),parent(4),parent(5),640,300):*FX15
 1200 PRINTTAB(0,30);"Press any key to continue";
 1210 A$=GET$:gen=gen-1:VDU22,0
 1220 ENDPROC
 1230 DEF PROC_TREE(D,L,dA,AR,DT,DS,X,Y)
 1240 MOVE X,Y:DRAW X,Y-L
 1250 PROC_GROW(PI/2,L,X,Y,D)
 1260 ENDPROC
 1270 DEF PROC_GROW(TH,L,X,Y,D)
 1280 IF D MOVE X,Y ELSE ENDPROC
 1290 dX=L*COS(TH+dA)*(1/AR)
 1300 dY=L*SIN(TH+dA)*AR
 1310 PLOT 1,dX,dY
 1320 PROC_GROW(TH+dA+DT,L-DS,X+dX,Y+dY,D-1)
 1330 MOVE X,Y
 1340 dX=L*COS(TH-dA)*(1/AR)
 1350 dY=L*SIN(TH-dA)*AR
 1360 PLOT 1,dX,dY:MOVE X,Y
 1370 PROC_GROW(TH-dA-DT,L-DS,X+dX,Y+dY,D-1)
 1380 ENDPROC