Brownian tree: Difference between revisions

Content deleted Content added
Chkas (talk | contribs)
1-based index
Morn (talk | contribs)
(15 intermediate revisions by 7 users not shown)
Line 255: Line 255:
14 HGR : POKE 49234,0
14 HGR : POKE 49234,0
15 ROT= 0: SCALE= 1: RETURN</syntaxhighlight>
15 ROT= 0: SCALE= 1: RETURN</syntaxhighlight>
=={{header|ATS}}==

[[File:Brownian tree.2023.05.07.18.48.00.png|thumb|alt=A brownian tree, black on white.]]
[[File:Brownian tree.2023.05.07.18.48.25.png|thumb|alt=A brownian tree, black on white.]]
[[File:Brownian tree.2023.05.07.18.49.01.png|thumb|alt=A brownian tree, black on white.]]
[[File:Brownian tree.2023.05.07.18.49.34.png|thumb|alt=A brownian tree, black on white.]]

The program outputs a Portable Arbitrary Map. Shown are some examples for 10000 particles on 300x300 grid.

<syntaxhighlight lang="ats">
(* This program pours all the particles onto the square at once, with
one of them as seed, and then lets the particles move around.

Compile with
patscc -std=gnu2x -D_GNU_SOURCE -g -O3 -DATS_MEMALLOC_LIBC brownian_tree_task.dats

You may need the -D_GNU_SOURCE to get a declaration of the
random(3) function. *)
(*------------------------------------------------------------------*)

%{^
#include <stdlib.h>
%}

#include "share/atspre_staload.hats"

#define NIL list_nil ()
#define :: list_cons

extern castfn lint2int : {i : int} lint i -<> int i
implement g1int2int<lintknd,intknd> i = lint2int i

extern fn random () : [i : nat] lint i = "mac#random"
extern fn srandom (seed : uint) : void = "mac#srandom"
extern fn atoi (s : string) : int = "mac#atoi"

(*------------------------------------------------------------------*)

datatype grid_position =
| Wall
| Empty
| Sticky
| Freely_moving

fn {}
grid_position_equal
(x : grid_position,
y : grid_position)
:<> bool =
case+ x of
| Wall () => (case+ y of Wall () => true | _ => false)
| Empty () => (case+ y of Empty () => true | _ => false)
| Sticky () => (case+ y of Sticky () => true | _ => false)
| Freely_moving () =>
(case+ y of Freely_moving () => true | _ => false)

fn {}
grid_position_notequal
(x : grid_position,
y : grid_position)
:<> bool =
~grid_position_equal (x, y)

overload = with grid_position_equal
overload <> with grid_position_notequal

(*------------------------------------------------------------------*)

abstype container (w : int, h : int) = ptr

local

typedef _container (w : int, h : int) =
'{M = matrixref (grid_position, w, h),
w = int w,
h = int h}

in (* local *)

assume container (w, h) = _container (w, h)

fn {}
container_make
{w, h : pos}
(w : int w,
h : int h)
: container (w, h) =
'{M = matrixref_make_elt<grid_position> (i2sz w, i2sz h, Empty),
w = w, h = h}

fn {}
container_width
{w, h : pos}
(C : container (w, h))
: int w =
C.w

fn {}
container_height
{w, h : pos}
(C : container (w, h))
: int h =
C.h

fn {}
container_get_at
{w, h : pos}
(C : container (w, h),
x : intBtwe (~1, w),
y : intBtwe (~1, h))
: grid_position =
let
macdef M = C.M
in
if (0 <= x) * (x < C.w) * (0 <= y) * (y < C.h) then
M[x, C.h, y]
else
Wall
end

fn
container_set_at
{w, h : pos}
(C : container (w, h),
x : intBtw (0, w),
y : intBtw (0, h),
gpos : grid_position)
: void =
let
macdef M = C.M
in
M[x, C.h, y] := gpos
end

end (* local *)

overload width with container_width
overload height with container_height
overload [] with container_get_at
overload [] with container_set_at

(*------------------------------------------------------------------*)

