fast-abelian-sandpile/sandpile_arithmetic.py

42 lines
1.2 KiB
Python

"""This one uses integer division to fire columns instead of
repeteadly removing 4 grains."""
import sys
def apply_gravity(terrain):
"""
$ python -m pyperf timeit --fast -s 'from examples.sandpile2 import main' 'main(10_000, False)'
...........
Mean +- std dev: 2.42 sec +- 0.04 sec
"""
width = len(terrain)
while True:
did_someting = False
for x in range(width):
for y in range(width):
if terrain[x][y] >= 4:
div, terrain[x][y] = divmod(terrain[x][y], 4)
terrain[x - 1][y] += div
terrain[x + 1][y] += div
terrain[x][y + 1] += div
terrain[x][y - 1] += div
did_someting = True
if not did_someting:
break
def main(height, show=True):
width = int(height ** .5) + 1
terrain = [[0] * width for _ in range(width)]
terrain[width // 2][width // 2] = height
apply_gravity(terrain)
if show:
import numpy
numpy.set_printoptions(threshold=sys.maxsize, linewidth=999)
print(numpy.array(terrain))
if __name__ == "__main__":
main(int(sys.argv[1]))