Abelian sandpile model: Difference between revisions

m
 
(33 intermediate revisions by 22 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">
<lang AArch64 Assembly>
/* ARM assembly AARCH64 Raspberry PI 3B or android 64 bits */
/* program abelian64.s */
Line 229 ⟶ 306:
/* for this file see task include a file in language AArch64 assembly */
.include "../includeARM64.inc"
</syntaxhighlight>
</lang>
{{Output}}
<pre>
Line 260 ⟶ 337:
0 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">
<lang ARM Assembly>
/* ARM assembly Raspberry PI or android 32 bits */
/* program abelian.s */
Line 454 ⟶ 667:
/***************************************************/
.include "../affichage.inc"
</syntaxhighlight>
</lang>
{{output}}
<pre>
Line 485 ⟶ 698:
0 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 608 ⟶ 910:
return 0;
}
</syntaxhighlight>
</lang>
 
Console output :
Line 647 ⟶ 949:
<!-- c++ bindings -->
<br>
<langsyntaxhighlight lang="cpp">#include <iostream>
#include "xtensor/xarray.hpp"
#include "xtensor/xio.hpp"
Line 720 ⟶ 1,022:
 
return 0;
}</langsyntaxhighlight>
Compile with following <tt>CMakeList.txt</tt>:
<langsyntaxhighlight lang="cmake">cmake_minimum_required(VERSION 3.1)
project(abelian_sandpile)
 
Line 736 ⟶ 1,038:
 
target_compile_options(abelian_sandpile PRIVATE -march=native -std=c++14)
target_link_libraries(abelian_sandpile xtensor ${OIIO})</langsyntaxhighlight>
 
=={{header|Delphi}}==
{{Trans|Python}}
<syntaxhighlight lang="delphi">
<lang Delphi>
program Abelian_sandpile_model;
 
Line 900 ⟶ 1,202:
Readln;
end.
</syntaxhighlight>
</lang>
 
 
Line 906 ⟶ 1,208:
{{works with|gforth|0.7.3}}
<br>
<langsyntaxhighlight lang="forth">#! /usr/bin/gforth -d 20M
\ Abelian Sandpile Model
 
Line 971 ⟶ 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 987 ⟶ 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 1,078 ⟶ 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 1,116 ⟶ 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 1,154 ⟶ 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 1,179 ⟶ 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 1,291 ⟶ 1,783:
// after the recursive algorithm has ended.
// writePile(pile)
}</langsyntaxhighlight>
 
{{out}}
Line 1,321 ⟶ 1,813:
<br>
Using a custom monad to make the code cleaner.
<langsyntaxhighlight lang="haskell">{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE ScopedTypeVariables #-}
Line 1,436 ⟶ 1,928:
fp = printf "sandpile_%d_%d.pgm" size height
toPGM b fp
putStrLn $ "wrote image to " ++ fp</langsyntaxhighlight>
 
{{out}}
Line 1,446 ⟶ 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=: - [: +/@(-"2 ((,-)=/~i.2)|.!.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,565 ⟶ 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,847 ⟶ 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}}==
<langsyntaxhighlight lang="lua">local sandpile = {
init = function(self, dim, val)
self.cell, self.dim = {}, dim
Line 1,889 ⟶ 2,474:
sandpile:init(15, 256)
sandpile:iter()
sandpile:draw()</langsyntaxhighlight>
{{out}}
<pre>0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Line 1,908 ⟶ 2,493:
 
=={{header|Mathematica}}/{{header|Wolfram Language}}==
<langsyntaxhighlight Mathematicalang="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];
Line 1,922 ⟶ 2,507:
u = sp[CenterArray[250, {15, 15}]];
u += sp[0];
StringRiffle[StringJoin /@ Map[ToString, u[[1]], {2}], "\n"]</langsyntaxhighlight>
{{out}}
<pre>000000000000000
Line 1,939 ⟶ 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 1,944 ⟶ 2,611:
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">
<lang Nim>
# Abelian sandpile.
 
Line 2,091 ⟶ 2,758:
#grid.writePpmFile(fmt"grid_{initVal}.ppm")
grid.writePngFile(fmt"grid_{initVal}.png")
</syntaxhighlight>
</lang>
 
{{out}}
Line 2,118 ⟶ 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 2,306 ⟶ 2,973:
OneTurn(100000);
END.
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 2,370 ⟶ 3,037:
{{works with|OCaml|4.11}}
In Sandpile module (sandpile.ml)
<syntaxhighlight lang="ocaml">
<lang OCaml>
module Make =
functor (M : sig val m : int val n : int end)
Line 2,450 ⟶ 3,117:
; S.avalanche ()
; S.print ()
</syntaxhighlight>
</lang>
 
=={{header|Perl}}==
<syntaxhighlight lang="perl">use strict;
<lang Perl>#!/usr/bin/perl
 
use strict; # http://www.rosettacode.org/wiki/Abelian_sandpile_model
use warnings;
use feature 'bitwise';
 
my ($high, $wide) = split ' ', qx(stty size);
Line 2,463 ⟶ 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 2,471 ⟶ 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 2,482 ⟶ 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.
<!--<langsyntaxhighlight Phixlang="phix">-->
<span style="color: #000080;font-style:italic;">-- demo\rosetta\Abelian_sandpile_model.exw</span>
<span style="color: #008080;">include</span> <span style="color: #000000;">pGUI</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span>
Line 2,575 ⟶ 3,241:
<span style="color: #000000;">main</span><span style="color: #0000FF;">()</span>
<!--</langsyntaxhighlight>-->
 
=={{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}}==
===Python: Original, with output===
<syntaxhighlight lang="python">import numpy as np
<lang Python>
import numpy as np
import matplotlib.pyplot as plt
 
Line 2,618 ⟶ 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 2,632 ⟶ 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 2,645 ⟶ 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 2,716 ⟶ 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 2,744 ⟶ 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===
<langsyntaxhighlight lang="python">
''' Python 3.6.5 code using Tkinter graphical user
interface (Canvas widget) to display final results.'''
Line 2,863 ⟶ 3,576:
## 0 0 0 0 0 0 0 0 0
## 0 0 0 0 0 0 0 0 0
</syntaxhighlight>
</lang>
 
=={{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 2,871 ⟶ 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,917 ⟶ 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 3,018 ⟶ 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 3,144 ⟶ 3,995:
display(&playfield);
//write_pile(&playfield);
}</langsyntaxhighlight>
 
'''Output:'''
Line 3,164 ⟶ 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 3,313 ⟶ 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 3,390 ⟶ 4,492:
var str2 = s.toString
printAcross.call(str1, str2)
}</langsyntaxhighlight>
 
{{out}}
Line 3,422 ⟶ 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