fn
random_direction () :
@(intBtwe (~1, 1), intBtwe (~1, 1)) =
let
val r1 = random ()
val r2 = random ()
val dx : intBtwe (0, 2) = g1i2i (r1 \nmod 3)
and dy : intBtwe (0, 2) = g1i2i (r2 \nmod 3)
in
@(pred dx, pred dy)
end

fn
in_sticky_position
{w, h : pos}
(C : container (w, h),
x : intBtw (0, w),
y : intBtw (0, h))
: bool =
(C[pred x, pred y] = Sticky () ||
C[pred x, y] = Sticky () ||
C[pred x, succ y] = Sticky () ||
C[succ x, pred y] = Sticky () ||
C[succ x, y] = Sticky () ||
C[succ x, succ y] = Sticky () ||
C[x, pred y] = Sticky () ||
C[x, succ y] = Sticky ())

fn
find_placement_for_another_particle
{w, h : pos}
(C : container (w, h))
: @(intBtw (0, w), intBtw (0, h)) =
let
val w = width C and h = height C

fun
loop () : @(intBtw (0, w), intBtw (0, h)) =
let
val r1 = random ()
val r2 = random ()
val x : intBtw (0, w) = g1i2i (r1 \nmod w)
and y : intBtw (0, h) = g1i2i (r2 \nmod h)
in
if C[x, y] <> Empty () then
loop ()
else
@(x, y)
end
in
loop ()
end

fn
move_particles
{w, h : pos}
(C : container (w, h),
particles : &List0 @(intBtw (0, w), intBtw (0, h)) >> _)
: void =
let
typedef coords = @(intBtw (0, w), intBtw (0, h))

fun
loop {n : nat} .<n>.
(particles : list (coords, n),
new_lst : List0 coords)
: List0 coords =
case+ particles of
| NIL => new_lst
| @(x0, y0) :: tl =>
let
val @(dx, dy) = random_direction ()
val x1 = x0 + dx and y1 = y0 + dy
in
if C[x1, y1] = Empty () then
let
val () = assertloc (0 <= x1)
val () = assertloc (x1 < width C)
val () = assertloc (0 <= y1)
val () = assertloc (y1 < height C)
in
C[x1, y1] := C[x0, y0];
C[x0, y0] := Empty ();
loop (tl, @(x1, y1) :: new_lst)
end
else
(* Our rule is: if there is anything where it WOULD have
moved to, then the particle does not move. *)
loop (tl, @(x0, y0) :: new_lst)
end
in
particles := loop (particles, NIL)
end

fn
find_which_particles_are_stuck
{w, h : pos}
(C : container (w, h),
particles : &List0 @(intBtw (0, w), intBtw (0, h)) >> _)
: void =
(* Our rule is: if a particle is next to something that ALREADY was
stuck, then it too is stuck. Otherwise it remains free. *)
let
typedef coords = @(intBtw (0, w), intBtw (0, h))

fun
loop {n : nat} .<n>.
(particles : list (coords, n),
new_lst : List0 coords)
: List0 coords =
case+ particles of
| NIL => new_lst
| @(x, y) :: tl =>
if in_sticky_position (C, x, y) then
begin
C[x, y] := Sticky ();
loop (tl, new_lst)
end
else
loop (tl, @(x, y) :: new_lst)
in
particles := loop (particles, NIL)
end

fn
pour_particles
{w, h : pos}
{n : nat}
(C : container (w, h),
n : int n,
free_particles : &List0 @(intBtw (0, w), intBtw (0, h))?
>> List0 @(intBtw (0, w), intBtw (0, h)))
: void =
if n = 0 then
free_particles := NIL
else
let
typedef coords = @(intBtw (0, w), intBtw (0, h))

fun
loop {i : nat | i <= n - 1}
.<(n - 1) - i>.
(particles : list (coords, i),
i : int i)
: list (coords, n - 1) =
if i = pred n then
particles
else
let
val @(x, y) = find_placement_for_another_particle C
in
C[x, y] := Freely_moving;
loop (@(x, y) :: particles, succ i)
end

val @(xseed, yseed) = find_placement_for_another_particle C
in
C[xseed, yseed] := Sticky ();
free_particles := loop (NIL, 0)
end

