Abelian sandpile model: Difference between revisions

m
m (→‎{{header|Perl}}: future-proof for 5.36, use new bitwise string operators)
 
(16 intermediate revisions by 11 users not shown)
Line 1:
{{task}}{{wikipedia|Abelian sandpile model}} [[Category:Cellular automata]]
<br>
Implement the '''Abelian sandpile model''' also known as '''Bak–Tang–Wiesenfeld model'''. Its history, mathematical definition and properties can be found under its [https://en.wikipedia.org/wiki/Abelian_sandpile_model wikipedia article].
Line 69:
simulate(&grid)
 
V ppm = File(‘sand_pile.ppm’, ‘w’WRITE)
ppm.write_bytes(("P6\n#. #.\n255\n".format(grid.len, grid.len)).encode())
V colors = [[Byte(0), 0, 0],
Line 336:
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
</pre>
 
=={{header|ALGOL 68}}==
Using code from the [[Abelian sandpile model/Identity]] task.
<syntaxhighlight lang="algol68">
BEGIN # model Abelian sandpiles #
# returns TRUE if the sandpile s is stable, FALSE otherwise #
OP STABLE = ( [,]INT s )BOOL:
BEGIN
BOOL result := TRUE;
FOR i FROM 1 LWB s TO 1 UPB s WHILE result DO
FOR j FROM 2 LWB s TO 2 UPB s WHILE result := s[ i, j ] < 4 DO SKIP OD
OD;
result
END # STABLE # ;
# returns the sandpile s after avalanches #
OP AVALANCHE = ( [,]INT s )[,]INT:
BEGIN
[ 1 : 1 UPB s, 1 : 2 UPB s ]INT result := s[ AT 1, AT 1 ];
WHILE BOOL had avalanche := FALSE;
FOR i TO 1 UPB s DO
FOR j TO 2 UPB s DO
IF result[ i, j ] >= 4 THEN
# unstable pile #
had avalanche := TRUE;
result[ i, j ] -:= 4;
IF i > 1 THEN result[ i - 1, j ] +:= 1 FI;
IF i < 1 UPB s THEN result[ i + 1, j ] +:= 1 FI;
IF j > 1 THEN result[ i, j - 1 ] +:= 1 FI;
IF j < 2 UPB s THEN result[ i, j + 1 ] +:= 1 FI
FI
OD
OD;
had avalanche
DO SKIP OD;
result
END # AVALANCHE # ;
# returns the maximum element of s #
OP MAX = ( [,]INT s )INT:
BEGIN
INT result := s[ 1 LWB s, 2 LWB s ];
FOR i FROM 1 LWB s TO 1 UPB s DO
FOR j FROM 2 LWB s TO 2 UPB s DO
IF s[ i, j ] > result THEN result := s[ i, j ] FI
OD
OD;
result
END # MAX # ;
# prints the sandpile s #
PROC show sandpile = ( STRING title, [,]INT s )VOID:
BEGIN
print( ( title, newline ) );
IF 1 UPB s >= 1 LWB s AND 2 UPB s >= 2 LWB s THEN
# non-empty sandpile #
INT width := 1; # find tthe width needed for each element #
INT v := MAX s;
WHILE v > 9 DO
v OVERAB 10;
width +:= 1
OD;
FOR i TO 1 UPB s DO
FOR j TO 2 UPB s DO
print( ( " ", whole( s[ i, j ], - width ) ) )
OD;
print( ( newline ) )
OD
FI
END # show sandpile # ;
# printys a sandpile before and after the avalanches #
PROC show sandpile before and after = ( [,]INT s )VOID:
BEGIN
[ 1 LWB s : 1 UPB s, 2 LWB s : 2 UPB s ]INT t := s;
show sandpile( "before: ", t );
WHILE NOT STABLE t DO
t := AVALANCHE t
OD;
show sandpile( "after: ", t );
print( ( newline ) )
END # show sandpile before and after # ;
# task test case #
[,]INT s1 = ( ( 0, 0, 0, 0, 0 )
, ( 0, 0, 0, 0, 0 )
, ( 0, 0, 16, 0, 0 )
, ( 0, 0, 0, 0, 0 )
, ( 0, 0, 0, 0, 0 )
);
show sandpile before and after( s1 );
# test case from 11l, C, etc. #
[ 1 : 10, 1 : 10 ]INT s2;
FOR i FROM 1 LWB s2 TO 1 UPB s2 DO
FOR j FROM 2 LWB s2 TO 2 UPB s2 DO
s2[ i, j ] := 0
OD
OD;
s2[ 6, 6 ] := 64;
show sandpile before and after( s2 )
END
</syntaxhighlight>
{{out}}
<pre>
before:
0 0 0 0 0
0 0 0 0 0
0 0 16 0 0
0 0 0 0 0
0 0 0 0 0
after:
0 0 1 0 0
0 2 1 2 0
1 1 0 1 1
0 2 1 2 0
0 0 1 0 0
 
before:
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 64 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
after:
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 1 2 1 0 0 0
0 0 0 2 2 2 2 2 0 0
0 0 1 2 2 2 2 2 1 0
0 0 2 2 2 0 2 2 2 0
0 0 1 2 2 2 2 2 1 0
0 0 0 2 2 2 2 2 0 0
0 0 0 0 1 2 1 0 0 0
0 0 0 0 0 0 0 0 0 0
</pre>
 
Line 1,287 ⟶ 1,422:
=={{header|Fōrmulæ}}==
 
{{FormulaeEntry|page=https://formulae.org/?script=examples/Abelian_sandpile_model}}
Fōrmulæ programs are not textual, visualization/edition of programs is done showing/manipulating structures but not text. Moreover, there can be multiple visual representations of the same program. Even though it is possible to have textual representation &mdash;i.e. XML, JSON&mdash; they are intended for storage and transfer purposes more than visualization and edition.
 
Programs in Fōrmulæ are created/edited online in its [https://formulae.org website], However they run on execution servers. By default remote servers are used, but they are limited in memory and processing power, since they are intended for demonstration and casual use. A local server can be downloaded and installed, it has no limitations (it runs in your own computer). Because of that, example programs can be fully visualized and edited, but some of them will not run if they require a moderate or heavy computation/memory resources, and no local server is being used.
 
In '''[https://formulae.org/?example=Abelian_sandpile_model this]''' page you can see the program(s) related to this task and their results.
 
=={{header|F_Sharp|F#}}==
Line 1,384 ⟶ 1,515:
</pre>
 
=={{header|FutureBasic}}==
<syntaxhighlight lang="futurebasic">
_mFile = 1
begin enum
_iClose
end enum
 
_window = 1
begin enum 1
_gridView
_gridSizeLabel
_gridSizeFld
_centerNumLabel
_centerNumFld
_colorRadio
_monoRadio
_avalancheBtn
end enum
 
 
void local fn BuildMenu
menu _mFile,,, @"File"
menu _mFile, _iClose,, @"Close", @"w"
MenuItemSetAction( _mFile, _iClose, @"performClose:" )
end fn
 
 
void local fn BuildWindow
window _window, @"Abelian Sandpile Model", (0,0,513,360), NSWindowStyleMaskTitled + NSWindowStyleMaskClosable + NSWindowStyleMaskMiniaturizable
subclass view _gridView, (20,20,320,320)
textlabel _gridSizeLabel, @"Grid size:", (385,322,61,16)
textfield _gridSizeFld,, @"5", (452,319,41,21)
ControlSetFormat( _gridSizeFld, @"0123456789", YES, 4, 0 )
textlabel _centerNumLabel, @"Center number:", (347,285,99,16)
textfield _centerNumFld,, @"32", (452,282,41,21)
ControlSetFormat( _centerNumFld, @"0123456789", YES, 4, 0 )
radiobutton _colorRadio,, NSControlStateValueOn, @"Color", (367,249,59,18)
radiobutton _monoRadio,, NSControlStateValueOff, @"Mono", (432,249,61,18)
button _avalancheBtn,,, @"Avalanche", (375,13,96,32)
WindowMakeFirstResponder( _window, _gridSizeFld )
end fn
 
 
void local fn ViewDrawRect
long gridSize = fn ControlIntegerValue(_gridSizeFld)
CGRect bounds = fn ViewBounds( _gridView )
CGFloat cellSize = bounds.size.width/gridSize
ColorRef col0 = fn ColorWhite, col1, col2, col3
long r, c, value
CGFloat x = 0, y = 0
ColorRef color
if ( fn ButtonState( _colorRadio ) == NSControlStateValueOn )
col1 = fn ColorRed
col2 = fn ColorGreen
col3 = fn ColorBlue
else
col1 = fn ColorWithRGB( 0.25, 0.25, 0.25, 1.0 )
col2 = fn ColorWithRGB( 0.5, 0.5, 0.5, 1.0 )
col3 = fn ColorWithRGB( 0.75, 0.75, 0.75, 1.0 )
end if
for r = 0 to gridSize-1
for c = 0 to gridSize-1
value = mda_integer(r,c)
select ( value )
case 1 : color = col1
case 2 : color = col2
case 3 : color = col3
case else : color = col0
end select
BezierPathFillRect( fn CGRectMake( x, y, cellSize, cellSize ), color )
x += cellSize
next
x = 0
y += cellSize
next
end fn
 
 
void local fn AvalancheAction
long r, c, gridSize = fn ControlIntegerValue(_gridSizeFld)
long centerNum = fn ControlIntegerValue(_centerNumFld)
long midNum = gridSize/2
long limit = gridSize-1
BOOL stable = NO
long value
// initialize array
mda_kill
for r = 0 to gridSize-1
for c = 0 to gridSize-1
mda(r,c) = 0
next
next
mda(midNum,midNum) = centerNum
// collapse
while ( stable == NO )
stable = YES
for r = 0 to gridSize-1
for c = 0 to gridSize-1
value = mda_integer(r,c)
if ( value > 3 )
mda(r,c) = @(mda_integer(r,c)-4)
if ( r > 0 ) then mda(r-1,c) = @(mda_integer(r-1,c) + 1)
if ( r < limit ) then mda(r+1,c) = @(mda_integer(r+1,c) + 1)
if ( c > 0 ) then mda(r,c-1) = @(mda_integer(r,c-1) + 1)
if ( c < limit ) then mda(r,c+1) = @(mda_integer(r,c+1) + 1)
stable = NO : break
end if
next
if ( stable == NO ) then break
next
wend
ViewSetNeedsDisplay( _gridView )
end fn
 
 
void local fn DoAppEvent( ev as long )
select ( ev )
case _appWillFinishLaunching
fn BuildMenu
fn BuildWindow
fn AvalancheAction
case _appShouldTerminateAfterLastWindowClosed : AppEventSetBool(YES)
end select
end fn
 
void local fn DoDialog( ev as long, tag as long, wnd as long, obj as CFTypeRef )
select ( ev )
case _btnClick
select ( tag )
case _avalancheBtn : fn AvalancheAction
case _gridSizeFld, _centerNumFld : fn AvalancheAction
case _colorRadio, _monoRadio : ViewSetNeedsDisplay( _gridView )
end select
case _viewDrawRect : fn ViewDrawRect
end select
end fn
 
on appevent fn DoAppEvent
on dialog fn DoDialog
 
HandleEvents
</syntaxhighlight>
[[File:AbeliaSandpileModelFB.png]]
 
=={{header|Go}}==
Line 1,775 ⟶ 2,061:
{{out}}
[[Media:Abelian sandpile java.png]]
 
=={{header|jq}}==
''Adapted from [[#Wren|Wren]]''
 
'''Works with jq and gojq, the C and Go implementations of jq'''
 
For consistency with [[Abelian sandpile model/Identity#jq]], the
function for reducing a sandpile to its equilibrium position is called
`avalanche` here.
 
<syntaxhighlight lang=jq>
# Generic functions
def array($n): . as $in | [range(0;$n)|$in];
 
def when(filter; action): if filter // null then action else . end;
 
def lpad($len): tostring | ($len - length) as $l | (" " * $l) + .;
 
# module Sandpile
 
# 'a' is a list of integers in row order
def new($a):
($a|length) as $length
| ($length|sqrt|floor) as $rows
| if ($rows * $rows != $length) then "The matrix of values must be square." | error
else
{$a,
$rows,
neighbors:
(reduce range(0; $length) as $i (null;
.[$i] = []
| when($i % $rows > 0; .[$i] += [$i-1] )
| when(($i + 1) % $rows > 0; .[$i] += [$i+1] )
| when($i - $rows >= 0; .[$i] += [$i-$rows] )
| when($i + $rows < $length; .[$i] += [$i+$rows] ) ) )
}
end;
 
def isStable:
all(.a[]; . <= 3);
 
def tos:
. as $in
| .rows as $rows
| reduce range(0; $rows) as $i ("";
reduce range(0; $rows) as $j (.;
. + " \($in.a[$rows*$i + $j] | lpad(2))" )
| . +"\n" );
 
# just topple once so we can observe intermediate results
def topple:
last(
label $out
| foreach range(0; .a|length) as $i (.;
if .a[$i] > 3
then .a[$i] += -4
| reduce .neighbors[$i][] as $j (.; .a[$j] += 1)
| ., break $out
else .
end ) );
 
def avalanche:
until(isStable; topple);
 
# str1 and str2 should be strings representing a sandpile (i.e. .a)
def printAcross(str1; str2):
(str1|split("\n")) as $r1
| (str2|split("\n")) as $r2
| ($r1|length - 1) as $rows
| ($rows/2|floor) as $cr
| reduce range(0; $rows) as $i ("";
(if $i == $cr then "->" else " " end) as $symbol
| . + "\($r1[$i]) \($symbol) \($r2[$i])\n" ) ;
 
{ a1: (0|array(25))}
| .a2 = .a1
| .a3 = .a1
| .a1[12] = 4
| .a2[12] = 6
| .a3[12] = 16
| .a4 = (0|array(100))
| .a4[55] = 64
 
| (.a1, .a2, .a3, .a4) as $a
| .s = new($a)
| (.s|tos) as $str1
| .s |= avalanche
| (.s|tos) as $str2
| printAcross($str1; $str2)
</syntaxhighlight>
{{output}}
As for [[#Wren|Wren]]
 
 
=={{header|Julia}}==
Line 2,145 ⟶ 2,524:
000001222100000
000000000000000</pre>
 
=={{header|MiniScript}}==
For use with the [http://miniscript.org/MiniMicro Mini Micro].
<syntaxhighlight lang="miniscript">
colors = [color.black, color.yellow, color.orange,
color.brown, color.red, color.fuchsia,
color.purple, color.blue, color.navy]
 
rows = 48; rowRange = range(0, rows-1)
cols = 72; colRange = range(0, cols-1)
particlesOfSand = rows * cols
divBase = particlesOfSand / (colors.len - 4)
deltas = [[0,-1],[-1, 0], [1, 0],[0, 1]]
 
displayGrid = function(grid, td)
for y in globals.rowRange
for x in globals.colRange
colorIx = grid[y][x]
// determine the rest of the colors if > 3 by division
if colorIx > 3 then colorIx = (colorIx - 3) / divBase + 4
td.setCell x,y, colorIx
end for
end for
end function
 
clear
 
// Prepare a tile display
// Generate image used for the tiles from the defined above.
// The colors are to indicate height of a sand pile.
img = Image.create(colors.len, 1);
for i in range(0, colors.len - 1)
img.setPixel(i, 0, colors[i])
end for
 
grid = []
for y in rowRange
row = []
for x in colRange
row.push(0)
end for
grid.push(row)
end for
 
grid[rows/2][cols/2] = particlesOfSand
 
display(4).mode = displayMode.tile
td = display(4)
td.cellSize = 640/48 // size of cells on screen
td.extent = [cols, rows]
td.overlap = 0 // adds a small gap between cells
td.tileSet = img; td.tileSetTileSize = 1
td.clear 0
 
toTopple = []
for y in rowRange
for x in colRange
if grid[y][x] > 3 and toTopple.indexOf([x,y]) == null then toTopple.push([x,y])
end for
end for
tt = time
while toTopple.len > 0
nextGen = []
for cell in toTopple
x = cell[0]; y = cell[1]
grid[y][x] -= 4
for delta in deltas
x1 = (x + delta[0]) % cols; y1 = (y + delta[1]) % rows
grid[y1][x1] += 1
end for
end for
for y in rowRange
for x in colRange
if grid[y][x] > 3 and nextGen.indexOf([x,y]) == null then nextGen.push([x,y])
end for
end for
toTopple = nextGen
displayGrid(grid, td)
end while
key.get()
</syntaxhighlight>
[[File:Miniscript_abelian_sandpille.png|800px|thumb|center|Image for 3456 particles grid 48*72]]
 
=={{header|Nim}}==
Line 2,781 ⟶ 3,242:
<span style="color: #000000;">main</span><span style="color: #0000FF;">()</span>
<!--</syntaxhighlight>-->
 
=={{header|PicoLisp}}==
<syntaxhighlight lang="picolisp">
(load "@lib/simul.l")
(symbols 'simul 'pico)
(de sandpile (A B)
(let
(Grid (grid A A)
Size (/ (inc A) 2)
Center (get Grid Size Size)
Done T )
(for G Grid
(for This G
(=: V 0) ) )
(with Center
(=: V B)
(while Done
(off Done)
(for G Grid
(for This G
(when (>= (: V) 4)
(=: V (- (: V) 4))
(on Done)
(mapc
'((Dir)
(with (Dir This) (=: V (inc (: V)))) )
'(north south west east) ) ) ) ) ) )
(disp Grid 0
'((This) (if (: V) (pack " " @ " ") " ")) ) ) )
(sandpile 10 64)
</syntaxhighlight>
 
{{out}}
<pre>
+---+---+---+---+---+---+---+---+---+---+
10 | 0 0 0 0 0 0 0 0 0 0 |
+ + + + + + + + + + +
9 | 0 0 0 0 0 0 0 0 0 0 |
+ + + + + + + + + + +
8 | 0 0 0 1 2 1 0 0 0 0 |
+ + + + + + + + + + +
7 | 0 0 2 2 2 2 2 0 0 0 |
+ + + + + + + + + + +
6 | 0 1 2 2 2 2 2 1 0 0 |
+ + + + + + + + + + +
5 | 0 2 2 2 0 2 2 2 0 0 |
+ + + + + + + + + + +
4 | 0 1 2 2 2 2 2 1 0 0 |
+ + + + + + + + + + +
3 | 0 0 2 2 2 2 2 0 0 0 |
+ + + + + + + + + + +
2 | 0 0 0 1 2 1 0 0 0 0 |
+ + + + + + + + + + +
1 | 0 0 0 0 0 0 0 0 0 0 |
+---+---+---+---+---+---+---+---+---+---+
a b c d e f g h i j
</pre>
 
=={{header|Python}}==
Line 3,059 ⟶ 3,577:
## 0 0 0 0 0 0 0 0 0
</syntaxhighlight>
 
=={{header|R}}==
<syntaxhighlight lang="R" line>
# Return (x,y) index from a grid from an index in a list based on the grid size
pos_to_index <- function(n) {
f1 <- n/gridsize
col <- ifelse(n%%gridsize == 0, f1,as.integer(f1)+1)
row <- n - ((col-1)*gridsize)
list(row=row,col=col)
}
 
# Return adjacent indexes (north, east, south, west)
adjacent_indexes <- function(r,c) {
rup <- r - 1
rdn <- ifelse(r == gridsize,0,r + 1)
cleft <- c - 1
cright <- ifelse(c==gridsize,0,c+1)
list(up=c(rup,c),right=c(r,cright),left=c(r,cleft),down=c(rdn,c))
}
 
# Generate Abelian pattern
abelian <- function(gridsize,sand) {
mat_ <- matrix(rep(0,gridsize^2),gridsize)
midv <- as.integer(gridsize/2) + 1
mat_[midv,midv] <- sand
cat("Before\n")
print(mat_)
 
while(T) {
cnt <- cnt + 1
tgt <- which(mat_ >= 4)
if (length(tgt) == 0) break
pos <- pos_to_index(tgt[1])
idxes <- adjacent_indexes(pos$row,pos$col)
mat_[pos$row,pos$col] <- mat_[pos$row,pos$col] - 4
 
for (i in idxes) if (0 %in% i == F) mat_[i[1],i[2]] <- mat_[i[1],i[2]] +1
}
cat("After\n")
print(mat_)
}
 
# Main
 
abelian(10,64)
</syntaxhighlight>
 
'''Output:'''
<pre>
Before
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] 0 0 0 0 0 0 0 0 0 0
[2,] 0 0 0 0 0 0 0 0 0 0
[3,] 0 0 0 0 0 0 0 0 0 0
[4,] 0 0 0 0 0 0 0 0 0 0
[5,] 0 0 0 0 0 0 0 0 0 0
[6,] 0 0 0 0 0 64 0 0 0 0
[7,] 0 0 0 0 0 0 0 0 0 0
[8,] 0 0 0 0 0 0 0 0 0 0
[9,] 0 0 0 0 0 0 0 0 0 0
[10,] 0 0 0 0 0 0 0 0 0 0
After
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] 0 0 0 0 0 0 0 0 0 0
[2,] 0 0 0 0 0 0 0 0 0 0
[3,] 0 0 0 0 1 2 1 0 0 0
[4,] 0 0 0 2 2 2 2 2 0 0
[5,] 0 0 1 2 2 2 2 2 1 0
[6,] 0 0 2 2 2 0 2 2 2 0
[7,] 0 0 1 2 2 2 2 2 1 0
[8,] 0 0 0 2 2 2 2 2 0 0
[9,] 0 0 0 0 1 2 1 0 0 0
[10,] 0 0 0 0 0 0 0 0 0 0
</pre>
 
=={{header|Raku}}==
Line 3,216 ⟶ 3,808:
 
Passing in a stack size of 20000 results in: [https://github.com/thundergnat/rc/blob/master/img/Abelian-sandpile-sdl2.png Abelian-sandpile-sdl2.png] (offsite .png image)
 
=={{header|RPL}}==
Using the built-in matrix data structure fulfils the requirements of the task:
[[1 2 0][2 1 1][0 1 3]] [[2 1 3][1 0 1][0 1 0]] +
'''Output:'''
1: [[3 3 3]
[3 1 2]
[0 2 3]]
{| class="wikitable" ≪
! RPL code
! Comment
|-
|
≪ ROT OVER RE + { } + ROT ROT IM + +
≫ ‘<span style="color:blue">→IDX</span>’ STO
≪ DUP SIZE 1 GET → n
≪ '''DO'''
1 CF 1 n '''FOR''' h 1 n '''FOR''' j
'''IF''' DUP h j 2 →LIST GET 3 > '''THEN'''
1 SF DUP 0 CON
h j 2 →LIST -4 PUT
1 4 '''FOR''' a
h j (0,1) a ^ <span style="color:blue">→IDX</span>
'''IFERR''' 1 PUT '''THEN''' DROP2 '''END'''
'''NEXT''' +
'''END NEXT NEXT'''
'''UNTIL''' 1 FC? '''END'''
≫ ≫ ‘<span style="color:blue">SPILE</span>’ STO
|
<span style="color:blue">→IDX</span> ''( a b (c,d) → { a+c b+d } ) ''
<span style="color:blue">SPILE</span> ''( [[a]] → [[a]] ) ''
loop
for h, j = 1 to n
if a[h,j] > 3 then
set flag, create empty matrix b
b[h,j] = -4
for a = 1 to 4
(x,y) = (h,j) + i^a
b[x,y] = 1 only if x > 0 and y > 0
a += b
end if, next h, j
until all elements <= 3
return a
|}
It is sometimes necessary to run the program several times to reach stability: user's eye is much faster than a program to detect a remaining unstable sandpile. This is the way in RPL.
It may nevertheless make sense when working on large matrices to have to run the program only once. In this case, the addtional line below shall be inserted after the <code>END NEXT NEXT</code> line:
1 n '''FOR''' h 1 n '''FOR''' j '''IF''' DUP h j 2 →LIST GET 3 > '''THEN''' 1 SF '''END NEXT NEXT'''
 
{3 3} 3 CON '<span style="color:green">S3</span>' STO
[[2 1 2][1 0 1][2 1 2]] '<span style="color:green">S3ID</span>' STO
<span style="color:green">S3</span> <span style="color:green">S3ID</span> + <span style="color:blue">SPILE</span> <span style="color:blue">SPILE</span>
<span style="color:green">S3ID</span> DUP + <span style="color:blue">SPILE</span> <span style="color:blue">SPILE</span>
{{out}}
<pre>
2: [[ 3 3 3 ]
[ 3 3 3 ]
[ 3 3 3 ]]
1: [[ 2 1 2 ]
[ 1 0 1 ]
[ 2 1 2 ]]
</pre>
 
=={{header|Rust}}==
Line 3,360 ⟶ 4,016:
</pre>
 
=={{header|Scheme}}==
{{works with|Chez Scheme}}
Line 3,766 ⟶ 4,423:
=={{header|Wren}}==
{{libheader|Wren-fmt}}
<syntaxhighlight lang="ecmascriptwren">import "./fmt" for Fmt
 
class Sandpile {
3,028

edits