Abelian sandpile model: Difference between revisions

m
 
(48 intermediate revisions by 30 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 29:
0 0 0 0 0 0 0 1 0 0
</pre>
=={{header|11l}}==
<syntaxhighlight lang="11l">V grid = [[0] * 10] * 10
grid[5][5] = 64
 
print(‘Before:’)
L(row) grid
print(row.map(c -> ‘#3’.format(c)).join(‘’))
 
F simulate(&grid)
L
V changed = 0B
L(arr) grid
V ii = L.index
L(val) arr
V jj = L.index
I val > 3
grid[ii][jj] -= 4
I ii > 0
grid[ii - 1][jj]++
I ii < grid.len - 1
grid[ii + 1][jj]++
I jj > 0
grid[ii][jj - 1]++
I jj < grid.len - 1
grid[ii][jj + 1]++
changed = 1B
I !changed
L.break
 
simulate(&grid)
 
print("\nAfter:")
L(row) grid
print(row.map(c -> ‘#3’.format(c)).join(‘’))
 
grid = [[0] * 65] * 65
grid[32][32] = 64 * 64
 
simulate(&grid)
 
V ppm = File(‘sand_pile.ppm’, WRITE)
ppm.write_bytes(("P6\n#. #.\n255\n".format(grid.len, grid.len)).encode())
V colors = [[Byte(0), 0, 0],
[Byte(255), 0, 0],
[Byte(0), 255, 0],
[Byte(0), 0, 255]]
L(row) grid
L(c) row
ppm.write_bytes(colors[c])</syntaxhighlight>
 
{{out}}
<pre>
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>
 
=={{header|AArch64 Assembly}}==
{{works with|as|Raspberry Pi 3B version Buster 64 bits
or android 64 bits with application Termux }}
<syntaxhighlight lang="aarch64 assembly">
/* ARM assembly AARCH64 Raspberry PI 3B or android 64 bits */
/* program abelian64.s */
 
/* run : abelian 256 12 12 */
 
/*******************************************/
/* Constantes file */
/*******************************************/
/* for this file see task include a file in language AArch64 assembly*/
.include "../includeConstantesARM64.inc"
.equ MAXI, 25
 
/*********************************/
/* Initialized data */
/*********************************/
.data
szMessValue: .asciz "@ "
szMessErrParam: .asciz "error : command line = abelian size posx posy \n"
szMessFin: .asciz "End display :\n"
szCarriageReturn: .asciz "\n"
/*********************************/
/* UnInitialized data */
/*********************************/
.bss
sZoneConv: .skip 24
iSandPile: .skip 8 * MAXI * MAXI
/*********************************/
/* code section */
/*********************************/
.text
.global main
main: // entry of program
mov fp,sp
ldr x4,[fp] // load number of parameters command line
cmp x4,#3 // < 4 -> error
ble 99f
add x0,fp,#32 // load address param 4 = pos y
ldr x0,[x0]
bl conversionAtoD // conversion ascii -> numeric
mov x3,x0
add x0,fp,#24 // load address param 3 = pos x
ldr x0,[x0]
bl conversionAtoD
mov x2,x0
add x0,fp,#16 // load address param 2 = size begin pile
ldr x0,[x0]
bl conversionAtoD
ldr x4,qAdriSandPile
mov x5,#MAXI
madd x5,x3,x5,x2 // compute offset = maxi * y + x
str x0,[x4,x5,lsl #3] // and store size in pos x,y
//mov x0,x4 // display start position
//bl displaySandPile
mov x0,x4 // sandpile address
mov x1,x2 // pos x to start
mov x2,x3 // pos y to start
bl addSand
ldr x0,qAdrszMessFin
bl affichageMess
mov x0,x4
bl displaySandPile
b 100f
99: // line command error
ldr x0,qAdrszMessErrParam
bl affichageMess
100: // standard end of the program
mov x0,0 // return code
mov x8,EXIT // request to exit program
svc 0 // perform the system call
qAdrszCarriageReturn: .quad szCarriageReturn
qAdrsZoneConv: .quad sZoneConv
qAdrszMessErrParam: .quad szMessErrParam
qAdrszMessFin: .quad szMessFin
qAdriSandPile: .quad iSandPile
/***************************************************/
/* display sandpile */
/***************************************************/
// x0 contains address to sandpile
displaySandPile:
stp x1,lr,[sp,-16]! // save registres
stp x2,x3,[sp,-16]! // save registres
stp x4,x5,[sp,-16]! // save registres
stp x6,x7,[sp,-16]! // save registres
mov x6,x0
mov x3,#0 // indice y
mov x4,#MAXI
1:
mov x2,#0 // indice x
2:
madd x5,x3,x4,x2 // compute offset
ldr x0,[x6,x5,lsl #3] // load value at pos x,y
ldr x1,qAdrsZoneConv
bl conversion10 // call decimal conversion
add x1,x1,1
mov x7,#0
strb w7,[x1,x0]
ldr x0,qAdrszMessValue
ldr x1,qAdrsZoneConv // insert value conversion in message
bl strInsertAtCharInc
bl affichageMess
add x2,x2,1
cmp x2,MAXI
blt 2b
ldr x0,qAdrszCarriageReturn
bl affichageMess
add x3,x3,1
cmp x3,MAXI
blt 1b
 
100:
ldp x6,x7,[sp],16 // restaur des 2 registres
ldp x4,x5,[sp],16 // restaur des 2 registres
ldp x2,x3,[sp],16 // restaur des 2 registres
ldp x1,lr,[sp],16 // restaur des 2 registres
ret
qAdrszMessValue: .quad szMessValue
/***************************************************/
/* display sandpile */
/***************************************************/
// x0 contains address to sanspile
// x1 contains position x
// x2 contains position y
addSand:
stp x1,lr,[sp,-16]! // save registres
stp x2,x3,[sp,-16]! // save registres
stp x4,x5,[sp,-16]! // save registres
mov x3,#MAXI
madd x4,x3,x2,x1 // compute offset
ldr x5,[x0,x4,lsl #3]
1:
cmp x5,#4 // 4 grains ?
blt 100f
sub x5,x5,4 // yes sustract
str x5,[x0,x4,lsl #3]
cmp x1,MAXI-1 // right position ok ?
beq 2f
add x1,x1,1 // yes
bl add1Sand // add 1 grain
bl addSand // and compute new pile
sub x1,x1,1
2:
cmp x1,0 // left position ok ?
beq 3f
sub x1,x1,1
bl add1Sand
bl addSand
add x1,x1,1
3:
cmp x2,0 // higt position ok ?
beq 4f
sub x2,x2,1
bl add1Sand
bl addSand
add x2,x2,1
4:
cmp x2,MAXI-1 // low position ok ?
beq 5f
add x2,x2,1
bl add1Sand
bl addSand
sub x2,x2,1
5:
ldr x5,[x0,x4,lsl #3] // reload value
b 1b // and loop
100:
ldp x4,x5,[sp],16 // restaur des 2 registres
ldp x2,x3,[sp],16 // restaur des 2 registres
ldp x1,lr,[sp],16 // restaur des 2 registres
ret
/***************************************************/
/* add 1 grain of sand */
/***************************************************/
// x0 contains address to sanspile
// x1 contains position x
// x2 contains position y
add1Sand:
stp x3,lr,[sp,-16]! // save registres
stp x4,x5,[sp,-16]! // save registres
mov x3,#MAXI
madd x4,x3,x2,x1 // compute offset
ldr x5,[x0,x4,lsl #3] // load value at pos x,y
add x5,x5,1
str x5,[x0,x4,lsl #3] // and store
100:
ldp x4,x5,[sp],16 // restaur des 2 registres
ldp x3,lr,[sp],16 // restaur des 2 registres
ret
/********************************************************/
/* File Include fonctions */
/********************************************************/
/* for this file see task include a file in language AArch64 assembly */
.include "../includeARM64.inc"
</syntaxhighlight>
{{Output}}
<pre>
~/.../rosetta/asm1 $ abelian64 64 12 12
End display :
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 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 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 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 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 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1 2 2 2 2 2 1 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 2 2 2 0 2 2 2 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1 2 2 2 2 2 1 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 2 2 2 2 2 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 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
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 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 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 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>
 
=={{header|ARM Assembly}}==
{{works with|as|Raspberry Pi}}
<syntaxhighlight lang="arm assembly">
/* ARM assembly Raspberry PI or android 32 bits */
/* program abelian.s */
 
/* run : abelian 256 12 12 */
 
/* REMARK 1 : this program use routines in a include file
see task Include a file language arm assembly
for the routine affichageMess conversion10
see at end of this program the instruction include */
/* for constantes see task include a file in arm assembly */
/************************************/
/* Constantes */
/************************************/
.include "../constantes.inc"
.equ MAXI, 25
 
/*********************************/
/* Initialized data */
/*********************************/
.data
szMessValue: .asciz "@ "
szMessErrParam: .asciz "error : command line = abelian size posx posy \n"
szMessFin: .asciz "End display :\n"
szCarriageReturn: .asciz "\n"
/*********************************/
/* UnInitialized data */
/*********************************/
.bss
sZoneConv: .skip 24
iSandPile: .skip 4 * MAXI * MAXI
/*********************************/
/* code section */
/*********************************/
.text
.global main
main: @ entry of program
mov fp,sp
ldr r4,[fp] @ load number of parameters commend line
cmp r4,#3 @ < 4 -> error
ble 99f
add r0,fp,#16 @ load address param 4 = pos y
ldr r0,[r0]
bl conversionAtoD @ conversion ascii -> numeric
mov r3,r0
add r0,fp,#12 @ load address param 3 = pos x
ldr r0,[r0]
bl conversionAtoD
mov r2,r0
add r0,fp,#8 @ load address param 2 = size begin pile
ldr r0,[r0]
bl conversionAtoD
ldr r4,iAdriSandPile
mov r5,#MAXI
mul r5,r3,r5 @ compute offset = maxi * y
add r5,r2 @ + x
str r0,[r4,r5,lsl #2] @ and store size in pos x,y
//mov r0,r4 @ display start position
//bl displaySandPile
mov r0,r4 @ sandpile address
mov r1,r2 @ pos x to start
mov r2,r3 @ pos y to start
bl addSand
ldr r0,iAdrszMessFin
bl affichageMess
mov r0,r4
bl displaySandPile
b 100f
99: @ line command error
ldr r0,iAdrszMessErrParam
bl affichageMess
100: @ standard end of the program
mov r0, #0 @ return code
mov r7, #EXIT @ request to exit program
svc #0 @ perform the system call
iAdrszCarriageReturn: .int szCarriageReturn
iAdrsZoneConv: .int sZoneConv
iAdrszMessErrParam: .int szMessErrParam
iAdrszMessFin: .int szMessFin
iAdriSandPile: .int iSandPile
/***************************************************/
/* display sandpile */
/***************************************************/
// r0 contains address to sandpile
displaySandPile:
push {r1-r6,lr} @ save registers
mov r6,r0
mov r3,#0 @ indice y
mov r4,#MAXI
1:
mov r2,#0 @ indice x
2:
mul r5,r3,r4
add r5,r2 @ compute offset
ldr r0,[r6,r5,lsl #2] @ load value at pos x,y
ldr r1,iAdrsZoneConv
bl conversion10 @ call decimal conversion
add r1,#1
mov r7,#0
strb r7,[r1,r0]
ldr r0,iAdrszMessValue
ldr r1,iAdrsZoneConv @ insert value conversion in message
bl strInsertAtCharInc
bl affichageMess
add r2,#1
cmp r2,#MAXI
blt 2b
ldr r0,iAdrszCarriageReturn
bl affichageMess
add r3,#1
cmp r3,#MAXI
blt 1b
 
100:
pop {r1-r6,lr} @ restaur registers
bx lr @ return
iAdrszMessValue: .int szMessValue
/***************************************************/
/* display sandpile */
/***************************************************/
// r0 contains address to sanspile
// r1 contains position x
// r2 contains position y
addSand:
push {r1-r5,lr} @ save registers
mov r3,#MAXI
mul r4,r3,r2
add r4,r1
ldr r5,[r0,r4,lsl #2]
1:
cmp r5,#4 @ 4 grains ?
blt 100f
sub r5,#4 @ yes sustract
str r5,[r0,r4,lsl #2]
cmp r1,#MAXI-1 @ right position ok ?
beq 2f
add r1,#1 @ yes
bl add1Sand @ add 1 grain
bl addSand @ and compute new pile
sub r1,#1
2:
cmp r1,#0 @ left position ok ?
beq 3f
sub r1,#1
bl add1Sand
bl addSand
add r1,#1
3:
cmp r2,#0 @ higt position ok ?
beq 4f
sub r2,#1
bl add1Sand
bl addSand
add r2,#1
4:
cmp r2,#MAXI-1 @ low position ok ?
beq 5f
add r2,#1
bl add1Sand
bl addSand
sub r2,#1
5:
ldr r5,[r0,r4,lsl #2] @ reload value
b 1b @ and loop
100:
pop {r1-r5,lr} @ restaur registers
bx lr @ return
/***************************************************/
/* add 1 grain of sand */
/***************************************************/
// r0 contains address to sanspile
// r1 contains position x
// r2 contains position y
add1Sand:
push {r3-r5,lr} @ save registers
mov r3,#MAXI
mul r4,r3,r2
add r4,r1 @ compute offset
ldr r5,[r0,r4,lsl #2] @ load value at pos x,y
add r5,#1
str r5,[r0,r4,lsl #2] @ and store
100:
pop {r3-r5,lr} @ restaur registers
bx lr @ return
/***************************************************/
/* ROUTINES INCLUDE */
/***************************************************/
.include "../affichage.inc"
</syntaxhighlight>
{{output}}
<pre>
pi@raspberrypi:~/asm32/rosetta32/ass10 $ abelian 512 12 12
End display :
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 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 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 1 3 0 2 2 2 0 3 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 2 1 2 3 2 3 2 3 2 1 2 0 0 0 0 0 0 0
0 0 0 0 0 0 2 3 3 0 2 0 3 0 2 0 3 3 2 0 0 0 0 0 0
0 0 0 0 0 2 3 0 3 3 3 3 3 3 3 3 3 0 3 2 0 0 0 0 0
0 0 0 0 1 1 3 3 0 3 1 3 3 3 1 3 0 3 3 1 1 0 0 0 0
0 0 0 0 3 2 0 3 3 2 2 0 3 0 2 2 3 3 0 2 3 0 0 0 0
0 0 0 1 0 3 2 3 1 2 2 2 3 2 2 2 1 3 2 3 0 1 0 0 0
0 0 0 1 2 2 0 3 3 0 2 0 3 0 2 0 3 3 0 2 2 1 0 0 0
0 0 0 1 2 3 3 3 3 3 3 3 0 3 3 3 3 3 3 3 2 1 0 0 0
0 0 0 1 2 2 0 3 3 0 2 0 3 0 2 0 3 3 0 2 2 1 0 0 0
0 0 0 1 0 3 2 3 1 2 2 2 3 2 2 2 1 3 2 3 0 1 0 0 0
0 0 0 0 3 2 0 3 3 2 2 0 3 0 2 2 3 3 0 2 3 0 0 0 0
0 0 0 0 1 1 3 3 0 3 1 3 3 3 1 3 0 3 3 1 1 0 0 0 0
0 0 0 0 0 2 3 0 3 3 3 3 3 3 3 3 3 0 3 2 0 0 0 0 0
0 0 0 0 0 0 2 3 3 0 2 0 3 0 2 0 3 3 2 0 0 0 0 0 0
0 0 0 0 0 0 0 2 1 2 3 2 3 2 3 2 1 2 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 1 3 0 2 2 2 0 3 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 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 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|AutoHotkey}}==
<syntaxhighlight lang="autohotkey">
Size := Size2 := 10
celula := [], Deltas := ["-1,0","1,1","0,-1","0,1"], Width := Size * 2.5
Gui, font, S%Size%
Gui, add, text, y1
loop, 19
{
Row := A_Index
loop, 19
{
Col := A_Index
Gui, add, button, % (Col=1 ? "xs y+1" : "x+1 yp") " v" Col "_" Row " w" Width " -TabStop"
celula[Col,Row] := 0
GuiControl, hide, %Col%_%Row%
}
}
gui, color, black
Gui, show,, Abelian SandPile
InputBox, areia,, How much particles?,, 140, 140
celula[10,10] := areia
inicio:
loop
{
GuiControl,, 10_10, % celula[10,10]
fim := true
loop 19
{
linha := A_Index
loop 19
{
coluna := A_Index
if (celula[coluna,linha] >= 4)
{
celula[coluna,linha] -= 4
celula[coluna-1,linha] += 1
celula[coluna+1,linha] += 1
celula[coluna,linha-1] += 1
celula[coluna,linha+1] += 1
fim := false
}
}
}
if (fim = true)
break
}
loop 19
{
line := A_Index
loop 19
{
column := A_Index
GuiControlGet, posicao, Pos, % column "_" line
switch celula[column,line]
{
case 0:
gui, add, progress, Backgroundblue w24 h24 x%posicaoX% y%posicaoY%
case 1:
gui, add, progress, backgroundred w24 h24 x%posicaoX% y%posicaoY%
case 2:
gui, add, progress, backgroundgreen w24 h24 x%posicaoX% y%posicaoY%
case 3:
gui, add, progress, backgroundyellow w24 h24 x%posicaoX% y%posicaoY%
}
}
}
msgbox sair
ExitApp
</syntaxhighlight>
[[File:Abelian_sandpile_ahk_1000_particles.png|500px|thumb|center|Image for 1000 particles grid 19x19]]
 
=={{header|BQN}}==
<syntaxhighlight lang="bqn">
#!/usr/bin/env BQN
# Takes the size of grid (1 side) and the size of the starting pile as command line arguments
size‿pile←•BQN¨ 2↑•args
_Fp←{𝔽∘⊢⍟≢⟜𝔽_𝕣∘⊢⍟≢⟜𝔽𝕩} # Fixed point function
Sand←{p←𝕩≥4 ⋄ (𝕩+¯4×p)++´⟨«,»,«˘,»˘⟩{𝕎𝕩}¨<p}_Fp # Calculates given sand grid until it stops changing
 
last←Sand pile˙⌾((⋈˜⌊size÷2)⊸⊑) size‿size⥊0 # Calculate the last state of the sand grid
 
# PPM output, code taken from https://rosettacode.org/wiki/Bitmap/Write_a_PPM_file#BQN
header_ppm←"P6"∾(@+10)∾(•Repr size)∾" "∾(•Repr size)∾(@+10)∾"255"∾@+10
colors←4⊸↑⌾⌽255×=⌜˜↕3 # Black, Red, Green, Blue
image_ppm←@+⥊colors⊏˜4|last
"sandpile.ppm" •file.Bytes header_ppm∾image_ppm
</syntaxhighlight>
 
=={{header|C}}==
Writes out the initial and final sand piles to the console and the final sand pile to a PPM file.
<syntaxhighlight lang="c">
<lang C>
#include<stdlib.h>
#include<string.h>
Line 153 ⟶ 910:
return 0;
}
</syntaxhighlight>
</lang>
 
Console output :
Line 192 ⟶ 949:
<!-- c++ bindings -->
<br>
<syntaxhighlight lang="cpp">#include <iostream>
<lang cpp>
#include <iostream>
#include "xtensor/xarray.hpp"
#include "xtensor/xio.hpp"
Line 266 ⟶ 1,022:
 
return 0;
}</syntaxhighlight>
}
Compile with following <tt>CMakeList.txt</tt>:
 
<syntaxhighlight lang="cmake">cmake_minimum_required(VERSION 3.1)
</lang>
<pre>
Compile with following CMakeList.txt
cmake_minimum_required(VERSION 3.1)
project(abelian_sandpile)
 
Line 285 ⟶ 1,038:
 
target_compile_options(abelian_sandpile PRIVATE -march=native -std=c++14)
target_link_libraries(abelian_sandpile xtensor ${OIIO})</syntaxhighlight>
 
 
target_link_libraries(abelian_sandpile xtensor ${OIIO})
</pre>
 
=={{header|Delphi}}==
{{Trans|Python}}
<syntaxhighlight lang="delphi">
<lang Delphi>
program Abelian_sandpile_model;
 
Line 452 ⟶ 1,202:
Readln;
end.
</syntaxhighlight>
</lang>
 
 
Line 458 ⟶ 1,208:
{{works with|gforth|0.7.3}}
<br>
<langsyntaxhighlight lang="forth">#! /usr/bin/gforth -d 20M
\ Abelian Sandpile Model
 
Line 523 ⟶ 1,273:
: simulate prepare begin stack-full? while 2dup 2>r reduce 2r> inc-all repeat drop to-pgm ." written to " filename type cr ;
 
simulate bye</langsyntaxhighlight>
 
{{out}}
Line 539 ⟶ 1,289:
{{works with|gfortran|9.2.0}}
The Abelian sandpile operations are defined here.
<langsyntaxhighlight lang="fortran">module abelian_sandpile_m
 
implicit none
Line 630 ⟶ 1,380:
end subroutine
 
end module</langsyntaxhighlight>
 
The <code>main</code> program calls the <code>abelian_sandpile_m</code> and creates an ppm bitmap file by loading <code>rgbimage_m</code> module, which is defined [[Basic bitmap storage#Fortran|here]].
<langsyntaxhighlight lang="fortran">program main
 
use rgbimage_m
Line 668 ⟶ 1,418:
call im%write('fig.ppm')
 
end program</langsyntaxhighlight>
 
=={{header|Fōrmulæ}}==
 
In [{{FormulaeEntry|page=https://wiki.formulae.org/?script=examples/Abelian_sandpile_model this] page you can see the solution of this task.}}
 
Fōrmulæ programs are not textual, visualization/edition of programs is done showing/manipulating structures but not text ([http://wiki.formulae.org/Editing_F%C5%8Drmul%C3%A6_expressions more info]). 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 transportation effects more than visualization and edition.
 
The option to show Fōrmulæ programs and their results is showing images. Unfortunately images cannot be uploaded in Rosetta Code.
 
=={{header|F_Sharp|F#}}==
<langsyntaxhighlight lang="fsharp">
// Abelian sandpile model. Nigel Galloway: July 20th., 2020
type Sandpile(x,y,N:int[])=
Line 706 ⟶ 1,452:
let e1=Array.zeroCreate<int> 25 in e1.[12]<-6; printfn "%s\n" (Sandpile(5,5,e1)).toS
let e1=Array.zeroCreate<int> 25 in e1.[12]<-16; printfn "%s\n" (Sandpile(5,5,e1)).toS
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 731 ⟶ 1,477:
[0; 0; 1; 0; 0]]
</pre>
 
 
=={{header|FreeBASIC}}==
<syntaxhighlight lang="freebasic">ScreenRes 320, 200, 8
WindowTitle "Abelian sandpile model"
 
Dim As Long dimen = 220
Dim As Long pila1(dimen*dimen), pila2(dimen*dimen)
Dim As Long i, x, y
Dim As Long partic = 400000
Dim As Double t0 = Timer
Do
i = 0
For y = 0 To dimen-1
For x = 0 To dimen-1
If x = dimen/2 And y = dimen/2 Then
partic -= 4
pila1(i) += 4
End If
If pila1(i) >= 4 Then
pila1(i) -= 4
pila2(i-1) += 1
pila2(i+1) += 1
pila2(i-dimen) += 1
pila2(i+dimen) += 1
End If
Pset(x, y), (pila1(i)*2)
i += 1
Swap pila1(i), pila2(i)
Next x
Next y
Loop Until partic < 4
Bsave "abelian_sandpile.bmp",0
Sleep</syntaxhighlight>
{{out}}
<pre>[https://www.dropbox.com/s/lky2ji9n15gn5u6/abelian_sandpile.bmp?dl=0 Abelian sandpile model FreeBasic image]
</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}}==
{{trans|Rust}}
<br>
Stack management in Go is automatic, starting very small (2KB) for each goroutine and expanding as necessary until the maximum allowed size is reached.
<langsyntaxhighlight lang="go">package main
 
import (
Line 843 ⟶ 1,783:
// after the recursive algorithm has ended.
// writePile(pile)
}</langsyntaxhighlight>
 
{{out}}
Line 873 ⟶ 1,813:
<br>
Using a custom monad to make the code cleaner.
<langsyntaxhighlight lang="haskell">{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE ScopedTypeVariables #-}
Line 988 ⟶ 1,928:
fp = printf "sandpile_%d_%d.pgm" size height
toPGM b fp
putStrLn $ "wrote image to " ++ fp</langsyntaxhighlight>
 
{{out}}
Line 998 ⟶ 1,938:
=={{header|J}}==
 
<langsyntaxhighlight Jlang="j">grid=: 4 : 'x (<<.-:2$y)} (2$y)$0' NB. y by y grid with x grains in middle
ab=: + [: (_4&* +- [: +/@(-"2 ((,-)=/~i.2]\i:1)|.!.0 ]) 3&< NB. abelian sand pile for grid graph
require 'viewmat' NB. viewmat utility
viewmat ab ^: _ (1024 grid 25) NB. visual </langsyntaxhighlight>
 
=={{header|Java}}==
This is based on the JavaScript implementation linked to in the task description.
<langsyntaxhighlight lang="java">import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
Line 1,117 ⟶ 2,057:
};
private static final int GRID_LENGTH = 300;
}</langsyntaxhighlight>
 
{{out}}
[[Media:Abelian sandpile java.png]]
See: [https://slack-files.com/T0CNUL56D-F017G8Z1E6Q-53cde3d692 abelian_sandpile.png] (offsite PNG image)
 
=={{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}}==
Modified from code by Hayk Aleksanyan, viewable at github.com/hayk314/Sandpiles, license viewable there.
<langsyntaxhighlight lang="julia">module AbelSand
 
# supports output functionality for the results of the sandpile simulations
Line 1,399 ⟶ 2,432:
 
Z_lat, Odometer = AbelSand.move(100000)
</langsyntaxhighlight>{{out}}
[http://alahonua.com/temp/Abel_Z_color_100000.png Link to PNG output file for N=100000 ie. AbelSand.move(100000)] <br />
[http://alahonua.com/temp/Abel_Z_color_1000000.png Link to PNG output file (run time >90 min) for N=1000000 (move(1000000))]
 
=={{header|Lua}}==
<syntaxhighlight lang="lua">local sandpile = {
init = function(self, dim, val)
self.cell, self.dim = {}, dim
for r = 1, dim do
self.cell[r] = {}
for c = 1, dim do
self.cell[r][c] = 0
end
end
self.cell[math.floor(dim/2)+1][math.floor(dim/2)+1] = val
end,
iter = function(self)
local dim, cel, more = self.dim, self.cell
repeat
more = false
for r = 1, dim do
for c = 1, dim do
if cel[r][c] >= 4 then
cel[r][c] = cel[r][c] - 4
if c > 1 then cel[r][c-1], more = cel[r][c-1]+1, more or cel[r][c-1]>=3 end
if c < dim then cel[r][c+1], more = cel[r][c+1]+1, more or cel[r][c+1]>=3 end
if r > 1 then cel[r-1][c], more = cel[r-1][c]+1, more or cel[r-1][c]>=3 end
if r < dim then cel[r+1][c], more = cel[r+1][c]+1, more or cel[r+1][c]>=3 end
end
more = more or cel[r][c] >= 4
end
end
until not more
end,
draw = function(self)
for r = 1, self.dim do
print(table.concat(self.cell[r]," "))
end
end,
}
sandpile:init(15, 256)
sandpile:iter()
sandpile:draw()</syntaxhighlight>
{{out}}
<pre>0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 1 2 2 2 1 0 0 0 0 0
0 0 0 0 2 1 0 2 0 1 2 0 0 0 0
0 0 0 2 3 3 3 2 3 3 3 2 0 0 0
0 0 2 3 2 2 2 3 2 2 2 3 2 0 0
0 1 1 3 2 2 3 0 3 2 2 3 1 1 0
0 2 0 3 2 3 2 3 2 3 2 3 0 2 0
0 2 2 2 3 0 3 0 3 0 3 2 2 2 0
0 2 0 3 2 3 2 3 2 3 2 3 0 2 0
0 1 1 3 2 2 3 0 3 2 2 3 1 1 0
0 0 2 3 2 2 2 3 2 2 2 3 2 0 0
0 0 0 2 3 3 3 2 3 3 3 2 0 0 0
0 0 0 0 2 1 0 2 0 1 2 0 0 0 0
0 0 0 0 0 1 2 2 2 1 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0</pre>
 
=={{header|Mathematica}}/{{header|Wolfram Language}}==
<syntaxhighlight lang="mathematica">ClearAll[sp]
sp[s_List] + sp[n_Integer] ^:= sp[s] + sp[ConstantArray[n, Dimensions[s]]]
sp[s_List] + sp[t_List] ^:= Module[{dim, r, tmp, neighbours}, dim = Dimensions[s];
r = s + t;
While[Max[r] > 3, r = ArrayPad[r, 1, 0];
tmp = Quotient[r, 4];
r -= 4 tmp;
r += RotateLeft[tmp, {0, 1}] + RotateLeft[tmp, {1, 0}] +
RotateLeft[tmp, {0, -1}] + RotateLeft[tmp, {-1, 0}];
r = ArrayPad[r, -1];];
sp[r]
]
u = sp[CenterArray[250, {15, 15}]];
u += sp[0];
StringRiffle[StringJoin /@ Map[ToString, u[[1]], {2}], "\n"]</syntaxhighlight>
{{out}}
<pre>000000000000000
000001222100000
000021020120000
000233323332000
002322222223200
011322232223110
020322030223020
022223323322220
020322030223020
011322232223110
002322222223200
000233323332000
000021020120000
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}}==
{{libheader|nimPNG}}
Our program uses Rust algorithm (and also its colors 🙂) and the formula to compute grid size from number of particles comes from Pascal algorithm.
Number of particles is an input from user. The program displays the values on the terminal if there are not too many and produce a PNG image. Code to produce a PPM image is also provided but not used.
<syntaxhighlight lang="nim">
# Abelian sandpile.
 
from math import sqrt
from nimPNG import savePNG24
from sequtils import repeat
from strformat import fmt
from strutils import strip, addSep, parseInt
 
# The grid represented as a sequence of sequences of int32.
type Grid = seq[seq[int32]]
 
# Colors to use for PPM and PNG files.
const Colors = [[byte 100, 40, 15],
[byte 117, 87, 30],
[byte 181, 134, 47],
[byte 245, 182, 66]]
 
#---------------------------------------------------------------------------------------------------
 
func sideLength(initVal: int32): int32 =
# Return the grid side length needed for "initVal" particles.
# We make sure that the returned value is odd.
result = sqrt(initVal.toFloat / 1.75).int32 + 3
result += result and 1 xor 1
 
#---------------------------------------------------------------------------------------------------
 
func doOneStep(grid: var Grid; boundary: var array[4, int]): bool =
## Compute one step.
 
result = false
 
for y in boundary[0]..boundary[2]:
for x in boundary[1]..boundary[3]:
if grid[y][x] >= 4:
 
let rem = grid[y][x] div 4
grid[y][x] = grid[y][x] mod 4
 
if y - 1 >= 0:
inc grid[y - 1][x], rem
if y == boundary[0]:
dec boundary[0]
 
if x - 1 >= 0:
inc grid[y][x - 1], rem
if x == boundary[1]:
dec boundary[1]
 
if y + 1 < grid.len:
inc grid[y + 1][x], rem
if y == boundary[2]:
inc boundary[2]
 
if x + 1 < grid.len:
inc grid[y][x + 1], rem
if x == boundary[3]:
inc boundary[3]
 
result = true
 
#---------------------------------------------------------------------------------------------------
 
proc display(grid: Grid; initVal: int) =
## Display the grid as an array of values.
 
echo fmt"Starting with {initVal} particles."
echo ""
 
var line = newStringOfCap(2 * grid.len - 1)
for row in grid:
for value in row:
line.addSep(" ", 0)
line.add($value)
echo line
line.setLen(0)
echo ""
 
#---------------------------------------------------------------------------------------------------
 
proc writePpmFile(grid: Grid; name: string) =
## Write a grid representation in a PPM file.
 
var file = open(name, fmWrite)
file.write(fmt"P6 {grid.len} {grid.len} 255 ")
 
for row in grid:
for value in row:
discard file.writeBytes(Colors[value], 0, 3)
 
file.close()
echo fmt"PPM image written in ""{name}""."
 
#---------------------------------------------------------------------------------------------------
 
proc writePngFile(grid: Grid; name: string) =
## Write a grid representation in a PNG file.
 
var pixels = newSeq[byte](3 * grid.len * grid.len)
 
# Build pixel list.
var idx = 0
for row in grid:
for value in row:
pixels[idx..idx+2] = Colors[value]
inc idx, 3
 
discard savePNG24(name, pixels, grid.len, grid.len)
echo fmt"PNG image written in ""{name}""."
 
#---------------------------------------------------------------------------------------------------
 
proc askInitVal(): int32 =
# Ask user for the number of particles.
 
while true:
stdout.write("Number of particles? ")
try:
let input = stdin.readLine().strip().parseInt()
if input in 4..int32.high:
return input.int32
echo fmt"Value not in expected range: 4..{int32.high}"
except ValueError:
echo "Invalid input"
except EOFError:
quit(QuitSuccess)
 
#---------------------------------------------------------------------------------------------------
 
# Initialize the grid.
let initVal = askInitVal()
let sideLen = sideLength(initVal)
var grid = repeat(newSeq[int32](sideLen), sideLen)
let origin = grid.len div 2
var boundaries: array[4, int] = [origin, origin, origin, origin]
grid[origin][origin] = initVal
 
# Run the simulation.
while doOneStep(grid, boundaries):
discard
 
# Display grid.
if grid.len <= 20:
grid.display(initVal)
#grid.writePpmFile(fmt"grid_{initVal}.ppm")
grid.writePngFile(fmt"grid_{initVal}.png")
</syntaxhighlight>
 
{{out}}
<pre>
Number of particles? 100
Starting with 100 particles.
 
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 1 2 1 0 0 0 0
0 0 0 3 2 0 2 3 0 0 0
0 0 3 0 3 2 3 0 3 0 0
0 1 2 3 0 3 0 3 2 1 0
0 2 0 2 3 0 3 2 0 2 0
0 1 2 3 0 3 0 3 2 1 0
0 0 3 0 3 2 3 0 3 0 0
0 0 0 3 2 0 2 3 0 0 0
0 0 0 0 1 2 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
 
PNG image written in "grid_100.png".
</pre>
 
=={{header|Pascal}}==
Line 1,408 ⟶ 2,785:
Memorizing the used colums of the rows has little effect when choosing the right size of the grid.Only 11 secs for abelian(1e6) -> 1min 9sec<BR>
[http://rosettacode.org/wiki/Abelian_sandpile_model#Python Python] shows 64 too.
<langsyntaxhighlight lang="pascal">
program Abelian2;
{$IFDEF FPC}
Line 1,596 ⟶ 2,973:
OneTurn(100000);
END.
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 1,657 ⟶ 3,034:
</pre>
 
=={{header|PerlOCaml}}==
{{works with|OCaml|4.11}}
<lang Perl>#!/usr/bin/perl
In Sandpile module (sandpile.ml)
<syntaxhighlight lang="ocaml">
module Make =
functor (M : sig val m : int val n : int end)
-> struct
 
let grid = Array.init M.m (fun _ -> Array.make M.n 0)
use strict; # http://www.rosettacode.org/wiki/Abelian_sandpile_model
 
let print () =
for i = 0 to M.m - 1
do for j = 0 to M.n - 1
do Printf.printf "%d " grid.(i).(j)
done
; print_newline ()
done
 
let unstable = Hashtbl.create 10
 
let add_grain x y
= grid.(x).(y) <- grid.(x).(y) + 1
; if grid.(x).(y) >= 4 then
Hashtbl.replace unstable (x,y) () (* Use Hashtbl.replace for uniqueness *)
let topple x y
= grid.(x).(y) <- grid.(x).(y) - 4
; if grid.(x).(y) < 4
then Hashtbl.remove unstable (x,y)
; match (x,y) with
(* corners *)
| (0,0) -> add_grain 1 0
; add_grain 0 1
| (0,n) when n = M.n - 1
-> add_grain 1 n
; add_grain 0 (n-1)
| (m,0) when m = M.m - 1
-> add_grain m 1
; add_grain (m-1) 0
| (m,n) when m = M.m - 1 && n = M.n - 1
-> add_grain ( m ) (n-1)
; add_grain (m-1) ( n )
(* sides *)
| (0,y) -> add_grain 1 y
; add_grain 0 (y+1)
; add_grain 0 (y-1)
| (m,y) when m = M.m - 1
-> add_grain ( m ) (y-1)
; add_grain ( m ) (y+1)
; add_grain (m-1) ( y )
| (x,0) -> add_grain (x+1) 0
; add_grain (x-1) 0
; add_grain ( x ) 1
| (x,n) when n = M.n - 1
-> add_grain (x-1) ( n )
; add_grain (x+1) ( n )
; add_grain ( x ) (n-1)
(* else *)
| (x,y) -> add_grain ( x ) (y+1)
; add_grain ( x ) (y-1)
; add_grain (x+1) ( y )
; add_grain (x-1) ( y )
let add_sand n x y
= for i = 1 to n
do add_grain x y
done
 
let avalanche ()
= while Hashtbl.length unstable > 0
do
let unstable' = Hashtbl.fold (fun (x,y) () r -> (x,y) :: r) unstable []
in List.iter (fun (x,y) -> topple x y ) unstable'
done
end
 
(* testing *)
let ()
= let module S = Make (struct let m = 11 let n = 11 end)
in S.add_sand 500 5 5
; S.avalanche ()
; S.print ()
</syntaxhighlight>
 
=={{header|Perl}}==
<syntaxhighlight lang="perl">use strict;
use warnings;
use feature 'bitwise';
 
my ($high, $wide) = split ' ', qx(stty size);
Line 1,668 ⟶ 3,129:
my $pile = $mask =~ s/\177/ rand() < 0.02 ? chr 64 + rand 20 : "\0" /ger;
 
for ( 1 .. 1e6 )
{
print "\e[H", $pile =~ tr/\0-\177/ 1-~/r, "\n$_";
Line 1,676 ⟶ 3,137:
for ("\0$add", "\0" x $wide . $add, substr($add, 1), substr $add, $wide)
{
$pile |.= $_;
$pile =~ tr/\200-\377/\1-\176/; # add one to each neighbor of >=4
$pile &.= $mask;
}
select undef, undef, undef, 0.1; # comment out for full speed
}</langsyntaxhighlight>
 
=={{header|Phix}}==
Line 1,687 ⟶ 3,148:
Generates moving images similar to the julia output.
The distributed version also has variable speed, additional display modes, and a random dropping toggle.
<!--<syntaxhighlight lang="phix">-->
<lang Phix>-- demo\rosetta\Abelian_sandpile_model.exw
<span style="color: #000080;font-style:italic;">-- demo\rosetta\Abelian_sandpile_model.exw</span>
include pGUI.e
<span style="color: #008080;">include</span> <span style="color: #000000;">pGUI</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span>
<span style="color: #004080;">Ihandle</span> <span style="color: #000000;">dlg</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">canvas</span>
<span style="color: #004080;">cdCanvas</span> <span style="color: #000000;">cddbuffer</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">board</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">}}</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">drop</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">moves</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
<span style="color: #008080;">while</span> <span style="color: #004600;">true</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">y</span><span style="color: #0000FF;">,</span><span style="color: #000000;">x</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">y</span><span style="color: #0000FF;">,</span><span style="color: #000000;">x</span><span style="color: #0000FF;">]>=</span><span style="color: #000000;">4</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">y</span><span style="color: #0000FF;">,</span><span style="color: #000000;">x</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">-=</span> <span style="color: #000000;">4</span>
<span style="color: #000000;">moves</span> <span style="color: #0000FF;">&=</span> <span style="color: #0000FF;">{{</span><span style="color: #000000;">y</span><span style="color: #0000FF;">,</span><span style="color: #000000;">x</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">y</span><span style="color: #0000FF;">,</span><span style="color: #000000;">x</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">y</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">x</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">y</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">x</span><span style="color: #0000FF;">}}</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000080;font-style:italic;">-- extend board if rqd (maintain a border of zeroes)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span> <span style="color: #000080;font-style:italic;">-- extend left</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">board</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">prepend</span><span style="color: #0000FF;">(</span><span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span><span style="color: #000000;">0</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">moves</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">moves</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">][</span><span style="color: #000000;">2</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">=</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">])</span> <span style="color: #008080;">then</span> <span style="color: #000080;font-style:italic;">-- extend right</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">board</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span><span style="color: #000000;">0</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000080;font-style:italic;">-- (copy the all-0 lines from the other end...)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span> <span style="color: #000080;font-style:italic;">-- extend up</span>
<span style="color: #000000;">board</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">prepend</span><span style="color: #0000FF;">(</span><span style="color: #000000;">board</span><span style="color: #0000FF;">,</span><span style="color: #000000;">board</span><span style="color: #0000FF;">[$])</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">moves</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">moves</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">][</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">=</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">board</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> <span style="color: #000080;font-style:italic;">-- extend down</span>
<span style="color: #000000;">board</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">board</span><span style="color: #0000FF;">,</span><span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">])</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">moves</span><span style="color: #0000FF;">)=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">y</span><span style="color: #0000FF;">,</span><span style="color: #000000;">x</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">moves</span><span style="color: #0000FF;">[$]</span>
<span style="color: #000000;">moves</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">moves</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..$-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #7060A8;">IupUpdate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">timer_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000080;font-style:italic;">/*ih*/</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">y</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">board</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">x</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">])/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)+</span><span style="color: #000000;">1</span>
<span style="color: #000000;">drop</span><span style="color: #0000FF;">(</span><span style="color: #000000;">y</span><span style="color: #0000FF;">,</span><span style="color: #000000;">x</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">redraw_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000000;">ih</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000080;font-style:italic;">/*posx*/</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000080;font-style:italic;">/*posy*/</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">IupGLMakeCurrent</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ih</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">cdCanvasActivate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">cdCanvasClear</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">board</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">])</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">c</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">y</span><span style="color: #0000FF;">][</span><span style="color: #000000;">x</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">colour</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #004600;">CD_VIOLET</span><span style="color: #0000FF;">,</span><span style="color: #004600;">CD_RED</span><span style="color: #0000FF;">,</span><span style="color: #004600;">CD_BLUE</span><span style="color: #0000FF;">}[</span><span style="color: #000000;">c</span><span style="color: #0000FF;">]</span>
<span style="color: #7060A8;">cdCanvasPixel</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">colour</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #7060A8;">cdCanvasFlush</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">map_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000000;">ih</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">IupGLMakeCurrent</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ih</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupGetDouble</span><span style="color: #0000FF;">(</span><span style="color: #004600;">NULL</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"SCREENDPI"</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">25.4</span>
<span style="color: #000000;">cddbuffer</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">cdCreateCanvas</span><span style="color: #0000FF;">(</span><span style="color: #004600;">CD_GL</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"300x100 %g"</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">res</span><span style="color: #0000FF;">})</span>
<span style="color: #7060A8;">cdCanvasSetBackground</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #004600;">CD_PARCHMENT</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">main</span><span style="color: #0000FF;">()</span>
<span style="color: #7060A8;">IupOpen</span><span style="color: #0000FF;">()</span>
<span style="color: #000000;">canvas</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupGLCanvas</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"RASTERSIZE=300x100"</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">IupSetCallbacks</span><span style="color: #0000FF;">({</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #008000;">"ACTION"</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"redraw_cb"</span><span style="color: #0000FF;">),</span>
<span style="color: #008000;">"MAP_CB"</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"map_cb"</span><span style="color: #0000FF;">)})</span>
<span style="color: #000000;">dlg</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupDialog</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"TITLE=\"Abelian sandpile model\""</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">IupShow</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dlg</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">Ihandle</span> <span style="color: #000000;">timer</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupTimer</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"timer_cb"</span><span style="color: #0000FF;">),</span> <span style="color: #000000;">10</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">IupMainLoop</span><span style="color: #0000FF;">()</span>
<span style="color: #7060A8;">IupClose</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #000000;">main</span><span style="color: #0000FF;">()</span>
<!--</syntaxhighlight>-->
 
=={{header|PicoLisp}}==
Ihandle dlg, canvas
<syntaxhighlight lang="picolisp">
cdCanvas cddbuffer
(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}}
sequence board = {{0,0,0},
<pre>
{0,0,0},
+---+---+---+---+---+---+---+---+---+---+
{0,0,0}}
10 | 0 0 0 0 0 0 0 0 0 0 |
 
+ + + + + + + + + + +
procedure drop(integer y, x)
9 | 0 0 0 0 0 0 0 0 0 0 |
sequence moves = {}
+ + + + + + + + + + +
while true do
8 | 0 0 0 1 2 1 0 0 0 0 |
board[y,x] += 1
+ + + + + + + + + + +
if board[y,x]>=4 then
7 | 0 0 2 board[y,x] -=2 4 2 2 2 0 0 0 |
+ + + moves &=+ {{y,x-1},{y,x+1},{y-1,x},{y + + + + + +1,x}}
6 | 0 1 2 2 2 2 2 1 0 0 |
end if
+ + -- extend board+ if rqd (maintain+ a border of+ zeroes) + + + + + +
5 | 0 2 if x=1 then2 2 0 2 2 2 0 0 -- extend left|
+ + + for i=1+ to length(board) do+ + + + + + +
4 | 0 1 2 2 board[i]2 2 2 1 = prepend(board[i],0) 0 |
+ + + end for+ + + + + + + +
3 | 0 0 2 for i=12 to length(moves) do2 2 2 0 0 0 |
+ + + + moves[i][2]+ += 1 + + + + +
2 | 0 0 0 end for1 2 1 0 0 0 0 |
+ + elsif x=length(board[1]) then+ + + + -- extend+ right + + + +
1 | 0 0 0 for i=10 0 0 0 0 0 to length(board)0 do|
+---+---+---+---+---+---+---+---+---+---+
board[i] = append(board[i],0)
a b endc for d e f g h i j
</pre>
end if
-- (copy the all-0 lines from the other end...)
if y=1 then -- extend up
board = prepend(board,board[$])
for i=1 to length(moves) do
moves[i][1] += 1
end for
elsif y=length(board) then -- extend down
board = append(board,board[1])
end if
if length(moves)=0 then exit end if
{y,x} = moves[$]
moves = moves[1..$-1]
end while
IupUpdate(canvas)
end procedure
 
function timer_cb(Ihandle /*ih*/)
integer y = floor(length(board)/2)+1,
x = floor(length(board[1])/2)+1
drop(y,x)
return IUP_DEFAULT
end function
 
function redraw_cb(Ihandle ih, integer /*posx*/, integer /*posy*/)
IupGLMakeCurrent(ih)
cdCanvasActivate(cddbuffer)
cdCanvasClear(cddbuffer)
for y=1 to length(board) do
for x=1 to length(board[1]) do
integer c = board[y][x]
if c!=0 then
integer colour = {CD_VIOLET,CD_RED,CD_BLUE}[c]
cdCanvasPixel(cddbuffer, x, y, colour)
end if
end for
end for
cdCanvasFlush(cddbuffer)
return IUP_DEFAULT
end function
 
function map_cb(Ihandle ih)
IupGLMakeCurrent(ih)
atom res = IupGetDouble(NULL, "SCREENDPI")/25.4
cddbuffer = cdCreateCanvas(CD_GL, "300x100 %g", {res})
cdCanvasSetBackground(cddbuffer, CD_PARCHMENT)
return IUP_DEFAULT
end function
 
procedure main()
IupOpen()
canvas = IupGLCanvas("RASTERSIZE=300x100")
IupSetCallbacks({canvas}, {"ACTION", Icallback("redraw_cb"),
"MAP_CB", Icallback("map_cb")})
dlg = IupDialog(canvas,"TITLE=\"Abelian sandpile model\"")
IupCloseOnEscape(dlg)
IupShow(dlg)
Ihandle timer = IupTimer(Icallback("timer_cb"), 10)
IupMainLoop()
IupClose()
end procedure
main()</lang>
 
=={{header|Python}}==
===Python: Original, with output===
<lang Python>
<syntaxhighlight lang="python">import numpy as np
import matplotlib.pyplot as plt
 
Line 1,821 ⟶ 3,340:
plt.figure()
plt.gray()
plt.imshow(final_grid)</syntaxhighlight>
{{Out}}
</lang>
<b>Output:</b> </n>
Before:
<syntaxhighlight lang="python">[[0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
<lang Python>
[[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.]
Line 1,835 ⟶ 3,352:
[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.]]</syntaxhighlight>
</lang>
After:
<syntaxhighlight lang="python">[[0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
<lang Python>
[[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.]
Line 1,848 ⟶ 3,363:
[0. 0. 0. 1. 2. 1. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]]</syntaxhighlight>
</lang>
 
 
An interactive variant to the above solution:
<syntaxhighlight lang="python">from os import system, name
<lang python>
from os import system, name
from time import sleep
 
Line 1,919 ⟶ 3,431:
run(area)
print('\nAfter:')
show_area(area)</syntaxhighlight>
{{Out}}
</lang>
<syntaxhighlight lang="python">
 
Output:
<lang>
Before:
0 0 0 0 0 0 0 0 0 0
Line 1,947 ⟶ 3,457:
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
</syntaxhighlight>
</lang>
 
===Python: using tkinter===
<syntaxhighlight lang="python">
''' Python 3.6.5 code using Tkinter graphical user
interface (Canvas widget) to display final results.'''
from tkinter import *
 
# given a grid, display it on a tkinter Canvas:
class Sandpile:
def __init__(self, wn, grid):
self.window = wn
self.grid = grid
self.canvas = Canvas(wn, bg='lemon chiffon')
self.canvas.pack(fill=BOTH, expand=1)
 
colors = {0:'dodger blue',
1:'red',
2:'green',
3:'lemon chiffon'}
x = 10
y = 10
d = 5
for row in self.grid:
for value in row:
clr = colors[value]
self.canvas.create_rectangle(
x, y, x+d, y+d,
outline=clr,
fill = clr)
x += 5
x = 10
y += 5
class Grid:
def __init__(self, size, center):
self.size = size # rows/cols in (best if odd)
self.center = center # start value at center of grid
self.grid = [[0]*self.size for i in range(self.size)]
self.grid[self.size // 2][self.size // 2] = self.center
 
# print the grid:
def show(self, msg):
print(' ' + msg + ':')
for row in self.grid:
print(' '.join(str(x) for x in row))
print()
return
 
# dissipate piles of sand as required:
def abelian(self):
while True:
found = False
for r in range(self.size):
for c in range(self.size):
if self.grid[r][c] > 3:
self.distribute(self.grid[r][c], r, c)
found = True
if not found:
return
 
# distribute sand from a single pile to its neighbors:
def distribute(self, nbr, row, col):
qty, remain = divmod(nbr, 4)
self.grid[row][col] = remain
for r, c in [(row+1, col),
(row-1, col),
(row, col+1),
(row, col-1)]:
self.grid[r][c] += qty
return
 
# display the grid using tkinter:
def display(self):
root = Tk()
root.title('Sandpile')
root.geometry('700x700+100+50')
sp = Sandpile(root, self.grid)
root.mainloop()
 
# execute program for size, center value pair:
# just print results for a small grid
g = Grid(9,17)
g.show('BEFORE')
g.abelian() # scatter the sand
g.show('AFTER')
 
# just show results in tkinter for a large grid
# I wish there was a way to attach a screen shot
# of the tkinter result here
g = Grid(131,25000)
g.abelian() # scatter the sand
g.display() # display result using tkinter
## OUTPUT:
##
## 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 17 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 1 0 0 0 0
## 0 0 0 2 1 2 0 0 0
## 0 0 1 1 1 1 1 0 0
## 0 0 0 2 1 2 0 0 0
## 0 0 0 0 1 0 0 0 0
## 0 0 0 0 0 0 0 0 0
## 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 1,955 ⟶ 3,658:
Defaults to a stack of 1000 and showing progress. Pass in a custom stack size if desired and -hide-progress to run without displaying progress (much faster.)
 
<syntaxhighlight lang="raku" perl6line>sub cleanup { print "\e[0m\e[?25h\n"; exit(0) }
 
signal(SIGINT).tap: { cleanup(); exit(0) }
Line 2,001 ⟶ 3,704:
print "\e[1;1H", @buffer.map( { @color[$_ min 4] }).join;
 
cleanup;</langsyntaxhighlight>
 
Passing in 2048 as a stack size results in: [https://github.com/thundergnat/rc/blob/master/img/Abelian-sandpile-model-perl6.png Abelian-sandpile-model-perl6.png] (offsite .png image)
 
===SDL2 Animation===
<syntaxhighlight lang="raku" perl6line>use NativeCall;
use SDL2::Raw;
 
Line 2,102 ⟶ 3,805:
}
$fps
}</langsyntaxhighlight>
 
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}}==
<langsyntaxhighlight lang="rust">// This is the main algorithm.
//
// It loops over the current state of the sandpile and updates it on-the-fly.
Line 2,228 ⟶ 3,995:
display(&playfield);
//write_pile(&playfield);
}</langsyntaxhighlight>
 
'''Output:'''
Line 2,248 ⟶ 4,015:
</pre>
 
=={{header|Scheme}}==
{{works with|Chez Scheme}}
<syntaxhighlight lang="scheme">; A two-dimensional grid of values...
 
; Create an empty (all cells 0) grid of the specified size.
; Optionally, fill all cells with given value.
(define make-grid
(lambda (size-x size-y . opt-value)
(cons size-x (make-vector (* size-x size-y) (if (null? opt-value) 0 (car opt-value))))))
 
; Return the vector of all values of a grid.
(define grid-vector
(lambda (grid)
(cdr grid)))
 
; Return the X size of a grid.
(define grid-size-x
(lambda (grid)
(car grid)))
 
; Return the Y size of a grid.
(define grid-size-y
(lambda (grid)
(/ (vector-length (cdr grid)) (car grid))))
 
; Return #t if the specified x/y is within the range of the given grid.
(define grid-in-range
(lambda (grid x y)
(and (>= x 0) (>= y 0) (< x (grid-size-x grid)) (< y (grid-size-y grid)))))
 
; Return the value from the specified cell of the given grid.
; Note: Returns 0 if x/y is out of range.
(define grid-ref
(lambda (grid x y)
(if (grid-in-range grid x y)
(vector-ref (cdr grid) (+ x (* y (car grid))))
0)))
 
; Store the given value into the specified cell of the given grid.
; Note: Does nothing if x/y is out of range.
(define grid-set!
(lambda (grid x y val)
(when (grid-in-range grid x y)
(vector-set! (cdr grid) (+ x (* y (car grid))) val))))
 
; Display the given grid, leaving correct spacing for maximum value.
; Optionally, uses a specified digit count for spacing.
; Returns the digit count of the largest grid value.
; Note: Assumes the values in the grid are all non-negative integers.
(define grid-display
(lambda (grid . opt-digcnt)
; Return count of digits in printed representation of integer.
(define digit-count
(lambda (int)
(if (= int 0) 1 (1+ (exact (floor (log int 10)))))))
; Display the grid, leaving correct spacing for maximum value.
(let* ((maxval (fold-left max 0 (vector->list (grid-vector grid))))
(digcnt (if (null? opt-digcnt) (digit-count maxval) (car opt-digcnt))))
(do ((y 0 (1+ y)))
((>= y (grid-size-y grid)))
(do ((x 0 (1+ x)))
((>= x (grid-size-x grid)))
(printf " ~vd" digcnt (grid-ref grid x y)))
(printf "~%"))
digcnt)))
 
; Implementation of the Abelian Sandpile Model using the above grid...
 
; Topple the specified cell of the given Abelian Sandpile Model grid.
; If number of grains in cell is less than 4, does nothing and returns #f.
; Otherwise, distributes 4 grains from the cell to its nearest neighbors and returns #t.
(define asm-topple
(lambda (asm x y)
(if (< (grid-ref asm x y) 4)
#f
(begin
(grid-set! asm x y (- (grid-ref asm x y) 4))
(grid-set! asm (1- x) y (1+ (grid-ref asm (1- x) y)))
(grid-set! asm (1+ x) y (1+ (grid-ref asm (1+ x) y)))
(grid-set! asm x (1- y) (1+ (grid-ref asm x (1- y))))
(grid-set! asm x (1+ y) (1+ (grid-ref asm x (1+ y))))
#t))))
 
; Repeatedly topple unstable cells in the given Abelian Sandpile Model grid
; until all cells are stable.
(define asm-stabilize
(lambda (asm)
(let loop ((any-toppled #f))
(do ((y 0 (1+ y)))
((>= y (grid-size-y asm)))
(do ((x 0 (1+ x)))
((>= x (grid-size-x asm)))
(when (asm-topple asm x y)
(set! any-toppled #t))))
(when any-toppled
(loop #f)))))
 
; Test the Abelian Sandpile Model on a simple grid...
 
(let ((asm (make-grid 9 9)))
(grid-set! asm 4 4 64)
(printf "Before:~%")
(let ((digcnt (grid-display asm)))
(asm-stabilize asm)
(printf "After:~%")
(grid-display asm digcnt)))</syntaxhighlight>
{{out}}
<pre>
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 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
After:
0 0 0 0 0 0 0 0 0
0 0 0 1 2 1 0 0 0
0 0 2 2 2 2 2 0 0
0 1 2 2 2 2 2 1 0
0 2 2 2 0 2 2 2 0
0 1 2 2 2 2 2 1 0
0 0 2 2 2 2 2 0 0
0 0 0 1 2 1 0 0 0
0 0 0 0 0 0 0 0 0
</pre>
 
=={{header|VBA}}==
<langsyntaxhighlight VBAlang="vba">Sub SetupPile(a As Integer, b As Integer)
Application.ScreenUpdating = False
For i = 1 To a
Line 2,397 ⟶ 4,294:
Debug.Print "End:" & Now()
 
End Sub</langsyntaxhighlight>
'''Output:'''
<pre>
On Excel Page
</pre>
 
=={{header|V (Vlang)}}==
{{trans|Go}}
 
<syntaxhighlight lang="v (vlang)">import os
import strings
 
const dim = 16
 
// Outputs the result to the terminal using UTF-8 block characters.
fn draw_pile(pile [][]int) {
chars:= [` `,`░`,`▓`,`█`]
for row in pile {
mut line := []rune{len: row.len}
for i, e in row {
mut elem := e
if elem > 3 { // only possible when algorithm not yet completed.
elem = 3
}
line[i] = chars[elem]
}
println(line.string())
}
}
// Creates a .ppm file in the current directory, which contains
// a colored image of the pile.
fn write_pile(pile [][]int) {
mut file := os.create("output.ppm") or {panic('ERROR creating file')}
defer {
file.close()
}
// Write the signature, image dimensions and maximum color value to the file.
file.writeln("P3\n$dim $dim\n255") or {panic('ERROR writing ln')}
bcolors := ["125 0 25 ", "125 80 0 ", "186 118 0 ", "224 142 0 "]
mut line := strings.new_builder(128)
for row in pile {
for elem in row {
line.write_string(bcolors[elem])
}
file.write_string('${line.str()}\n') or {panic('ERROR writing str')}
line = strings.new_builder(128)
}
}
// Main part of the algorithm, a simple, recursive implementation of the model.
fn handle_pile(x int, y int, mut pile [][]int) {
if pile[y][x] >= 4 {
pile[y][x] -= 4
// Check each neighbor, whether they have enough "sand" to collapse and if they do,
// recursively call handle_pile on them.
if y > 0 {
pile[y-1][x]++
if pile[y-1][x] >= 4 {
handle_pile(x, y-1, mut pile)
}
}
if x > 0 {
pile[y][x-1]++
if pile[y][x-1] >= 4 {
handle_pile(x-1, y, mut pile)
}
}
if y < dim-1 {
pile[y+1][x]++
if pile[y+1][x] >= 4 {
handle_pile(x, y+1, mut pile)
}
}
if x < dim-1 {
pile[y][x+1]++
if pile[y][x+1] >= 4 {
handle_pile(x+1, y, mut pile)
}
}
// Uncomment this line to show every iteration of the program.
// Not recommended with large input values.
// draw_pile(pile)
// Finally call the fntion on the current cell again,
// in case it had more than 4 particles.
handle_pile(x, y, mut pile)
}
}
fn main() {
// Create 2D grid and set size using the 'dim' constant.
mut pile := [][]int{len: dim, init: []int{len: dim}}
// Place some sand particles in the center of the grid and start the algorithm.
hdim := int(dim/2 - 1)
pile[hdim][hdim] = 16
handle_pile(hdim, hdim, mut pile)
draw_pile(pile)
// Uncomment this to save the final image to a file
// after the recursive algorithm has ended.
// write_pile(pile)
}</syntaxhighlight>
 
{{out}}
<pre>
▓░▓
░░ ░░
▓░▓
</pre>
 
=={{header|Wren}}==
{{libheader|Wren-fmt}}
<langsyntaxhighlight ecmascriptlang="wren">import "./fmt" for Fmt
 
class Sandpile {
Line 2,474 ⟶ 4,492:
var str2 = s.toString
printAcross.call(str1, str2)
}</langsyntaxhighlight>
 
{{out}}
Line 2,506 ⟶ 4,524:
0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 1 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|XPL0}}==
<syntaxhighlight lang="xpl0">def Size = 200;
char Pile1(Size*Size), Pile2(Size*Size);
int Spigot, I, X, Y;
[SetVid($13); \VGA 320x200x8
FillMem(Pile1, 0, Size*Size);
FillMem(Pile2, 0, Size*Size);
Spigot:= 400_000;
repeat I:= 0;
for Y:= 0 to Size-1 do
for X:= 0 to Size-1 do
[if X=Size/2 & Y=Size/2 then
[Spigot:= Spigot-4;
Pile1(I):= Pile1(I)+4;
];
if Pile1(I) >= 4 then
[Pile1(I):= Pile1(I)-4;
Pile2(I-1):= Pile2(I-1)+1;
Pile2(I+1):= Pile2(I+1)+1;
Pile2(I-Size):= Pile2(I-Size)+1;
Pile2(I+Size):= Pile2(I+Size)+1;
];
Point(X, Y, Pile1(I)*2);
I:= I+1;
];
I:= Pile1; Pile1:= Pile2; Pile2:= I;
until Spigot < 4;
]</syntaxhighlight>
 
{{out}}
<pre>
[http://www.xpl0.org/rpi/sand.gif]
</pre>
3,028

edits