fn
go_until_all_particles_are_stuck
{w, h : pos}
(C : container (w, h),
free_particles : List0 @(intBtw (0, w), intBtw (0, h)))
: void =
let
typedef coords = @(intBtw (0, w), intBtw (0, h))

fun
loop (free_particles : &List0 coords >> _) : void =
case+ free_particles of
| NIL => ()
| _ :: _ =>
begin
move_particles (C, free_particles);
find_which_particles_are_stuck (C, free_particles);
loop free_particles
end

var free_particles : List0 coords = free_particles
in
find_which_particles_are_stuck (C, free_particles);
loop free_particles
end

fn
build_a_tree {w, h : pos}
{n : nat}
(w : int w,
h : int h,
n : int n)
: container (w, h) =
let
val C = container_make (w, h)
var free_particles : List0 @(intBtw (0, w), intBtw (0, h))
in
pour_particles (C, n, free_particles);
go_until_all_particles_are_stuck (C, free_particles);
C
end

fn
write_a_PAM_image
{w, h : pos}
(outf : FILEref,
C : container (w, h),
seed : uint)
: void =
let
val w = width C and h = height C

fun
count_particles
{x, y : nat | x <= w; y <= h}
.<h - y, w - x>.
(x : int x,
y : int y,
n : int)
: int =
if y = h then
n
else if x = w then
count_particles (0, succ y, n)
else if C[x, y] = Empty () then
count_particles (succ x, y, n)
else
count_particles (succ x, y, succ n)

fun
loop {x, y : nat | x <= w; y <= h}
.<h - y, w - x>.
(x : int x,
y : int y)
: void =
if y = h then
()
else if x = w then
loop (0, succ y)
else
begin
fprint_val<char>
(outf, if C[x, y] = Empty () then '\1' else '\0');
loop (succ x, y)
end
in
fprintln! (outf, "P7");
fprintln! (outf, "# Number of particles = ",
count_particles (0, 0, 0));
fprintln! (outf, "# Seed = ", seed);
fprintln! (outf, "WIDTH ", width C);
fprintln! (outf, "HEIGHT ", height C);
fprintln! (outf, "DEPTH 1");
fprintln! (outf, "MAXVAL 1");
fprintln! (outf, "TUPLTYPE BLACKANDWHITE");
fprintln! (outf, "ENDHDR");
loop (0, 0)
end

(*------------------------------------------------------------------*)

implement
main0 (argc, argv) =
let
val args = list_vt2t (listize_argc_argv (argc, argv))
val nargs = argc
in
if nargs <> 5 then
begin
fprintln! (stderr_ref, "Usage: ", args[0],
" width height num_particles seed");
exit 1
end
else
let
val w = g1ofg0 (atoi (args[1]))
and h = g1ofg0 (atoi (args[2]))
and num_particles = g1ofg0 (atoi (args[3]))
and seed = g1ofg0 (atoi (args[4]))
in
if (w < 1) + (h < 1) + (num_particles < 0) + (seed < 0) then
begin
fprintln! (stderr_ref, "Illegal command line argument.");
exit 1
end
else
let
val seed : uint = g0i2u seed
val () = srandom seed
val C = build_a_tree (w, h, num_particles)
in
write_a_PAM_image (stdout_ref, C, seed)
end
end
end

(*------------------------------------------------------------------*)
</syntaxhighlight>

