2016 Update
This commit is contained in:
parent
948b86eafa
commit
dcf5d15da3
7965 changed files with 139854 additions and 31002 deletions
|
|
@ -1,4 +1,9 @@
|
|||
Generate and draw a [[wp:Brownian tree|Brownian Tree]].
|
||||
[[File:Brownian_tree.jpg|600px||right]]
|
||||
|
||||
|
||||
;Task:
|
||||
Generate and draw a [[wp:Brownian tree|Brownian Tree]].
|
||||
|
||||
|
||||
A Brownian Tree is generated as a result of an initial seed, followed by the interaction of two processes.
|
||||
|
||||
|
|
@ -6,4 +11,4 @@ A Brownian Tree is generated as a result of an initial seed, followed by the int
|
|||
# Particles are injected into the field, and are individually given a (typically random) motion pattern.
|
||||
# When a particle collides with the seed or tree, its position is fixed, and it's considered to be part of the tree.
|
||||
|
||||
Because of the lax rules governing the random nature of the particle's placement and motion, no two resulting trees are really expected to be the same, or even necessarily have the same general shape.
|
||||
<br>Because of the lax rules governing the random nature of the particle's placement and motion, no two resulting trees are really expected to be the same, or even necessarily have the same general shape. <br><br>
|
||||
|
|
|
|||
11
Task/Brownian-tree/PARI-GP/brownian-tree-1.pari
Normal file
11
Task/Brownian-tree/PARI-GP/brownian-tree-1.pari
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
\\ 2 plotting helper functions 3/2/16 aev
|
||||
\\ insm(): x,y are inside matrix mat (+/- p deep).
|
||||
insm(mat,x,y,p=0)={my(xz=#mat[1,],yz=#mat[,1]);
|
||||
return(x+p>0 && x+p<=xz && y+p>0 && y+p<=yz && x-p>0 && x-p<=xz && y-p>0 && y-p<=yz)}
|
||||
\\ plotmat(): Simple plotting using matrix mat (filled with 0/1).
|
||||
plotmat(mat)={
|
||||
my(xz=#mat[1,],yz=#mat[,1],vx=List(),vy=vx,x,y);
|
||||
for(i=1,yz, for(j=1,xz, if(mat[i,j]==0, next, listput(vx,i); listput(vy,j))));
|
||||
plothraw(Vec(vx),Vec(vy));
|
||||
print(" *** matrix(",xz,"x",yz,") ",#vy, " DOTS");
|
||||
}
|
||||
20
Task/Brownian-tree/PARI-GP/brownian-tree-2.pari
Normal file
20
Task/Brownian-tree/PARI-GP/brownian-tree-2.pari
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
\\ 3/8/2016
|
||||
BrownianTree1(size,lim)={
|
||||
my(Myx=matrix(size,size),sz=size-1,sz2=sz\2,x,y,ox,oy);
|
||||
x=sz2; y=sz2; Myx[y,x]=1; \\ seed in center
|
||||
print(" *** START: ",x,"/",y);
|
||||
for(i=1,lim,
|
||||
x=random(sz)+1; y=random(sz)+1;
|
||||
while(1,
|
||||
ox=x; oy=y;
|
||||
x+=random(3)-1; y+=random(3)-1;
|
||||
if(insm(Myx,x,y)&&Myx[y,x],
|
||||
if(insm(Myx,ox,oy), Myx[oy,ox]=1; break));
|
||||
if(!insm(Myx,x,y), break);
|
||||
);\\wend
|
||||
);\\ fend i
|
||||
plotmat(Myx);
|
||||
}
|
||||
{\\ Executing:
|
||||
BrownianTree1(400,15000);
|
||||
}
|
||||
18
Task/Brownian-tree/PARI-GP/brownian-tree-3.pari
Normal file
18
Task/Brownian-tree/PARI-GP/brownian-tree-3.pari
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
\\ 3/11/2016
|
||||
BrownianTree2(size,lim)={
|
||||
my(Myx=matrix(size,size),sz=size-1,dx,dy,x,y);
|
||||
x=random(sz); y=random(sz); Myx[y,x]=1; \\ random seed
|
||||
print(" *** START: ",x,"/",y);
|
||||
for(i=1,lim,
|
||||
x=random(sz)+1; y=random(sz)+1;
|
||||
while(1,
|
||||
dx=random(3)-1; dy=random(3)-1;
|
||||
if(!insm(Myx,x+dx,y+dy), x=random(sz)+1; y=random(sz)+1,
|
||||
if(Myx[y+dy,x+dx], Myx[y,x]=1; break, x+=dx; y+=dy));
|
||||
);\\wend
|
||||
);\\fend i
|
||||
plotmat(Myx);
|
||||
}
|
||||
{\\ Executing:
|
||||
BrownianTree2(1000,3000);
|
||||
}
|
||||
20
Task/Brownian-tree/PARI-GP/brownian-tree-4.pari
Normal file
20
Task/Brownian-tree/PARI-GP/brownian-tree-4.pari
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
\\ 3/14/2016
|
||||
BrownianTree3(size,lim)={
|
||||
my(Myx=matrix(size,size),sz=size-2,x,y,dx,dy,b=0);
|
||||
x=random(sz); y=random(sz); Myx[y,x]=1; \\ random seed
|
||||
print("*** START: ", x,"/",y);
|
||||
for(i=1,lim,
|
||||
x=random(sz); y=random(sz);
|
||||
b=0; \\ bumped not
|
||||
while(!b,
|
||||
dx=random(3)-1; dy=random(3)-1;
|
||||
if(!insm(Myx,x+dx,y+dy), x=random(sz); y=random(sz),
|
||||
if(Myx[y+dy,x+dx]==1, Myx[y,x]=1; b=1, x+=dx; y+=dy);
|
||||
);
|
||||
);\\wend
|
||||
);\\fend i
|
||||
plotmat(Myx);
|
||||
}
|
||||
{\\ Executing:
|
||||
BrownianTree3(400,5000);
|
||||
}
|
||||
27
Task/Brownian-tree/PARI-GP/brownian-tree-5.pari
Normal file
27
Task/Brownian-tree/PARI-GP/brownian-tree-5.pari
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
\\ 3/17/2016
|
||||
\\ s=1/2(random seed/seed in the center); p=0..n (level of the "deep" checking).
|
||||
BrownianTree4(size,lim,s=1,p=0)={
|
||||
my(Myx=matrix(size,size),sz=size-3,x,y);
|
||||
\\ seed s=1 for BTPB1, s=2 for BTPB2, BTPB3
|
||||
if(s==1,x=random(sz); y=random(sz), x=sz\2; y=sz\2); Myx[y,x]=1;
|
||||
print(" *** START: ",x,"/",y);
|
||||
for(i=1,lim,
|
||||
if(!(i==1&&s==2), x=random(sz)+1; y=random(sz)+1);
|
||||
while(insm(Myx,x,y,1)&&
|
||||
(Myx[y+1,x+1]+Myx[y+1,x]+Myx[y+1,x-1]+Myx[y,x+1]+
|
||||
Myx[y-1,x-1]+Myx[y,x-1]+Myx[y-1,x]+Myx[y-1,x+1])==0,
|
||||
x+=random(3)-1; y+=random(3)-1;
|
||||
\\ p=0 for BTPB1, BTPB2; p=5 for BTPB3
|
||||
if(!insm(Myx,x,y,p), x=random(sz)+1; y=random(sz)+1;);
|
||||
);\\wend
|
||||
Myx[y,x]=1;
|
||||
);\\fend i
|
||||
plotmat(Myx);
|
||||
}
|
||||
|
||||
{
|
||||
\\ Executing:
|
||||
BrownianTree4(200,4000); \\BTPB1.png
|
||||
BrownianTree4(200,4000,2); \\BTPB2.png
|
||||
BrownianTree4(200,4000,2,5); \\BTPB3.png
|
||||
}
|
||||
37
Task/Brownian-tree/Processing/brownian-tree
Normal file
37
Task/Brownian-tree/Processing/brownian-tree
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
boolean SIDESTICK = false;
|
||||
boolean[][] isTaken;
|
||||
|
||||
void setup() {
|
||||
size(512, 512);
|
||||
isTaken = new boolean[width][height];
|
||||
isTaken[width/2][height/2] = true;
|
||||
}
|
||||
|
||||
void draw() {
|
||||
for (int i = 0; i < width*height; i++) {
|
||||
int x = floor(random(width));
|
||||
int y = floor(random(height));
|
||||
if (isTaken[x][y]) { continue; }
|
||||
while (true) {
|
||||
int xp = x + floor(random(-1, 2));
|
||||
int yp = y + floor(random(-1, 2));
|
||||
boolean iscontained = (
|
||||
0 <= xp && xp < width &&
|
||||
0 <= yp && yp < height
|
||||
);
|
||||
if (iscontained && !isTaken[xp][yp]) {
|
||||
x = xp;
|
||||
y = yp;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
if (SIDESTICK || (iscontained && isTaken[xp][yp])) {
|
||||
isTaken[x][y] = true;
|
||||
set(x, y, #000000);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
noLoop();
|
||||
}
|
||||
|
|
@ -1,105 +1,105 @@
|
|||
/*REXX program shows Brownian motion of dust in a field with one seed.*/
|
||||
parse arg height width motes randSeed . /*get args from the C.L. */
|
||||
if height=='' | height==',' then height=0 /*None? Use the default*/
|
||||
if width=='' | width==',' then width=0 /* " " " " */
|
||||
if motes=='' | motes==',' then motes='10%' /*% dust motes in field, */
|
||||
/* ··· otherwise just the number.*/
|
||||
tree = '*' /*an affixed dust speck (tree). */
|
||||
mote = '·' /*char for a loose mote (of dust)*/
|
||||
hole = ' ' /*char for an empty spot in field*/
|
||||
clearScr = 'CLS' /*(DOS?) command to clear screen.*/
|
||||
eons = 1000000 /* # cycles for Brownian movement*/
|
||||
snapshot = 0 /*every n winks, show snapshot.*/
|
||||
snaptime = 1 /*every n secs, show snapshot.*/
|
||||
seedPos = 30 45 /*place seed in this field pos. */
|
||||
seedPos = 0 /*if =0, use middle of the field.*/
|
||||
/*if -1, use a random placement. */
|
||||
/*otherwise, place it at seedPos.*/
|
||||
/*set RANDSEED for repeatability.*/
|
||||
if datatype(randSeed,'W') then call random ,,randSeed /*if #, use it*/
|
||||
/* [↑] set the 1st random number*/
|
||||
if height==0 | width==0 then _=scrsize() /*not all REXXes have SCRSIZE.*/
|
||||
if height==0 then height=word(_,1)-3 /*adjust for border.*/
|
||||
if width==0 then width=word(_,2)-1 /* " " " */
|
||||
/*REXX program animates and displays Brownian motion of dust in a field (with one seed).*/
|
||||
parse arg height width motes randSeed . /*get args from the C.L. */
|
||||
if height=='' | height=="," then height=0 /*Not specified? Then use the default.*/
|
||||
if width=='' | width=="," then width=0 /* " " " " " " */
|
||||
if motes=='' | motes=="," then motes='10%' /*The % dust motes in the field, */
|
||||
/* [↑] either a # -or- a # with a %.*/
|
||||
tree = '*' /*an affixed dust speck, start of tree.*/
|
||||
mote = '·' /*character for a loose mote (of dust).*/
|
||||
hole = ' ' /* " " an empty spot in field.*/
|
||||
clearScr = 'CLS' /*(DOS) command to clear the screen. */
|
||||
eons = 1000000 /*number cycles for Brownian movement.*/
|
||||
snapshot = 0 /*every N winks, display a snapshot.*/
|
||||
snaptime = 1 /* " " secs, " " " */
|
||||
seedPos = 30 45 /*place a seed in this field position. */
|
||||
seedPos = 0 /*if =0, then use middle of the field.*/
|
||||
/* " -1, " " a random placement.*/
|
||||
/*otherwise, place the seed at seedPos.*/
|
||||
/*use RANDSEED for RANDOM repeatability*/
|
||||
if datatype(randSeed,'W') then call random ,,randSeed /*if an integer, use the seed.*/
|
||||
/* [↑] set the first random number. */
|
||||
if height==0 | width==0 then _=scrsize() /*Note: not all REXXes have SCRSIZE BIF*/
|
||||
if height==0 then height=word(_,1)-3 /*adjust useable height for the border.*/
|
||||
if width==0 then width=word(_,2)-1 /* " " width " " " */
|
||||
|
||||
seedAt=seedPos
|
||||
if seedPos== 0 then seedAt=width%2 height%2
|
||||
if seedPos==-1 then seedAt=random(1,width) random(1,height)
|
||||
parse var seedAt xs ys . /*obtain X & Y seed coördinates*/
|
||||
/* [↓] if right-most≡'%', use %.*/
|
||||
if right(motes,1)=='%' then motes=height * width * strip(motes,,'%') %100
|
||||
@.=hole /*create the field, all empty. */
|
||||
if seedPos== 0 then seedAt=width%2 height%2 /*if it's a zero, start in the middle.*/
|
||||
if seedPos==-1 then seedAt=random(1,width) random(1,height) /*if negative, use random.*/
|
||||
parse var seedAt xs ys . /*obtain the X and Y seed coördinates*/
|
||||
/* [↓] if right-most ≡ '%', then use %*/
|
||||
if right(motes,1)=='%' then motes=height * width * strip(motes,,'%') % 100
|
||||
@.=hole /*create the Brownian field, all empty.*/
|
||||
|
||||
do j=1 for motes /*sprinkle # dust motes randomly.*/
|
||||
do j=1 for motes /*sprinkle a # of dust motes randomly.*/
|
||||
rx=random(1, width); ry=random(1,height); @.rx.ry=mote
|
||||
end /*j*/ /* [↑] place a mote at random. */
|
||||
/*plant the seed from which the */
|
||||
/*tree will grow from dust motes */
|
||||
@.xs.ys=tree /*that affixed themselves. */
|
||||
call show /*show field before we mess it up*/
|
||||
tim=0 /*the time (in secs) of last show*/
|
||||
loX=1; hiX= width /*used to optimize mote searching*/
|
||||
loY=1; hiY=height /* " " " " " */
|
||||
end /*j*/ /* [↑] place a mote at random in field*/
|
||||
/*plant the seed from which the tree */
|
||||
/* will grow from dust motes that */
|
||||
@.xs.ys=tree /* affixed themselves to others. */
|
||||
call show /*show field before we mess it up again*/
|
||||
tim=0 /*the time in seconds of last display. */
|
||||
loX=1; hiX= width /*used to optimize the mote searching.*/
|
||||
loY=1; hiY=height /* " " " " " " */
|
||||
|
||||
/*═════════════════════════════soooo, this is Brownian motion.*/
|
||||
do winks=1 for eons until \motion /*EONs is used instead of ∞. */
|
||||
motion=0 /*turn off Brownian motion flag. */
|
||||
/*═══════════════════════════════════════ soooo, this is Brownian motion. */
|
||||
do winks=1 for eons until \motion /*EONs is used instead of ∞, close 'nuf*/
|
||||
motion=0 /*turn off the Brownian motion flag. */
|
||||
if snapshot\==0 then if winks//snapshot==0 then call show
|
||||
if snaptime\==0 then do; t=time('S')
|
||||
if t\==tim & t//snaptime==0 then do
|
||||
tim=time('s')
|
||||
call show
|
||||
end
|
||||
if t\==tim & t//snaptime==0 then do; tim=time('s')
|
||||
call show
|
||||
end
|
||||
end
|
||||
minX=loX; maxX=hiX /*as the tree grows, the search */
|
||||
minY=loY; maxY=hiY /* for dust motes gets faster. */
|
||||
loX= width; hiX=1 /*used to limit mote searching. */
|
||||
loY=height; hiY=1 /* " " " " " */
|
||||
minX=loX; maxX=hiX /*as the tree grows, the search for */
|
||||
minY=loY; maxY=hiY /* dust motes gets faster. */
|
||||
loX= width; hiX=1 /*used to limit the mote searching. */
|
||||
loY=height; hiY=1 /* " " " " " " */
|
||||
|
||||
do x =minX to maxX; xm=x-1; xp=x+1
|
||||
do y=minY to maxY; if @.x.y\==mote then iterate
|
||||
if x<loX then loX=x; if x>hiX then hiX=x /*is faster than: hiX=max(X hiX) */
|
||||
if y<loY then loY=y; if y>hiY then hiY=y /*is faster than: hiY=max(y hiY) */
|
||||
if @.xm.y ==tree then do; @.x.y=tree; iterate; end /*neighbor?*/
|
||||
if @.xp.y ==tree then do; @.x.y=tree; iterate; end /*neighbor?*/
|
||||
do x =minX to maxX; xm=x-1; xp=x+1 /*a couple handy-dandy values*/
|
||||
do y=minY to maxY; if @.x.y\==mote then iterate /*Not a mote: keep looking. */
|
||||
if x<loX then loX=x; if x>hiX then hiX=x /*faster than: hiX=max(X hiX)*/
|
||||
if y<loY then loY=y; if y>hiY then hiY=y /*faster than: hiY=max(y hiY)*/
|
||||
if @.xm.y ==tree then do; @.x.y=tree; iterate; end /*neighbor?*/
|
||||
if @.xp.y ==tree then do; @.x.y=tree; iterate; end /*neighbor?*/
|
||||
ym=y-1
|
||||
if @.x.ym ==tree then do; @.x.y=tree; iterate; end /*neighbor?*/
|
||||
if @.xm.ym==tree then do; @.x.y=tree; iterate; end /*neighbor?*/
|
||||
if @.xp.ym==tree then do; @.x.y=tree; iterate; end /*neighbor?*/
|
||||
if @.x.ym ==tree then do; @.x.y=tree; iterate; end /*neighbor?*/
|
||||
if @.xm.ym==tree then do; @.x.y=tree; iterate; end /*neighbor?*/
|
||||
if @.xp.ym==tree then do; @.x.y=tree; iterate; end /*neighbor?*/
|
||||
yp=y+1
|
||||
if @.x.yp ==tree then do; @.x.y=tree; iterate; end /*neighbor?*/
|
||||
if @.xm.yp==tree then do; @.x.y=tree; iterate; end /*neighbor?*/
|
||||
if @.xp.yp==tree then do; @.x.y=tree; iterate; end /*neighbor?*/
|
||||
motion=1 /* [↓] Brownian motion is coming.*/
|
||||
xb=x+random(1,3)-2 /* apply Brownian motion for X.*/
|
||||
yb=y+random(1,3)-2 /* " " " " Y.*/
|
||||
if @.xb.yb\==hole then iterate /*can mote actually move there ? */
|
||||
@.x.y=hole /*empty out the old mote position*/
|
||||
@.xb.yb=mote /*move the mote (or possibly not)*/
|
||||
if xb<loX then loX=max(1,xb); if xb>hiX then hiX=min( width, xb)
|
||||
if yb<loY then loY=max(1,yb); if yb>hiY then hiY=min(height, yb)
|
||||
end /*y*/ /* [↑] limit the motes movement.*/
|
||||
if @.x.yp ==tree then do; @.x.y=tree; iterate; end /*neighbor?*/
|
||||
if @.xm.yp==tree then do; @.x.y=tree; iterate; end /*neighbor?*/
|
||||
if @.xp.yp==tree then do; @.x.y=tree; iterate; end /*neighbor?*/
|
||||
motion=1 /* [↓] Brownian motion is coming. */
|
||||
xb=x + random(1, 3) - 2 /* apply Brownian motion for X. */
|
||||
yb=y + random(1, 3) - 2 /* " " " " Y. */
|
||||
if @.xb.yb\==hole then iterate /*can the mote actually move to there ?*/
|
||||
@.x.y=hole /*"empty out" the old mote position. */
|
||||
@.xb.yb=mote /*move the mote (or possibly not). */
|
||||
if xb<loX then loX=max(1, xb); if xb>hiX then hiX=min( width, xb)
|
||||
if yb<loY then loY=max(1, yb); if yb>hiY then hiY=min(height, yb)
|
||||
end /*y*/ /* [↑] limit mote's movement to field.*/
|
||||
end /*x*/
|
||||
call crop /*crops/truncates the mote field.*/
|
||||
|
||||
call crop /*crops (or truncates) the mote field.*/
|
||||
end /*winks*/
|
||||
|
||||
call show
|
||||
exit /*stick a fork in it, we're done.*/
|
||||
/*────────────────────────────────CROP subroutine───────────────────────*/
|
||||
crop: if loX>1 & hiX<width & loY>1 & hiY<height then return /*cropping?*/
|
||||
|
||||
do yc=-1 to height+1 by height+2 /*delete motes (moved off field).*/
|
||||
do xc=-1 to width+1; if @.xc.yc==hole then iterate; @.xc.yc=hole
|
||||
end /*xc*/
|
||||
end /*yc*/
|
||||
|
||||
do xc=-1 to width+1 by width+2 /*delete motes (moved off field).*/
|
||||
do yc=-1 to height+1; if @.xc.yc==hole then iterate; @.xc.yc=hole
|
||||
end /*yc*/
|
||||
end /*xc*/
|
||||
return
|
||||
/*────────────────────────────────SHOW subroutine───────────────────────*/
|
||||
show: clearScr /*not necessary, but speeds it up*/
|
||||
exit /*stick a fork in it, we're all done. */
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
crop: if loX>1 & hiX<width & loY>1 & hiY<height then return /*are we cropping?*/
|
||||
/* [↓] delete motes (moved off field).*/
|
||||
do yc=-1 to height+1 by height+2
|
||||
do xc=-1 to width+1; if @.xc.yc==hole then iterate; @.xc.yc=hole
|
||||
end /*xc*/
|
||||
end /*yc*/
|
||||
/* [↓] delete motes (moved off field).*/
|
||||
do xc=-1 to width+1 by width+2
|
||||
do yc=-1 to height+1; if @.xc.yc==hole then iterate; @.xc.yc=hole
|
||||
end /*yc*/
|
||||
end /*xc*/
|
||||
return
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
show: clearScr /*¬ necessary, but everything speeds up*/
|
||||
do ys=height for height by -1; aRow=
|
||||
do xs=1 for width; aRow=aRow || @.xs.ys
|
||||
end /*xs*/
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
numParticles = 3000
|
||||
dim canvas(201,201)
|
||||
graphic #g, 200,200
|
||||
#g fill("blue")
|
||||
canvas(rnd(1) * 100 , rnd(1) * 200) = 1 'start point
|
||||
for i = 1 To numParticles
|
||||
x = (rnd(1) * 199) + 1
|
||||
y = (rnd(1) * 199) + 1
|
||||
|
||||
while canvas(x+1, y+1) + canvas(x, y+1)+canvas(x+1, y)+canvas(x-1, y-1)+canvas(x-1, y)+canvas(x, y-1) = 0
|
||||
while canvas(x+1, y+1)+canvas(x, y+1)+canvas(x+1, y)+canvas(x-1, y-1)+canvas(x-1, y)+canvas(x, y-1) = 0
|
||||
x = x + (rnd(1)* 2) + 1
|
||||
y = y + (rnd(1)* 2) + 1
|
||||
If x < 1 Or x > 200 Or y < 1 Or y > 200 then
|
||||
|
|
@ -14,13 +15,7 @@ for i = 1 To numParticles
|
|||
end if
|
||||
wend
|
||||
canvas(x,y) = 1
|
||||
#g "color green ; set "; x; " "; y
|
||||
next i
|
||||
|
||||
graphic #g, 200,200
|
||||
for x = 1 to 200
|
||||
for y = 1 to 200
|
||||
if canvas(x,y) = 1 then #g "color green ; set "; x; " "; y else #g "color blue ; set "; x; " "; y
|
||||
next y
|
||||
next x
|
||||
render #g
|
||||
#g "flush"
|
||||
|
|
|
|||
107
Task/Brownian-tree/Rust/brownian-tree.rust
Normal file
107
Task/Brownian-tree/Rust/brownian-tree.rust
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
extern crate image;
|
||||
extern crate rand;
|
||||
|
||||
use image::ColorType;
|
||||
use rand::distributions::{IndependentSample, Range};
|
||||
use std::cmp::{min, max};
|
||||
use std::env;
|
||||
use std::path::Path;
|
||||
use std::process;
|
||||
|
||||
fn help() {
|
||||
println!("Usage: brownian_tree <output_path> <mote_count> <edge_length>");
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
let mut output_path = Path::new("out.png");
|
||||
let mut mote_count: u32 = 10000;
|
||||
let mut width: usize = 512;
|
||||
let mut height: usize = 512;
|
||||
|
||||
match args.len() {
|
||||
1 => {}
|
||||
4 => {
|
||||
output_path = Path::new(&args[1]);
|
||||
mote_count = args[2].parse::<u32>().unwrap();
|
||||
width = args[3].parse::<usize>().unwrap();
|
||||
height = width;
|
||||
}
|
||||
_ => {
|
||||
help();
|
||||
process::exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
assert!(width >= 2);
|
||||
|
||||
// Base 1d array
|
||||
let mut field_raw = vec![0u8; width * height];
|
||||
populate_tree(&mut field_raw, width, height, mote_count);
|
||||
|
||||
// Balance image for 8-bit grayscale
|
||||
let our_max = field_raw.iter().fold(0u8, |champ, e| max(champ, *e));
|
||||
let fudge = std::u8::MAX / our_max;
|
||||
let balanced: Vec<u8> = field_raw.iter().map(|e| e * fudge).collect();
|
||||
|
||||
match image::save_buffer(output_path,
|
||||
&balanced,
|
||||
width as u32,
|
||||
height as u32,
|
||||
ColorType::Gray(8)) {
|
||||
Err(e) => println!("Error writing output image:\n{}", e),
|
||||
Ok(_) => println!("Output written to:\n{}", output_path.to_str().unwrap()),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn populate_tree(raw: &mut Vec<u8>, width: usize, height: usize, mc: u32) {
|
||||
// Vector of 'width' elements slices
|
||||
let mut field_base: Vec<_> = raw.as_mut_slice().chunks_mut(width).collect();
|
||||
// Addressable 2d vector
|
||||
let mut field: &mut [&mut [u8]] = field_base.as_mut_slice();
|
||||
|
||||
// Seed mote
|
||||
field[width / 2][height / 2] = 1;
|
||||
|
||||
let walk_range = Range::new(-1i32, 2i32);
|
||||
let x_spawn_range = Range::new(1usize, width - 1);
|
||||
let y_spawn_range = Range::new(1usize, height - 1);
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
for i in 0..mc {
|
||||
if i % 100 == 0 {
|
||||
println!("{}", i)
|
||||
}
|
||||
|
||||
// Spawn mote
|
||||
let mut x = x_spawn_range.ind_sample(&mut rng);
|
||||
let mut y = y_spawn_range.ind_sample(&mut rng);
|
||||
|
||||
// Increment field value when motes spawn on top of the structure
|
||||
if field[x][y] > 0 {
|
||||
field[x][y] = min(field[x][y] as u32 + 1, std::u8::MAX as u32) as u8;
|
||||
continue;
|
||||
}
|
||||
|
||||
loop {
|
||||
let contacts = field[x - 1][y - 1] + field[x][y - 1] + field[x + 1][y - 1] +
|
||||
field[x - 1][y] + field[x + 1][y] +
|
||||
field[x - 1][y + 1] + field[x][y + 1] +
|
||||
field[x + 1][y + 1];
|
||||
|
||||
if contacts > 0 {
|
||||
field[x][y] = 1;
|
||||
break;
|
||||
} else {
|
||||
let xw = walk_range.ind_sample(&mut rng) + x as i32;
|
||||
let yw = walk_range.ind_sample(&mut rng) + y as i32;
|
||||
if xw < 1 || xw >= (width as i32 - 1) || yw < 1 || yw >= (height as i32 - 1) {
|
||||
break;
|
||||
}
|
||||
x = xw as usize;
|
||||
y = yw as usize;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
16
Task/Brownian-tree/ZX-Spectrum-Basic/brownian-tree.zx
Normal file
16
Task/Brownian-tree/ZX-Spectrum-Basic/brownian-tree.zx
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
10 LET np=1000
|
||||
20 PAPER 0: INK 4: CLS
|
||||
30 PLOT 128,88
|
||||
40 FOR i=1 TO np
|
||||
50 GO SUB 1000
|
||||
60 IF NOT ((POINT (x+1,y+1)+POINT (x,y+1)+POINT (x+1,y)+POINT (x-1,y-1)+POINT (x-1,y)+POINT (x,y-1))=0) THEN GO TO 100
|
||||
70 LET x=x+RND*2-1: LET y=y+RND*2-1
|
||||
80 IF x<1 OR x>254 OR y<1 OR y>174 THEN GO SUB 1000
|
||||
90 GO TO 60
|
||||
100 PLOT x,y
|
||||
110 NEXT i
|
||||
120 STOP
|
||||
1000 REM Calculate new pos
|
||||
1010 LET x=RND*254
|
||||
1020 LET y=RND*174
|
||||
1030 RETURN
|
||||
Loading…
Add table
Add a link
Reference in a new issue