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();
}