=={{header|AutoHotkey}}==
=={{header|AutoHotkey}}==
{{works with|AutoHotkey_L}}
{{works with|AutoHotkey_L}}
Line 312: Line 755:
return r
return r
}</syntaxhighlight>Sample output file [http://www.autohotkey.net/~crazyfirex/Images/brownian.png here]
}</syntaxhighlight>Sample output file [http://www.autohotkey.net/~crazyfirex/Images/brownian.png here]

=={{header|BBC BASIC}}==
=={{header|BBC BASIC}}==
{{works with|BBC BASIC for Windows}}
{{works with|BBC BASIC for Windows}}
Line 1,003: Line 1,447:
=={{header|EasyLang}}==
=={{header|EasyLang}}==


[https://easylang.dev/show/#cod=dZHLboMwEEX3/oqzLoqxiahUCfIjiAUlRrVK7IjQFv6+snmkqpKFrfH1eM6dcet7PxxRaLTojaOrajKleAm7uPhvQ67IlRhMO6JkHpboKr3lkKCVqinRwlHyppQSPx+2N1gKnIDBXE0zCoCJkqFxZ+vG+PiAjvr8RP9yo+3pqnmHTQFYU5xihhSwwHR0EBmekmkpG8J5JSd3xJED2Qp+KNuOiQKFH5i3YOJURhdRXOKYDe+DaT5XvtwqPLC9eYQ42smTkgWb6QoO0/oz6EXqqtnfK/n/pWzoYT90WC7+jH6lZPMH7frTMiPBkuLin2/Xt96Y654un7QlhRS/ Run it]
[https://easylang.online/apps/_brownian-tree.html Run it]


<syntaxhighlight lang="text">
<syntaxhighlight>
color3 0 1 1
color3 0 1 1
len f[] 200 * 200
len f[] 200 * 200
Line 1,014: Line 1,458:
while i < n
while i < n
repeat
repeat
x = random 200 - 1
x = randint 200 - 1
y = random 200 - 1
y = randint 200 - 1
until f[y * 200 + x + 1] <> 1
until f[y * 200 + x + 1] <> 1
.
.
Line 1,021: Line 1,465:
xo = x
xo = x
yo = y
yo = y
x += random 3 - 2
x += randint 3 - 2
y += random 3 - 2
y += randint 3 - 2
if x < 0 or y < 0 or x >= 200 or y >= 200
if x < 0 or y < 0 or x >= 200 or y >= 200
break 1
break 1
Line 1,039: Line 1,483:
.
.
.
.
</syntaxhighlight>

=={{header|Evaldraw}}==

Based on the C version. Shows the brownian tree animate. Color each particle based on the time it settled. Dont overwrite existing particles.

[[File:Brownian tree from initial particle at center.gif|thumb|alt=Brownian trees form patterns similar to dendrites in nature|Animated brownian tree over the coarse of circa 1000 frames]]

<syntaxhighlight lang="c">
enum{SIZE=256, PARTICLES_PER_FRAME=10, PARTICLE_OK, GIVE_UP};
static world[SIZE][SIZE];
()
{
// set the seed
if (numframes==0) world[SIZE/2][SIZE/2] = 1;
t = klock();
simulate_brownian_tree(t);

cls(0);
for (y = 0; y < SIZE; y++){
for (x = 0; x < SIZE; x++){
cell = world[y][x];
if ( cell ) {
s = 100; // color scale
setcol(128+(s*cell % 128), 128+(s*.7*cell % 128), 128+(s*.1*cell % 128) );
setpix(x,y);
}
}
}
moveto(0,SIZE+15);
setcol(0xffffff);
printf("%g frames", numframes);
}

plop_particle(&px, &py) {
for (try=0; try<1000; try++) {
px = int(rnd*SIZE);
py = int(rnd*SIZE);
if (world[py][px] == 0) return PARTICLE_OK;
}
return GIVE_UP;
}

simulate_brownian_tree(time){
for(iter=0; iter<PARTICLES_PER_FRAME; iter++) // Rate of particle creation
{
// set particle's initial position
px=0; py=0;
if ( plop_particle(px,py) == GIVE_UP ) return;

while (1) { // Keep iterating until we bump into a solid particle
// randomly choose a direction
dx = int(rnd * 3) - 1;
dy = int(rnd * 3) - 1;
if (dx + px < 0 || dx + px >= SIZE || dy + py < 0 || dy + py >= SIZE)
{
// Restart if outside of screen
if ( plop_particle(px,py) == GIVE_UP ) return;
}else if (world[py + dy][px + dx]){
// bumped into something
world[py][px] = time;
break;
}else{
py += dy;
px += dx;
}
}
}
}

</syntaxhighlight>
</syntaxhighlight>


=={{header|Factor}}==
=={{header|Factor}}==
This example sets four spawn points, one in each corner of the image, giving the result a vague x-shaped appearance. For visual reasons, movement is restricted to diagonals. So be careful if you change the seed or spawns — they should all fall on the same diagonal.
This example sets four spawn points, one in each corner of the image, giving the result a vague x-shaped appearance. For visual reasons, movement is restricted to diagonals. So be careful if you change the seed or spawns — they should all fall on the same diagonal.
<syntaxhighlight lang="factor">USING: accessors images images.loader kernel literals math
headerUSING: accessors images images.loader kernel literals math
math.vectors random sets ;
math.vectors random sets ;
FROM: sets => in? ;
FROM: sets => in? ;
Line 2,282: Line 2,798:
=={{header|Locomotive Basic}}==
=={{header|Locomotive Basic}}==
{{trans|ZX Spectrum Basic}}
{{trans|ZX Spectrum Basic}}
[[File:Cpcbasic brownian.png|thumb|Output]]
This program is ideally run in [https://benchmarko.github.io/CPCBasic/cpcbasic.html CPCBasic] and should finish after about 20 to 25 minutes (Chrome, desktop CPU). At normal CPC speed, it would probably take several days to run when set to 10000 particles.
This program is ideally run in [https://benchmarko.github.io/CPCBasic/cpcbasic.html CPCBasic] and should finish after about 20 to 25 minutes (Chrome, desktop CPU). At normal CPC speed, it would probably take several days to run when set to 10000 particles.
<syntaxhighlight lang="locobasic">10 MODE 1:DEFINT a-z:RANDOMIZE TIME:np=10000
<syntaxhighlight lang="locobasic">10 MODE 1:DEFINT a-z:RANDOMIZE TIME:np=10000
Line 2,299: Line 2,816:
1020 y=RND*400
1020 y=RND*400
1030 RETURN</syntaxhighlight>
1030 RETURN</syntaxhighlight>

=={{header|Lua}}==
=={{header|Lua}}==
The output is stored in as a ppm-image. The source code of these output-functions is located at
The output is stored in as a ppm-image. The source code of these output-functions is located at
Line 2,790: Line 3,308:


Code runs until the tree reached specified radius. Output is written to "test.eps" of wherever the current directory is.
Code runs until the tree reached specified radius. Output is written to "test.eps" of wherever the current directory is.
<syntaxhighlight lang="perl">sub PI() { atan2(1,1) * 4 } # The, er, pi
<syntaxhighlight lang="perl">use strict;
use warnings;
sub STEP() { .5 } # How far does the particle move each step. Affects

# both speed and accuracy greatly
use constant PI => 2*atan2(1,0); # π
sub STOP_RADIUS() { 100 } # When the tree reaches this far from center, end
use constant STEP => 0.5; # How far particle moves each step. Affects both speed and accuracy greatly
use constant STOP_RADIUS => 100; # When the tree reaches this far from center, end


# At each step, move this much towards center. Bigger numbers help the speed because
# At each step, move this much towards center. Bigger numbers help the speed because
# particles are less likely to wander off, but greatly affects tree shape.
# particles are less likely to wander off, but greatly affects tree shape.
# Should be between 0 and 1 ish. Set to 0 for pain.
# Should be between 0 and 1 ish. Set to 0 for pain.
sub ATTRACT() { .2 }
use constant ATTRACT => 0.2;


my @particles = map([ map([], 0 .. 2 * STOP_RADIUS) ], 0 .. 2 * STOP_RADIUS);
my @particles = map([ map([], 0 .. 2 * STOP_RADIUS) ], 0 .. 2 * STOP_RADIUS);
push @{ $particles[STOP_RADIUS][STOP_RADIUS] }, [0, 0];
push @{ $particles[STOP_RADIUS][STOP_RADIUS] }, [0, 0];
my($r_start, $max_dist) = (3, 0);

my $r_start = 3;
my $max_dist = 0;


sub dist2 {
sub dist2 {
no warnings 'uninitialized';
my ($dx, $dy) = ($_[0][0] - $_[1][0], $_[0][1] - $_[1][1]);
my ($dx, $dy) = ($_[0][0] - $_[1][0], $_[0][1] - $_[1][1]);
$dx * $dx + $dy * $dy
$dx * $dx + $dy * $dy
Line 2,890: Line 3,409:


my $count;
my $count;
PARTICLE: while (1) {
PARTICLE: while () {
my $a = rand(2 * PI);
my $a = rand(2 * PI);
my $p = [ $r_start * cos($a), $r_start * sin($a) ];
my $p = [ $r_start * cos($a), $r_start * sin($a) ];
while (my $m = move($p)) {
while (my $m = move $p) {
if ($m == 1) { next }
if ($m == 1) { next }
elsif ($m == 2) { $count++; last; }
elsif ($m == 2) { $count++; last }
elsif ($m == 3) { last PARTICLE }
elsif ($m == 3) { last PARTICLE }
else { last }
else { last }
}
}
print STDERR "$count $max_dist/@{[int($r_start)]}/@{[STOP_RADIUS]}\r" unless $count% 7;
print STDERR "$count $max_dist/@{[int($r_start)]}/@{[STOP_RADIUS]}\r" unless $count% 7;
Line 2,904: Line 3,423:
sub write_eps {
sub write_eps {
my $size = 128;
my $size = 128;
my $p = $size / (STOP_RADIUS * 1.05);
my $p = $size / (STOP_RADIUS * 1.05);
my $b = STOP_RADIUS * $p;
my $b = STOP_RADIUS * $p;
if ($p < 1) {
if ($p < 1) {
$size = STOP_RADIUS * 1.05;
$size = STOP_RADIUS * 1.05;
$b = STOP_RADIUS;
$p = 1;
$p = 1;
$b = STOP_RADIUS;
}
}

my $hp = $p / 2;
my $hp = $p / 2;


open OUT, ">", "test.eps";
open OUT, '>', 'test.eps';
print OUT <<~"HEAD";

# print EPS to standard out
%!PS-Adobe-3.0 EPSF-3.0
%%BoundingBox: 0 0 @{[$size*2, $size*2]}
print OUT <<"HEAD";
$size $size translate
%!PS-Adobe-3.0 EPSF-3.0
/l{ rlineto }def
%%BoundingBox: 0 0 @{[$size*2, $size*2]}
/c{ $hp 0 360 arc fill }def
$size $size translate
-$size -$size moveto
/l{ rlineto }def
$size 2 mul 0 l
/c{ $hp 0 360 arc fill }def
-$size -$size moveto
0 $size 2 mul l
$size 2 mul 0 l
-$size 2 mul 0 l
closepath
0 $size 2 mul l
0 setgray fill
-$size 2 mul 0 l
0 setlinewidth .1 setgray 0 0 $b 0 360 arc stroke
closepath
.8 setgray /TimesRoman findfont 16 scalefont setfont
0 setgray fill
-$size 10 add $size -16 add moveto
0 setlinewidth .1 setgray 0 0 $b 0 360 arc stroke
(Step = @{[STEP]} Attract = @{[ATTRACT]}) show
.8 setgray /TimesRoman findfont 16 scalefont setfont
0 1 0 setrgbcolor newpath
-$size 10 add $size -16 add moveto
HEAD
(Step = @{[STEP]} Attract = @{[ATTRACT]}) show
0 1 0 setrgbcolor newpath
HEAD


for (@particles) {
for (@particles) {
Line 2,945: Line 3,461:
}
}


write_eps;</syntaxhighlight>
write_eps();</syntaxhighlight>

=={{header|Phix}}==
=={{header|Phix}}==
As-is, runs in about 2s, but can be very slow when bigger or (even worse) resize-able.
As-is, runs in about 2s, but can be very slow when bigger or (even worse) resize-able.
Line 4,444: Line 4,961:
world[py][px] := 1;
world[py][px] := 1;
rect(SCALE * pred(px), SCALE * pred(py), SCALE, SCALE, white);
rect(SCALE * pred(px), SCALE * pred(py), SCALE, SCALE, white);
DRAW_FLUSH;
flushGraphic;
bumped := TRUE;
bumped := TRUE;
else
else
Line 4,452: Line 4,969:
until bumped;
until bumped;
end for;
end for;
end func;
const proc: main is func
begin
screen(SIZE * SCALE, SIZE * SCALE);
KEYBOARD := GRAPH_KEYBOARD;
genBrownianTree(SIZE, 20000);
readln(KEYBOARD);
end func;</syntaxhighlight>
end func;</syntaxhighlight>


Original source: [http://seed7.sourceforge.net/algorith/graphic.htm#brownian_tree]
Original source: [http://seed7.sourceforge.net/algorith/graphic.htm#brownian_tree]

=={{header|SequenceL}}==
=={{header|SequenceL}}==
'''SequenceL Code:'''<br>
'''SequenceL Code:'''<br>
Line 4,911: Line 5,421:
:Pause
:Pause
:RecallGDB 0</syntaxhighlight>
:RecallGDB 0</syntaxhighlight>

=={{header|Uiua}}==
Uiua Pad will show well-shaped arrays as images directly. If running locally you can uncomment the final few lines to save it as a file instead. (Running local is ~10 times faster too.)

The main move loop passes round a pair of points: here and previous position, so when we hit a set cell we can just back up one.

<syntaxhighlight lang="Uiua">
S ← 80
# Create SxS grid, and set the centre point as seed.
⍜⊡(+1)↯2⌊÷2S ↯ S_S 0

RandInt ← ⌊×⚂
RandPoint ← ([⍥(RandInt S)2])
# Update the pair to be a new adjacent [[Here] [Last]]
Move ← ⊟∵(-1+⌊RandInt 3).⊢
In ← /××⊃(≥0)(<S) # Is this point in bounds?
# Given a grid return a free point pair and that grid.
SeedPair ← ⊟.⍢(RandPoint ◌)(=1⊡) RandPoint
# Find next adjacent position, or new seed if out of bounds.
Next ← ⟨SeedPair ◌|∘⟩:⟜(In ⊢)Move
# Start from a new Seed Pair and move until you hit the tree. Add the prior pos to the tree.
JoinTree ← ⍜⊡(+1)◌°⊟⍢Next (=0⊡⊢) SeedPair
# Do it multiple times.
⍜now⍥JoinTree500

# ◌
# &ime "png"
# &fwa "BrownianTree.png"
</syntaxhighlight>

Or if you like your code terse :-)

<syntaxhighlight lang="Uiua">
S ← 80
⍜⊡(+1)↯2⌊÷2S↯S_S0
Rp ← (⊟⍥(⌊×⚂S)2)
Sd ← ⊟.⍢(Rp◌)(=1⊡) Rp
Nx ← ⟨Sd◌|∘⟩:⟜(/××⊃(≥0)(<S)⊢)⊟∵(-1+⌊×⚂3).⊢
⍜now⍥(⍜⊡(+1)◌°⊟⍢Nx(=0⊡⊢)Sd)500
</syntaxhighlight>
{{out}}
[[File:UiuaBrownianTree.png|thumb|center||Sample with higher values than provided code]]

=={{header|Visual Basic .NET}}==
=={{header|Visual Basic .NET}}==
Windows Forms Application.
Windows Forms Application.
Line 5,051: Line 5,604:
{{trans|Go}}
{{trans|Go}}
As you'd expect, not very fast so have halved Go's parameters to draw the tree in around 45 seconds.
As you'd expect, not very fast so have halved Go's parameters to draw the tree in around 45 seconds.
<syntaxhighlight lang="ecmascript">import "graphics" for Canvas, Color
<syntaxhighlight lang="wren">import "graphics" for Canvas, Color
import "dome" for Window
import "dome" for Window
import "random" for Random
import "random" for Random
Line 5,142: Line 5,695:


var Game = BrownianTree.new(200, 150, 7500)</syntaxhighlight>
var Game = BrownianTree.new(200, 150, 7500)</syntaxhighlight>

=={{header|XPL0}}==
=={{header|XPL0}}==
[[File:BrownXPL0.gif|right]]
[[File:BrownXPL0.gif|right]]