recursion
BlitzPlus Forums/BlitzPlus Beginners Area/recursion| 
 | ||
| Hello World! I am trying to understand recursion. Can anyone please show me how to make this test case work? 
Global csd						; currently selected directory
Global dir$, root$="C:\Program Files\" 			; lets try it on this
Global fileout=WriteFile("C:\log.txt")			; write a log here
ListDir( root$ )					; call the recursive function
CloseFile fileout					; close the log
End
Function ListDir( dir$ )
	WriteLine( fileout, dir$)
	csd=ReadDir(dir$)
	Repeat
		file$=NextFile(csd)
		If 2=FileType(file$) And file$>".."	; a candidate?
			dir$=dir$+"\"+file$		; add to the filepath
			WriteLine( fileout, dir$)	; and record it
			csd=ReadDir(dir$)		; select the new path
			ListDir(dir$)			; and read the contents
		EndIf
		file$=NextFile(csd)
		If 1=FileType(file$) Then
			WriteLine(fileout, file$)	; log any filenames
		EndIf
	Until file$=""
End Function
 | 
| 
 | ||
| In short: recursion is a function calling itself. To prevent infinite loops there's usually a check built-in. A small 'n simple example: rec 10 Notify "done" End Function rec(a,counter=0) If counter>8 Return ; the check counter=counter+1 a=a*2 ; the actual functionality of this function DebugLog "counter = "+counter+", 'a' value = "+a DebugLog "---------------" rec a,counter ; and call it again. End Function | 
| 
 | ||
| ..and ofcourse the famous recursive tree.. or plant.. window=CreateWindow("tree",0,0,640,480)
canvas=CreateCanvas(0,0,640,480,window)
SetBuffer CanvasBuffer(canvas)
	tree 320,240,32,180
FlipCanvas canvas
Repeat
	WaitEvent()
	If EventID()=$803 End
Forever
Function tree(x,y,l#,a,counter=0)
	If counter>10 Return ; toy with the '10'
	counter=counter+1
	
	nx=x+Sin(a)*l
	ny=y+Cos(a)*l
	
	Line x,y,nx,ny
	
	l=l*.9 ; <- to toy with
	tree nx,ny,l,a+20,counter ; toy with both '20' numbers
	tree nx,ny,l,a-20,counter
	
End Function | 
| 
 | ||
| Thank you, CS_TBL, for those examples   :-) Your first example makes the bare-bones machanism clear (excellant!). I really wanted corrections for my routine so as to be able to print the contents of a folder and its sub-folders to a text file. Is my code too messy to bother with? Going up and down directories is what is most confusing to me. Can you help with that? Thank you for your kind attention :-) Julian (-_-) | 
| 
 | ||
| atm no, I'm trying to debug your stuff, but for some odd reason, filetype returns 0 for dirs and files. [edit] arf, classic bug.. FileType(dir$+file$) | 
| 
 | ||
