Abelian sandpile model: Difference between revisions
Content added Content deleted
m (→{{header|C++}}: cmake syntax) |
|||
Line 1,395: | Line 1,395: | ||
[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_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))] |
[http://alahonua.com/temp/Abel_Z_color_1000000.png Link to PNG output file (run time >90 min) for N=1000000 (move(1000000))] |
||
=={{header|Nim}}== |
|||
<lang Nim> |
|||
# Abelian sand pile. |
|||
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 an array of arrays 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 <= 40: |
|||
grid.display(initVal) |
|||
#grid.writePpmFile(fmt"grid_{initVal}.ppm") |
|||
grid.writePngFile(fmt"grid_{initVal}.png") |
|||
</lang> |
|||
{{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}}== |
=={{header|Pascal}}== |