option nolet dim verts(1,1), tempverts(1,1), edges(1,1), tempedges(1,1),diddist(1,1) dim templist(1),beenthere(1) dim menuchoices(1), menulabel$(1,1), code$(1,1), oldcode$(1) dim left(1), right(1), bottom(1), top(1), xpix(0:1), ypix(0:1) declare def findvert,find_other_vert declare def distance declare def which_window graphsize=0 graph_win=1 menu_win=2 message_win=3 current_menu=1 dowhat$="move1" digraph$="no" selected=0 call init_windows call init_pics call init_menus !call init_graph Don't do this anymore, replaced it with "graphsize=0" above call update_menu call initperim call initdots !################## Main Loop ############# !call clear_mouse do window #0 get mouse xmouse,ymouse,statmouse if statmouse<>0 then call mouse_click !get point xmouse,ymouse !for mouseless version !call mouse_click !for mouseless version if key input then call key_press loop !################## Handle mouse clicking nonsense ############# sub mouse_click local m the_win=which_window(xmouse,ymouse) select case the_win case 1 ! They clicked in the graph's window window #1 ! The big one to the left call global2local(1,xmouse,ymouse) if findvert(xmouse,ymouse) <> 0 then ! They clicked on a vertex who=findvert(xmouse,ymouse) call clicked_on_vert(who) else ! didn't click on a vertex if dowhat$= "advert2" then call advert(xmouse,ymouse) window #1 call drawverts call drawedges end if end if case 2 ! They clicked in the menu region window #menu_win call global2local(menu_win,xmouse,ymouse) let m=maxchoices-int((ymouse-menuborder)/menuboxheight) if m=0 then current_menu=int(num_menus*(xmouse-menuleft)/menuwidth)+1 ! call message("chose menu "&str$(current_menu),menu_win) dowhat$="move1" call update_menu call clear_mouse exit sub end if ! call message("yup",menu_win) select case current_menu case 1 ! graph building menu select case m case 1 to 5 !move, add/rem vert, add/rem edge when error in dowhat$=code$(current_menu,m) use dowhat$=code$(current_menu,1) !default to move end when case 6 call digraph_toggle case 7 call saveit case 8 call oldn case 9 call nukeall case 10 call quitit case else end select case 2 select case m case 1 to 3 dowhat$=code$(current_menu,m) case 4 call quitit case else end select case else call message("oops",menu_win) end select call update_menu case else end select end sub !############# Text massage to the user, returns to the specified channel after # sub message(msg$,return_to) window #message_win print " "&msg$; !a thin, extended mass of monosodium glutamate ? window #return_to end sub sub quitit set mode "80" stop end sub !############## Handle a click on a vertex in the graph window ################# sub clicked_on_vert(who) select case dowhat$ !find out what we're doing now case "move1" !we're moving things do get mouse xmouse,ymouse,statmouse if statmouse=1 then if xmouse<>oldxmouse or ymouse<>oldymouse then call movert(who) oldxmouse=xmouse oldymouse=ymouse end if end if loop until statmouse=3 or statmouse=0 call movert(who) oldxmouse,oldymouse=0 case "adage4","removedge5" !we're adding or removing an edge if selected=0 then call selekt(who) call clear_mouse else call adage(who) end if case "advert2" !we're adding a vertex window #3 print "can't add a vertex on top of another one" call clear_mouse window #1 case "nukevert3" !we're eliminating a vertex call nukevert(who) case "distance2" if selected=0 then call selekt(who) call clear_mouse else dist=distance(selected,who) call message(str$(dist),menu_win) call selekt(0) end if case else !we don't know what we're doing print "not yet implemented" end select end sub !################## Handle Key Press ####################### sub key_press local a get key a select case a case 17, 272 !ctrl-Q or alt-Q set mode "80" stop case 13, 306 !ctrl-M or alt-M dowhat$="move1" case 22, 303 !ctrl-V or alt-V dowhat$="advert2" case 14, 305 !ctrl-N or alt-N dowhat$="nukevert3" case 5, 274 !ctrl-E or alt-E dowhat$="adage4" case 18, 275 !ctrl-R or alt-R dowhat$="removedge5" case 19, 287 !ctrl-S or alt-S call saveit !(#1,#2,#3) case 15, 280 !ctrl-O or alt-O call oldn !(#1,#2,#3) case else end select call update_menu window #0 end sub !############### initialize the window channels ########################## sub init_windows local i num_windows=3 mat redim left(num_windows),right(num_windows),bottom(num_windows),top(num_windows) mat redim xpix(0:num_windows),ypix(0:num_windows) ask pixels xpix(0),ypix(0) left(1)=1 right(1)=int(.8*xpix(0)-1) bottom(1)=int(ypix(0)/6-1) top(1)=ypix(0)-2 left(2)=right(1)+2 right(2)=xpix(0)-2 bottom(2)=bottom(1) top(2)=top(1) left(3)=left(1) right(3)=right(2) bottom(3)=2 top(3)=bottom(1)-3 window #0 set window 0,xpix(0)-1,0,ypix(0)-1 for i=1 to num_windows open #i:screen left(i)/xpix(0),right(i)/xpix(0),bottom(i)/ypix(0),top(i)/ypix(0) ask pixels xpix(i),ypix(i) set window 0,xpix(i)-1,0,ypix(i)-1 next i for i=0 to num_windows window #i set color "blue" !i+1 box lines 0,xpix(i)-1,0,ypix(i)-1 next i window #graph_win set color "green" !green edges for variety end sub !###################### Initialize menu choices, labels, and codes ##### sub init_menus local i,j num_menus=2 mat redim menuchoices(num_menus) data 10,4 mat read menuchoices for i=1 to num_menus maxchoices=max(maxchoices,menuchoices(i)) next i mat redim menulabel$(num_menus,maxchoices),code$(num_menus,maxchoices),oldcode$(num_menus) ! main menu data move, add vertex,remove vertex,add edge,remove edge,digraph,save graph,retrieve graph,clear graph,quit data move,distance,distance to,quit for i=1 to num_menus for j=1 to menuchoices(i) read menulabel$(i,j) if menulabel$(i,j)="digraph" then digraphi=i digraphj=j end if next j next i data move,advert,nukevert,adage,removedge,digraph_toggle,saveit,oldn,nukeall,togquit data move,distance,disto,quit for i=1 to num_menus for j=1 to menuchoices(i) read code$(i,j) code$(i,j)=code$(i,j)&str$(j) next j next i menuborder=2 menuheight=ypix(menu_win)-2*menuborder menuwidth=xpix(menu_win)-2*menuborder menuboxheight=int(menuheight/(maxchoices+1)) menuboxwidth=menuwidth menuleft=menuborder menuright=menuleft+menuwidth end sub !###################### Redraw Menu ####################### sub update_menu local i,whatitwas,n,m if digraph$="yes" then menulabel$(digraphi,digraphj)="un-digraph" else menulabel$(digraphi,digraphj)="make digraph" end if window #menu_win ask color whatitwas n=len(dowhat$) m=0 i=0 do i=i+1 when error in m=val(dowhat$[i:n]) use end when loop until m>0 box clear 0,xpix(menu_win),0,ypix(menu_win) box lines 0,xpix(menu_win),0,ypix(menu_win) set text justify "center","half" for i=1 to menuchoices(current_menu) box lines (xpix(2)-menuboxwidth)/2,(xpix(2)-menuboxwidth)/2+menuboxwidth,ypix(2)-i*menuboxheight,ypix(2)-(i+1)*menuboxheight plot text, at xpix(2)/2,ypix(2)-(i+.5)*menuboxheight:menulabel$(current_menu,i) next i for i=1 to num_menus if i=current_menu then set color "red" else set color whatitwas plot text, at menuborder+(i-.5)*menuboxwidth/num_menus,ypix(2)-2-.5*menuboxheight:str$(i) next i set color "red" box lines (xpix(2)-menuboxwidth)/2,(xpix(2)-menuboxwidth)/2+menuboxwidth,ypix(2)-m*menuboxheight,ypix(2)-(m+1)*menuboxheight plot text, at xpix(2)/2,ypix(2)-(m+.5)*menuboxheight:menulabel$(current_menu,m) set color whatitwas !select case dowhat$ call clear_mouse end sub !########## find which window the point x,y is in: (x,y) in pixels ####### function which_window(x,y) local i which_window=0 for i=1 to num_windows if left(i)0 then do call nukevert(1) loop until graphsize=0 end if end if window #menu_win call clear_mouse dowhat$=code$(current_menu,1) end sub !################## Select a Vertex ##################! sub selekt(who) selected=who call drawverts end sub !################## Add/Remove Edge ##################! sub adage(who) if who<>selected then if dowhat$="adage4" then edges(selected,who)=1 else !if dowhat$="removedge5" edges(selected,who)=0 call wipedge(selected,who) end if end if call clear_mouse call selekt(0) ! select did this--call drawverts call drawedges end sub !################ Clear windows ############ !sub windex(#1,#2,#3) sub windex ! :) for i=0 to num_windows window #i ask window xmn,xmx,ymn,ymx box clear xmn,xmx,ymn,ymx box lines xmn,xmx,ymn,ymx next i call update_menu window #1 call initdots call drawverts call drawedges end sub !################# Save Config ############## !sub saveit(#1,#2,#3) sub saveit window #3 input prompt "filename? (c to cancel)":savefile$ if lcase$(savefile$)="c" then call clear_mouse window #2 exit sub end if call can_opener(savefile$,"write",#10) print #10:graphsize;",";xpix(graph_win);",";ypix(graph_win) !tell the size of window for portability for i=1 to graphsize print#10: verts(i,1);",";verts(i,2) next i numedges=0 for i=1 to graphsize for j=i to graphsize if edges(i,j)=1 then numedges=numedges+1 print #10: i;",";j else if edges(j,i)=1 then numedges=numedges+1 print #10: j;",";i end if next j next i print#10: numedges;",";0 close #10 call clear_mouse dowhat$="move1" call update_menu end sub !################ Load Saved Config ######### !sub oldn(#1,#2,#3) (If you want it out of main program, you have to ! send the channels sub oldn window #message_win input prompt "Name of old file? ":oldfile$ call can_opener(oldfile$,"read",#10) if more #10 then xsize,ysize=0 when error in input #10: graphsize,xsize,ysize use reset #10: begin input #10: graphsize end when mat redim verts(graphsize,2) for i=1 to graphsize input #10: verts(i,1),verts(i,2) if verts(i,1)<1 then verts(i,1)=verts(i,1)*xpix(graph_win) verts(i,2)=verts(i,2)*ypix(graph_win) else if xsize>0 then verts(i,1)=int(verts(i,1)*xpix(graph_win)/xsize) verts(i,2)=int(verts(i,2)*ypix(graph_win)/xsize) end if next i do while more #10 input #10: numedges,zero !the last pair = numedges,zero loop mat redim edges(graphsize,graphsize) mat edges=0 reset #10: begin if xsize>0 then input #10: null,nuller,nullest else input #10: null end if for i=1 to graphsize input#10:null,waynull !just getting past the info we already have next i for m=1 to numedges input #10:i,j edges(i,j),edges(j,i)=1 next m close #10 end if call clear_mouse dowhat$="move1" call update_menu mat redim diddist(graphsize,graphsize) call windex !(#1,#2,#3) end sub !##################### Initialize Pictures (little dots, that is) ############ sub init_pics ask color whatitwas vertsize=6 halfvertsize=.5*vertsize box clear 0,vertsize,0,vertsize box keep 0,vertsize,0,vertsize in vertwipe$ set color "blue" box area 0,vertsize,0,vertsize box keep 0,vertsize,0,vertsize in vertpic$ set color "red" box area 0,vertsize,0,vertsize box keep 0,vertsize,0,vertsize in redvert$ set color whatitwas clear end sub !################### digraph toggle ########### ! (only affects display at this point, since it is always stored ! directionally) sub digraph_toggle local whatitwas if digraph$="no" then digraph$="yes" else window #graph_win ask color whatitwas set color back call drawedges !sneaky way to erase the arrows set color whatitwas digraph$="no" end if window #graph_win call drawverts call drawedges end sub !#################### Draw the vertices ############### sub drawverts local aye !window #graph_win for aye=1 to graphsize box show vertpic$ at verts(aye,1)-halfvertsize,verts(aye,2)-halfvertsize next aye if selected<>0 and selected <= graphsize then box show redvert$ at verts(selected,1)-halfvertsize,verts(selected,2)-halfvertsize end if end sub !#################### Draw all edges ############### sub drawedges local i,j for i=1 to graphsize for j=1 to graphsize if edges(i,j)=1 then plot lines: verts(i,1),verts(i,2);verts(j,1),verts(j,2) if digraph$="yes" then call draw_arrow((verts(i,1)),(verts(i,2)),(verts(j,1)),(verts(j,2))) end if next j next i end sub !############ add an arrow to existing line ############## sub draw_arrow(x1,y1,x2,y2) local half_width,half_height,xnear,ynear call arrow_width_height(x1,y1,x2,y2,half_width,half_height) xnear=x1+.75*(x2-x1) ynear=y1+.75*(y2-y1) plot xnear+half_width,ynear+half_height; plot xnear-half_width,ynear-half_height; plot x1+.875*(x2-x1),y1+.875*(y2-y1); plot xnear+half_width,ynear+half_height !flood (xnear+x2)/2,(ynear+y2)/2 end sub sub arrow_width_height(x1,y1,x2,y2,half_width,half_height) local slope if (y2-y1)<>0 then slope=-(x2-x1)/(y2-y1) ! half_width=.5*sgn(slope)*sqr(vertsize^2/(1+slope^2)) half_width=.5*sqr(vertsize^2/(1+slope^2)) half_height=slope*half_width else half_width=0 half_height=.5*vertsize end if end sub !##################### Drag a vertex around, updating edges as you go ########## sub movert(who) local i window #graph_win box show vertwipe$ at verts(who,1)-halfvertsize,verts(who,2)-halfvertsize !ask color whatitwas !set color "white" for i=1 to graphsize if edges(who,i)=1 then call wipedge(who,i) if edges(i,who)=1 then call wipedge(i,who) next i if find_other_vert(xmouse,ymouse,who)=0 then verts(who,1)=max(min(xmouse,xpix(1)-vertsize),0+vertsize) verts(who,2)=max(min(ymouse,ypix(1)-vertsize),0+vertsize) end if call drawdots call perimeter call drawverts call drawedges end sub sub initdots local left,right,bottom,top,width,height,xstep,ystep,x,y window #graph_win ask window left,right,bottom,top width=right-left height=top-bottom xstep=int(width/10) !ystep=int(height/10) for x=left to right step xstep plot x,bottom;x,top for y=bottom to top step xstep plot left,y;right,y plot x,y next y next x end sub sub drawdots end sub !################# Erases a drawn edge ############ sub perimeter !window #graph_win perim=0 mat diddist=0 for i=1 to graphsize for j=1 to graphsize if (edges(i,j)=1 or edges(j,i)=1) and diddist(i,j)=0 then perim=perim+round(.01*sqr((verts(i,1)-verts(j,1))^2+(verts(i,2)-verts(j,2))^2),3) diddist(i,j),diddist(j,i)=1 end if next j next i box clear perileft,periright,peribottom,peritop box lines perileft-1,periright+1,peribottom-1,peritop+1 set text justify "center","half" plot text, at perix,periy: str$(perim) end sub sub initperim perileft=5 periright=100 peribottom=200 peritop=220 perix=(periright+perileft)/2 periy=(peritop+peribottom)/2 end sub sub wipedge(a,b) local whatitwas ! window #graph_win ask color whatitwas set color back plot lines: verts(a,1),verts(a,2);verts(b,1),verts(b,2) if digraph$="yes" then call draw_arrow((verts(a,1)),(verts(a,2)),(verts(b,1)),(verts(b,2))) set color whatitwas end sub !################# Erases a drawn vertex ############ sub wipevert(who) window #graph_win box show vertwipe$ at verts(who,1)-halfvertsize,verts(who,2)-halfvertsize end sub !################## Function--sees if mouse is on a vertex or not #################### function findvert(xmouse,ymouse) local I findvert=0 for i=1 to graphsize if verts(i,1)<=(xmouse+halfvertsize) and verts(i,2)<=(ymouse+halfvertsize) and xmouse<=verts(i,1)+halfvertsize and ymouse<=verts(i,2)+halfvertsize then findvert=i end if next i end function !################## Function--sees if pair of points is within a vertex other than the given one#################### function find_other_vert(x,y,given_vert) local i,ex,why find_other_vert=0 ex=max(min(x,xpix(1)-vertsize),0+vertsize) why=max(min(y,ypix(1)-vertsize),0+vertsize) for i=1 to graphsize if verts(i,1)<=(ex+3*halfvertsize) and verts(i,2)<=(why+3*halfvertsize) and ex<=verts(i,1)+3*halfvertsize and why<=verts(i,2)+3*halfvertsize then if i<>given_vert then find_other_vert=i end if next i end function !################ Do nothing until mouse button is released ########## sub clear_mouse do get mouse x,y,s loop until s=0 or s=3 end sub !################ Find the distance from vert1 to vert2 ########## function distance(vert1,vert2) local done,dist,which,whichwas,begindex,endex if graphsize<>savedgraphsize then mat redim templist(graphsize),beenthere(graphsize) !put that in advert? mat beenthere=0 dist=0 ! in order to be able to write dist=dist+1, since on the right it would be a a function which=1 whichwas=1 beenthere(vert1)=1 templist(which)=vert1 !howmany=1 done=0 if vert1=vert2 then done=1 endex=0 do until done=1 begindex=endex+1 !from last time endex=begindex+which-whichwas whichwas=which for i=begindex to endex for j=1 to graphsize if beenthere(j)=0 then !fix this for digraph if edges(templist(i),j)=1 or edges(j,templist(i))=1 then which=which+1 templist(which)=j beenthere(j)=1 if j=vert2 then done=1 end if end if next j next i dist=dist+1 if which=whichwas then dist=-1 ! there's no path between the vertices done=1 end if loop savedgraphsize=graphsize distance=dist end function end !################ End of main program ############### !#################### Generic File Opener #################### sub can_opener (filename$,reedwright$,#1) do when error in close #1 open #1: name filename$, org "text", create newold exit do use Input prompt filename$&" can't be opened (not a text file?). Please enter another filename.":filename$ end when loop if more #1 then if reedwright$="write" then print "File ";filename$;" exists. Type" print "1 to select another file" print "2 to append to the end of this file" print "3 to overwrite this file" do when error in get key choice let choice=val(chr$(choice)) if choice=1 or choice=2 or choice=3 then exit do else print"please enter 1 (select another), 2 (append), or 3 (overwrite)." end if use print "Please type a 1, 2, or 3" end when loop select case choice case 1 input prompt "Please input desired filename. ":filename$ call can_opener (filename$,reedwright$,#1) exit sub case 2 reset #1:end exit sub case 3 input prompt "Are you sure you want to write over the data in "&filename$&"(y/n)?":yesno$ if lcase$(yesno$[1:1])<>"y" then call can_opener(filename$,reedwright$,#1) exit sub else erase #1 end if case else print "error--please report to mike" ! print ! print"please enter 1 (select another), 2 (append), or 3 (overwrite)." ! let tryagain=1 end select ! loop until tryagain=0 end if end if end sub !public verts(1,1),tempverts(1,1),edges(1,1),tempedges(1,1),graphsize,xmouse,ymouse !public firstvert,vertpic$,redvert$,vertwipe$,vertsize,halfvertsize,dowhat$ !public menuchoices,menulabel$(6) ! !public left(1),right(1),bottom(1),top(1),xpix(0:1),ypix(0:1) !public verts(1,1),tempverts(1,1),edges(1,1),tempedges(1,1),graphsize !public firstvert,vertpic$,redvert$,vertwipe$,vertsize,halfvertsize,dowhat$ !public menuchoices(),menulabel$(1,1),code$(1,1),oldcode$(1) !public left(1),right(1),bottom(1),top(1),xpix(0:1),ypix(0:1) !public graph_win,menu_win,message_win,current_menu,maxchoices,num_menus !hell? no (line 667, tday+1, 1995)