| I've more or less rebuilt the whole shebang, it now outputs a string rather than directly writing to a file. This way it's less hardwired, e.g. you can just view this list now, without having to load it back. Also, all the globals are gone. Globals = evil. The Showtext function is not mandatory, it's just a small self-contained textviewer.. usage: Showtext text$,width,height when omitted, width and height default to 640,480 when either width or height <1 then the viewer is full-screen. 
Showtext ListDir$("i:\")
; mystring$=ListDir$("c:\")
End
Function ListDir$(dir$)
	
	csd=ReadDir(dir$)
	If Not csd Return
	Repeat
		file$=NextFile$(csd)
		If file$="" Exit
		If FileType(dir$+file$)=1
			out$=out$+dir$+file$+Chr$(13)+Chr$(10)
		EndIf
		
		If FileType(dir$+file$)=2 And file$<>".." And file$<>"."
			out$=out$+ListDir$(dir$+file$+"\")
		EndIf
	Forever
	Return out$
End Function
Function Showtext(t$,w=640,h=480)
	cw=ClientWidth(Desktop())
	ch=ClientHeight(Desktop())
	If w<1 Or h<1
		w=cw:h=ch
	EndIf
	If w>cw w=cw
	If h>ch h=ch
	window=CreateWindow("Show text",cw/2-w/2,ch/2-h/2,w,h,0,3)
	textarea=CreateTextArea(0,0,ClientWidth(window),ClientHeight(window),window)
	SetTextAreaColor textarea,128,192,255
	SetTextAreaColor textarea,0,32,64,1	
	SetTextAreaText textarea,t$
	Repeat
		WaitEvent()
		If EventSource()=window
			If EventID()=$803 Exit
			If EventID()=$802
				SetGadgetShape textarea,0,0,ClientWidth(window),ClientHeight(window)
			EndIf
		EndIf
	Forever
	FreeGadget window
End Function
'ave fun *update* Flags added for certain layout thingies. Function ListDir$(dir$,flags=1+4+8+16,d=0)
; flags:
;
; +1  show dir path+name
; +2  show path in filename
; +4  recursive indent
; +8  [] around dirs
; +16 <> around files
	
	csd=ReadDir(dir$)
	If Not csd Return "error"
	Repeat
		file$=NextFile$(csd)
		If file$="" Exit
		; recursive indenting:		
		recindent$=""
		If (flags Shr 2) And 1 recindent$=String$(" ",d*4)
		
		; normal file?
		If FileType(dir$+file$)=1
			out$=out$+recindent$+indent$
			If (flags Shr 4) And 1 out$=out$+"<"
			If (flags Shr 1) And 1 out$=out$+dir$ ; show full path?
			out$=out$+file$
			If (flags Shr 4) And 1 out$=out$+">"
			out$=out$+Chr$(13)+Chr$(10)
		EndIf
		; dir?	
		If FileType(dir$+file$)=2 And file$<>".." And file$<>"."
			If (flags Shr 0) And 1 ; show dir path+name?
				out$=out$+recindent$
				If (flags Shr 3) And 1 out$=out$+"["
				out$=out$+dir$+file$
				If (flags Shr 3) And 1 out$=out$+"]"
				out$=out$+Chr$(13)+Chr$(10)
			EndIf
			out$=out$+ListDir$(dir$+file$+"\",flags,d+1)
		EndIf
	Forever
	
	Return out$
End Function | 
| 
 | ||
| Hi CS_TBL (^_^) That is a spectacular response! Thank you so much :-D Julian (-_-) http://joolian.net/ | 
| 
 | ||
| I am sorry to bother you with this ... I've been trying to make this work but keep getting an error: "Invalid Stream Handle" What am I doing wrong? 
;=============================================================
; First_List - A folders and files lister.
; To produce a file called "First.txt".
; A sister routine, Second_List, will produce "Second.txt".
; First.txt and Second.txt to be compared. 
; Differences to be written to "Third.txt".
;=============================================================
fileout=WriteFile( "First.txt" )
	ListDir$( "C:\Program Files\", 31, 0)
CloseFile(fileout)
End
Function ListDir$(dir$,flags,d)
; flags:
;
; +1	show dir path+name
; +2	show path in filename
; +4	recursive indent
; +8	[] around dirs
; +16 <> around files
	
	csd=ReadDir(dir$)
	If Not csd Return "error"
	Repeat
		file$=NextFile$(csd)
		If file$="" Exit
		; recursive indenting:		
		recindent$=""
		If (flags Shr 2) And 1 recindent$=String$(" ",d*4)
		; normal file?
		If FileType(dir$+file$)=1
			out$=out$+recindent$+indent$
			If (flags Shr 4) And 1 out$=out$+"<"
			If (flags Shr 1) And 1 out$=out$+dir$ ; show full path?
			out$=out$+file$
			If (flags Shr 4) And 1 out$=out$+">"
			out$=out$+Chr$(13)+Chr$(10)
		EndIf
		; dir?	
		If FileType(dir$+file$)=2 And file$<>".." And file$<>"."
			If (flags Shr 0) And 1 ; show dir path+name?
				out$=out$+recindent$
				If (flags Shr 3) And 1 out$=out$+"["
				out$=out$+dir$+file$
				If (flags Shr 3) And 1 out$=out$+"]"
				out$=out$+Chr$(13)+Chr$(10)
			EndIf
			out$=out$+ListDir$(dir$+file$+"\",flags,d+1)
		EndIf
		; record the data in First.txt
		WriteLine(fileout, out$)
	Forever
	Return 0
End Function
 | 
| 
 | ||
| Make the fileout variable a Global (replace 'fileout=WriteFile( "First.txt" )' with 'Global fileout=WriteFile( "First.txt" )'), or pass it to the function through another parameter. | 
| 
 | ||
| Hm, but this defeats the initial idea of having things not being hardwired. If you want to save the result, just save the string you got back from that function. | 
| 
 | ||
| So, why have this writeline thing in that function? It would mean that you can only use this function for one single thing: write the dir content to a file. If you delete this line from that function and return out$ (as I initially had) then this function can be used to create a string, and afterwards you can do two things with it: save it, or show it. This makes such a function way more practical. Actually, when I read your 'description', you intend to compare dir content, why do you need to write to files anyway? Just compare strings. Did I read correctly that you'd have another routine for another text file, doing exactly the same? So, 2 identical functions, just with a different name? | 
| 
 | ||
| And: ListDir$( "C:\Program Files\", 31, 0) Why add ,0 there and wipe it here: Function ListDir$(dir$,flags,d) The ,d parameter is -in this case- only relevant for the function itself (internally), the user doesn't need to know about its existance, and therefor the user also doesn't need to be able to use or change it, so why give this 0 to the user? ? You're making things far more complex than they need to be! |