[Richard Suchenwirth] 2003-06-26 - Re-reading an old book on DR [Logo], I found this funny little program that produces random recipes (please correct my re-translations to English where needed). Small as it is, it can produce 900 different recipes, though they might not be to everybody's taste... but may be helpful when we [teach programming to children]? [WikiDbImage cookbook.jpg] The basic idea is to pick an arbitrary element from a list, which is easily done in Tcl with the following: ====== proc ? L { lindex $L [expr {int(rand()*[llength $L])}] } ====== This is used several times in: ====== proc recipe {} { set a { {3 eggs} {an apple} {a pound of garlic} {a pumpkin} {20 marshmallows} } set b { {Cut in small pieces} {Dissolve in lemonade} {Bury in the ground for 3 months} {Bake at 300 degrees} {Cook until tender} } set c {parsley snow nutmeg curry raisins cinnamon} set d { {ice cream} {chocolate cake} spinach {fried potatoes} rice {soy sprouts} } return " Take [? $a]. [? $b]. Top with [? $c]. Serve with [? $d]." } ====== [Larry Smith] In the gaming world, we call these ''generators''. There are lots of good examples and explanations of the theory at http://www.seventhsanctum.com/. As it happens, I have been working on such a program in Tcl for my own use. You can do some amazing things with them. One problem with using Tcl, though, is recursion. I started hitting the recursion limit with very simple expressions, and really didn't manage to dodge it until I added my own code to process the statements non-recursively. Thus You see a [[color]] mushroom. Becomes You see a mushroom. Kind of sad, really, especially since having the entire Tcl language available at the substitution point is a ''huge'' advantage. You can do things like save certain choices and refer back to them in other areas to keep things consistent. For example, I have one table for spell ingredients where the first table selects an animal - a carp, a bat, whatever - but saves "fish" or "bat" or "reptile" - which are used later to select subtables of the appropriate bits - so that the system never demands a "foot of a fish" or the "wing of a cow". The recursion limit is forcing me to implement other escapes to get these effects and making it quite a bit more complicated. If anyone is interested, I could post this stuff when I'm satisfied with it. ====== And as modern programs always need a GUI, here is a minimal one that appears when you source this file at top level, and shows a new recipe every time you click on it: ====== if {[file tail [info script]]==[file tail $argv0]} { package require Tk pack [text .t -width 40 -height 5] bind .t <1> {showRecipe %W; break} proc showRecipe w { $w delete 1.0 end $w insert end [recipe] } showRecipe .t } ====== [TV] Good, me like. Looks like the beginning of a little expert system. Maybe one would want ot value the various combinations and suggest a taste base. ---- [AM] What about adding a few questions for those young programmers: * Show why the program can come up with 900 different receipes * Adjust the program so that it will show two or three receipes at the same time * Adjust the program so that no receipe will contain both apples and spinach together * Adjust the program so that it will show 1050 receipes * Adjust the program so that it will show 901 receipes Actually the last question is not that easy to answer: it requires restructuring a part of the program rather than small, almost negligeable changes. It is what one might call an example of the discontinuous nature of programs. Sometimes (often) small changes in the requirements lead to big changes in the program code. They might as well get used to this at an early age :( See also: [A simple memory game] which was inspired by this page. <> Arts and crafts of Tcl-Tk programming | Toys