EUREKA! After searching the books I have and not finding quite what I thought I would, I decided to experiment. After looking at the picture again it seemed that standard DLA would not do. I think I could modify a DLA program to produce something like that and I'm sure it could also be done with some percolation model, but the algorithm I found is probably the simplest. Actually I found two methods that produce the same result. The second one is simpler and faster but doesn't keep a record of the whole picture. I started coding in C, but soon realized that recompiling ever time I made a little change would soon take all the fun out. So here they are in BASIC for the QBasic interpreter. #1: Drop particles straight down at random x values from higher than the highest part of the aggregate, looking at the 3 sites below, sticking when one of them is filled. #2: Just keep track of y for the highest particle at each x value, look for the maximum of the values at x-1, x, x+1 for random x, use that plus one as y for the new particle. The third program is for comparison. RANDOMIZE TIMER SCREEN 12: WINDOW (-320, 239)-(319, -240): CLS w = 120: h = 120: d = 1: m = 14: p = 1 DIM s(w + 1, h + 1) FOR x = 0 TO w FOR y = 0 TO h s(x, y) = 0 NEXT y NEXT x WHILE d <= h x = INT(RND * (w - 1)) + 1 y = d c = 0 WHILE y <> 0 AND c = 0 IF p = 1 THEN PSET (x, y), 15 c = s(x, y - 1) IF c = 0 THEN c = s(x - 1, y - 1) IF c = 0 THEN c = s(x + 1, y - 1) IF INT(RND * 2) = 1 AND s(x + 1, y - 1) <> 0 THEN c = s(x + 1, y - 1) IF p = 1 THEN PSET (x, y), 0 IF c = 0 THEN y = y - 1 WEND IF c = 0 THEN c = (x MOD m) + 1 s(x, y) = c PSET (x, y), c IF y = d - 1 THEN d = d + 1 WEND RANDOMIZE TIMER SCREEN 12: WINDOW (0, 479)-(639, 0): CLS w = 640: h = 480: d = 1: m = 14 DIM s(w + 1), c(w + 1) FOR x = 0 TO w s(x) = 0 c(x) = 0 NEXT x WHILE d <= h x = INT(RND * (w - 1)) + 1 f = x IF s(f) < s(x - 1) THEN f = x - 1 IF s(f) < s(x + 1) THEN f = x + 1 IF INT(RND * 2) = 1 AND s(f) = s(x + 1) THEN f = x + 1 s(x) = s(f) c(x) = c(f) IF c(x) = 0 THEN c(x) = (x MOD m) + 1 PSET (x, s(x)), c(x) s(x) = s(x) + 1 IF s(x) = d THEN d = d + 1 WEND SCREEN 12 RANDOMIZE TIMER PRINT "initializing" w = 100: h = 100: m = 14: n = INT(w * h / 4) DIM r(n), s(w + 1), c(w + 1), i(w + 1, h + 1) FOR t = 0 TO n IF t MOD 100 = 0 THEN PRINT "."; r(t) = INT(RND * (w - 1)) + 1 NEXT t FOR x = 0 TO w PRINT "."; s(x) = 0 c(x) = 0 FOR y = 0 TO h i(x, y) = 0 NEXT y NEXT x CLS WINDOW (-320 + w + 10, 239)-(319 + w + 10, -240) d = 1: t = 0: p = 1 LOCATE 1, 1: PRINT TIME$ WHILE d <= h AND t < n x = r(t): t = t + 1: LOCATE 2, 1: PRINT t y = d c = 0 WHILE y <> 0 AND c = 0 IF p = 1 THEN PSET (x, y), 15 c = i(x, y - 1) IF c = 0 THEN c = i(x - 1, y - 1) IF c = 0 THEN c = i(x + 1, y - 1) IF i(x + 1, y - 1) <> 0 AND r(t) MOD 2 = 1 THEN c = i(x + 1, y - 1) IF p = 1 THEN PSET (x, y), 0 IF c = 0 THEN y = y - 1 WEND IF c = 0 THEN c = (x MOD m) + 1 i(x, y) = c PSET (x, y), c IF y = d - 1 THEN d = d + 1: PSET (-5, d), 15 WEND WINDOW (-320, 239)-(319, -240) d = 1: t = 0 LOCATE 3, 1: PRINT TIME$ WHILE d <= h AND t < n x = r(t): t = t + 1: LOCATE 4, 1: PRINT t f = x IF s(f) < s(x - 1) THEN f = x - 1 IF s(f) < s(x + 1) THEN f = x + 1 IF s(f) = s(x + 1) AND r(t) MOD 2 = 1 THEN f = x + 1 s(x) = s(f) c(x) = c(f) IF c(x) = 0 THEN c(x) = (x MOD m) + 1 PSET (x, s(x)), c(x) s(x) = s(x) + 1 IF s(x) = d THEN d = d + 1: PSET (-5, d), 15 WEND LOCATE 5, 1: PRINT TIME$ Some books that briefly mention aggregation or percolation and have a picture or two of generated clusters: 1. FractalVision Dick Oliver 2. The Science of Fractal Images Heinz-Otto Peitgen & Dietmar Saupe Editors 3. Islands of Truth Ivars Peterson 4. The Mathematical Tourist Ivars Peterson 5. Fractals, Chaos, Power Laws Manfred Schroeder 6. Does God Play Dice? Ian Stewart 7. Cellular Automata Machines Tommaso Toffoli & Norman Margolus Books with the most about aggregation and percolation: 8. Fractals Jens Feder 9. Fractal Growth Phenomena (Second Edition) Tamas Vicsek Number 8 is the book that inspired me a few years ago to write a program I called RFCGDLAS. (which obviously stands for Random Fractal Cluster Generating Diffusion Limited Aggregation Simulation ;-) Number 9 is the book that prompted me on Friday to try ballistic aggregation. And finally, after I wrote my ballistic aggregation programs, I looked through my Algorithm magazines and found an ad in November 1990 issue: ------------------------------------------------------------------------ Generate your own fractals using BALLISTIC \\\\\\\\\\\\\\\\\ AGGREGATION TECHNIQUES. Beautiful \ small and \ fractals resemble coral, bushes, trees and \ blocky black \ mountains. In color on EGA or VGA. Many \ and white \ hours of fun and education. Menus and Help \ graphic here \ plus hot keys provide ease of use. Introductory \ \ offer: $25.00 \ \ Contact: FRACTAL RECREATIONS \\\\\\\\\\\\\\\\\ 21 Wichard Blvd. Commack, NY 11725-1706 (516) 543-3850 ------------------------------------------------------------------------ Although the picture is small and not colored, this is probably what I remember seeing that I thought was in a book! Or maybe it was something in Science News....... The world may never know. PS: Here's the C++ for the graphics if you want it ... #include "Xwin.h" #include main() { const int w = 640, h = 480; short int f, x, d = 1, m = 14, s[w+1], c[w+1]; cout << "rand seed: "; cin >> f; srand(f); Xwin ba("Ballistic Aggregation", w, h, 1); ba.clear(); for(x = 0; x <= w; x++) s[x] = c[x] = 0; while(d <= h) { x = rand()%(w-1) + 1; f = x; if(s[f] < s[x-1]) f = x - 1; if(s[f] < s[x+1]) f = x + 1; if(s[f] == s[x+1] && rand()/2%2) f = x + 1; s[x] = s[f]; c[x] = c[f]; if(!c[x]) c[x] = x%m + 1; switch(c[x]) { case 1: ba.change_color("gold"); break; case 2: ba.change_color("orange"); break; case 3: ba.change_color("yellow"); break; case 4: ba.change_color("deep pink"); break; case 5: ba.change_color("red"); break; case 6: ba.change_color("magenta"); break; case 7: ba.change_color("cyan"); break; case 8: ba.change_color("blue"); break; case 9: ba.change_color("coral"); break; case 10: ba.change_color("orchid"); break; case 11: ba.change_color("aquamarine"); break; case 12: ba.change_color("maroon"); break; case 13: ba.change_color("cornflower blue"); break; case 14: ba.change_color("violet red"); break; // alternative palette // case 1: ba.change_color("slate blue"); break; // case 2: ba.change_color("sky blue"); break; // case 3: ba.change_color("turquoise"); break; // case 4: ba.change_color("cyan"); break; // case 5: ba.change_color("aquamarine"); break; // case 6: ba.change_color("sea green"); break; // case 7: ba.change_color("cornflower blue"); break; // case 8: ba.change_color("purple"); break; // case 9: ba.change_color("lime green"); break; // case 10: ba.change_color("orchid"); break; // case 11: ba.change_color("medium aquamarine"); break; // case 12: ba.change_color("medium sea green"); break; // case 13: ba.change_color("steel blue"); break; // case 14: ba.change_color("violet red"); break; } ba.draw_block(x, s[x]); if(++s[x] == d) d++; if(!(d%5)) Xwin::flush(); } Xwin::flush(); Xwin::wait_for_button_press(); }