RosettaCodeData/Task/Brownian-tree/SequenceL/brownian-tree-1.sequencel
2023-07-01 13:44:08 -04:00

47 lines
1.5 KiB
Text

import <Utilities/Random.sl>;
import <Utilities/Sequence.sl>;
POINT ::= (X: int, Y: int);
RET_VAL ::= (World: int(2), Rand: RandomGenerator<int, int>, Point: POINT);
randomWalk(x, y, world(2), rand) :=
let
randX := getRandom(rand);
randY := getRandom(randX.Generator);
nextX := x + (randX.Value mod 3) - 1;
nextY := y + (randY.Value mod 3) - 1;
newStartX := (randX.Value mod (size(world) - 2)) + 2;
newStartY := (randY.Value mod (size(world) - 2)) + 2;
numNeighbors := world[y-1,x-1] + world[y-1,x] + world[y-1,x+1] +
world[y,x-1] + world[y,x+1] +
world[y+1,x-1] + world[y+1,x] + world[y+1,x+1];
outOfBounds := nextX <= 1 or nextY <= 1 or nextX >= size(world) or nextY >= size(world);
in
randomWalk(newStartX, newStartY, world, randY.Generator) when world[y,x] = 1 or outOfBounds
else
(X: x, Y: y) when numNeighbors > 0
else
randomWalk(nextX, nextY, world, randY.Generator);
step(rand, world(2)) :=
let
walkSeed := getRandom(rand);
newParticle := randomWalk(size(world)/2,size(world)/2, world, seedRandom(walkSeed.Value));
newWorld[j] :=
world[j] when j /= newParticle.Y
else
setElementAt(world[j], newParticle.X, 1);
in
(World: newWorld, Rand: walkSeed.Generator, Point: newParticle);
initialWorld(worldSize, seed) :=
let
world[i,j] := 1 when i = worldSize / 2 and j = worldSize / 2 else 0
foreach i within 1 ... worldSize,
j within 1 ... worldSize;
in
(World: world, Rand: seedRandom(seed), Point: (X: worldSize / 2, Y: worldSize / 2));