Random numbers
July 20, 1998
by Alan Levine
The DOUG boys granted me this public space on DOUG, without a whole lot of instruction. They still asked after I told 'em that I hated the red color and my own bias against web pages that employ pictures of text.
Without a grand thematic plan, this column will touch on Lingo, Shockwave, HTML (dynamic and un-dynamic), Director related web sites, cgi, ranting at Macromedia, praising Macromedia... essentially what randomly flies on my radar screen.
Regardless of the topic, eventually I'll get around to writing something useful, be it a scrap of Lingo code, a reference web site, or some other tidbit. If this isn't useful, then click away or send me some flame-mail.
So for random(alan) = 1, I'll zip through some banal introductory blather, and then jump off the soapbox and show some ways I've used random() in Lingo.
Coming next, I'll cover some of the ins and outs of shockwave and CGI.
"I'm Not a Director Expert, But I Play one on the Web..."
I'VE YET TO FIGURE OUT how people think I'm some sort of Director guru; someone who I met last year had a boss who thought I invented Director! (sorry Marc! Sorry JT! I never claimed so...) Laughable, eh? It just goes to show the incredible and distorted magnification of what happens on the web.
All I've done is to package a bunch of resources, many of it from Direct-L into Director Web. It's a typical thing I do in my job as an instructional technologist at the Maricopa Community Colleges, in Phoenix, Arizona. I do some multimedia production, but my main role is exploring new technologies for education and helping our faculty find resources they can use.
In '93, I plucked the Director 3 box off the shelf for a new Study Skills project that called for more animation that was reasonable to do in HyperCard. I'd been using listservs since the late 80's and figured there was likely one devoted to Director.
Ahhhh, the glory days of Direct-L. It was a civil and chock full of fantastically useful tips. I learned so much by asking, reading, and earning my own flame-scarred tissue. I began pulling resources off the 'net, starting with the original sharedcast ftp site set up by Marvyn Hortmann, then at Houston Community Colleges. I compiled them, among other resources, on a public file server for folks in our college district.
Later that fall, I was slightly distracted when a colleague handed my a floppy disc labeled "Mosaic". In a week I came across an early version of MacHTTP, and opened our first web server (running on a Mac SE/30!). It seemed natural, to put up a "Director Page", which we meekly announced in the summer of '94 (<EGO>quite some time before Macromedia got around to it!!!</EGO>) To take a stroll back in time, see our DirWeb Scrapbook.
Over time, we've cobbled on more and more pieces, using it as a learning process for myself and a clever student that wrote some perl scripts, to have searchable collections of demos and x-objects. In '95 I started wondering of there was someway to have our server (now a speedy Alpha) sign up as a Direct-L subscriber, in digest mode. Of course! It was easy! We wrote some server scripts that on a daily basis would check the inbox, and move any digests that arrived to a directory on our web server. We hooked in some other scripts to make it searchable, and voilá! the Direct-L Digest.
And now I publicly admit that this entire system was created for my own convenience, so that I do not have to get mail from Direct-L and I can merely bookmark the daily digest file.
In August of '95, I had a business trip to San Jose, and wrote the kindly John Dowdell to see if I could visit 600 Townsend Street. This little visit (beyond getting a free lunch) introduced me to Harry Chesley, who was nice enough to put me on the Shockwave beta group. So over the next months, I was merrily frying green director files, now brewing at my whimsical No Java Shop.
I relished the challenges of the original Shockwave design; to do it well (meaning small file sizes) called for an entirely different design approach, and new bags of tricks. I owe Steve Bullock for telling me how to chop a few precious k by importing a blank FontMap.txt file before Afterburning. Hey, when you were waiting for that plug-in to load, dropping 4 or 5 k meant a lot!
Even today when you can stream shockwave content in Director 6, there is still a benefit of thinking lean in terms of file sizes. I still have little patience to watch the Macromedia logo while a 200k shockwave loads-- there's little excuse not to shape your content so that it loads while the viewer (that's me, with the itchy finger poised above the mouse button) is doing something else.
BUT NOW I'VE ALREADY STARTED to wander off topic. Here it is in December 1997, and I am a bit behind the curve in ramping up to Director 6. Mark that down for a future column; deciding whether your bike racing strategy is blasting the front edge of the wind, or drafting the leaders until they reveal the potholes in the road that you can avoid.
And what about the nightmare of creating web content given 4 generation of 2+ brands of browsers running on ?? operating systems... Hello, world wide web! It's NOT A STANDARD ANYMORE. Another future topic.
And when will I start behaving? Not in the sense of etiquette but of taking advantage of Director 6 behaviors. Sure it sounds cool just to tap into someone else's canned code for some functionality, but is it overkill for just a freakin' button? Stay tuned...
"Enough BS, Already! How About Some Code?"
ALLRIGHT, ALRIGHT, BUT FIRST LET ME talk a bit about code. I love creative lingo. I'm still on the learning cliff. I'm not deeply steeped into proper OOP theory and my head gets light when I hear all this jabber about "swapping inheritance" and "object class managers."I love writing Lingo. given a certain task, there always seems about 90 ways to write the code. Some are more elegant, some may work several nanoseconds faster, some may violate textbook coding habits, but in the end, who ever knows? Does it work? Was it delivered on time?
I always try to write stuff that is re-usable, not hard coded to particular sprite channels or cast members, generic handlers that can be re-purposed. (What a minute! AM I talking about Behaviors here? hmmmmm)
I am savagely disappointed when I peek into someone else's code and see no or little comments. And you know what, even when code is commented to death, it can still be hard to grasp because it was developed in the framework of the code writer's logic and perspective. I loathe even trying to figure out my own old code, much less than someone elses. Since I began posted examples of my own code. I've become acutely aware of making it as readable as possible-- and even there are still times when someone writes with a question about my well-commented code, and I look at my own handiwork thinking, "What the #$ / at / % / at / ^ is this?"
So let's talk about random()ness. It's a pretty familiar function and not to hard to think of some different situations where it could be used. On my interfaces, I look for ways to generate small acts of random motion (e.g.. a blinking array of lights, an analog-like meter, bouncing text that says "Please wait while we download this 600k shockwave file...")
And despite the illusion of the permanence of our own world, our computer screens, boxes of software, soda cans, our bodies themselves, are all at some level random processes of sub-atomic particles. Everything is random!
But one of the ways I've used random() the most is when I have a set of some information that needs to be presented or modified or dealt with in a random order. The original idea came when constructing multiple choice quizzes, when I wanted to have a "bank" of questions, and the order in which the questions are asked (and in fact, the order in which the answer choices also appear) is different every time I take the test. I first developed this approach in HyperCard and Toolbook, and have extended it to several director projects.
My approach is built upon lists. I love lists! I am a list junkie. Let's say you have a set of any type of data, the name of graphics files for a slide show or a series of parent-child objects representing test items. Whatever you have goes into a linear list, kept in a global variable. The order that they appear in the list does not matter. Lets call it:
global gItemBank set gItemBank = [ x, y, z, .... ]
Next, you create a global variable that is simply a counter that tracks what item you are dealing with. It "points" to the current item being dealt with. It could be incremented up or down depending on whether you want the viewer to move in either direction through your content. (Of course, you will have to check when they reach the minimum and maximum allowable values): We'll start with the first item.
global gItemCounter set gItemCounter = 1
Now here is the cool part. Instead of messing around with randomizing the order of our original lost, we leave that in tact. We create a second list, of the same length as th e original gItemBank, that serves as a mapping to that list. This second list contains integers between 1 and count(gItemBank), arranged in a random order. (I owe this clever little handler to a tip I once saw in the Lingo Users Journal). It's a generic handler (see!):
global gRandomIndex set gRandomIndex = randomList ¬ ( count( gItemBank ) ) on randomList listsize set newList to [] -- insert each number 1, 2, 3, -- ... listSize to a random -- position in the list repeat with i=1 to listsize addAt(newList, random(i), i ) end repeat return newList end
You can monkey around with this handler by throwing it into a movie script, calling up the message window, and sending it some calls:
put randomList(20) -- [6, 12, 11, 9, 14, 19, 7, 16, 2, 15, ¬ 18, 10, 1, 20, 8, 13, 4, 3, 17, 5] put randomList(10) -- [6, 5, 1, 10, 4, 9, 7, 2, 3, 8] put randomList(10) -- [10, 5, 7, 4, 1, 3, 2, 9, 8, 6] put randomList(10) -- [9, 6, 4, 3, 2, 10, 1, 7, 5, 8]
So now all I have to do is to increment gItemCounter to represent my current position in the order that the viewer is seeing things. When we need to pull a piece of data out of it, we access it by doing something like:
global gItemBank, gItemCounter, gRandomIndex set itemPointer = getAt¬ ( gRandomIndex, gItemCounter) set currentItem = getAt¬ ( gItemBank, itemPointer)
or for those that love compact code and fewer variable names floating about:
global gItemBank, gItemCounter, gRandomIndex set currentItem = getAt( gItemBank, ¬ getAt( gRandomIndex, gItemCounter) )
The beauty of this is, if the viewer exits the interaction but return later, all you have to do is to re-initialize the counter variable and create a newly random organized indexList... the original content is still intact, and hanging around in a global variable.
Okay, okay. This could all be done eleganty in OOP-land or Behavior-ville. I welcome other solutions to share. But this has proved a useful structure for several of my own projects.
To see some examples, look at my Shockwave "Quizzer". It reads in the test content from text files, so anyone can re-purpose the application to create a series of tests. You will be able to locate the source code from the links on that page. I used the same code structure for the test and laboratory rooms of a simulated environment called Negative Reinforcement University.
"That's Nice. Got Anything Else?"
THERE ARE OTHER TIMES WHEN you want Lingo-created objects to have their own functionality that has some roots in random process-es. Recently, someone in our local user group asked for a method to re-create the effect seen in the movie "Sneakers" where a computer screen of randomly generated text slowly unscrambles to reveal a hidden message.
Now it's not to hard to lay out the logic here. You know the final string of text, and then for some period of time you cycle through random letters in each character position. So we'll need to generate random characters and this is easiest done by generating random numbers and then converting them to text by the numToChar() function.And we could also use some randomness in making sure that the characters reveal themselves at different times.
And I thought it would be even more useful if the string of message text could be set external to the program, so in shockwave, it could be read in via the HTML embedding code. (like set gSneakText = externalParamValue("sw1"))
So let's think... We need each character in a string to scramble itself for some set of loops. All of the characters need to generate random letters in their proper position in a text string. Hey, this sounds like a job for Objects! Yes, we'll create lingo objects for each character in the string using a parent script that we'll call "sneaker". Each object will have properties:
property pId, pDestChar, pCurrChar, pTimes
where pId is the character position in the message string, pDestChar is the final character it should be when it is done scrambling, pCurrChar is a randomly generated character while the letter is still cycling, and pTimes is an integer telling this object how many times it should scramble itself before revealing the final character.
Also in the parent script for the letter objects, we include an on stepFrame handler, so that our letter objects can be put into Director's actorList and automatically updated while we loop over a frame. This stepFrame handler will do things like check if our pTimes property has reached 0 (meaning we are done scrambling and can reveal the final character). If pTimes has not reached zero, we'll subtract 1 from it, and generate a new random character to display:
on stepFrame me -- check if we have run the counter down if pTimes = 0 then -- put the intended letter -- into the proper place put pDestChar into char pID ¬ of field "display" else -- decrement the counter set pTimes = pTimes - 1 -- generate another random character set pCurrChar = numToChar( 31 + random(94) ) -- put the intended letter -- into the proper place put pCurrChar into char pID ¬ of field "display" end if end
So we start things off by creating a bunch of objects based upon our final message string:
repeat with i = 1 to length (gSneakText) -- let's create a random number -- for how many times to cycle -- each letter; this one is based -- upon a parameter read -- in from HTML parameters set fudgeFactor = gNumSneaks + ¬ random(10) * random(gNumSneaks) -- create an object for each letter -- and stick it in the actorList add the actorList, new( script "sneaker", ¬ i, char i of gSneakText,fudgeFactor) end repeat
Now we can have a grand 2 frame movie-- one frame to set up the objects and a second just to loop and let the objects do their work. You can see it for yourself and download the code from my Sneakerizer site which also demonstrates a known shockwave bug (!) in setting the foreColor of characters in fields plus other solutions by a few other Lingo-heads.
Copyright 1997-2024, Director Online. Article content copyright by respective authors.