Skip to content

Instantly share code, notes, and snippets.

@carneloot
Created February 16, 2017 02:23
Show Gist options
  • Select an option

  • Save carneloot/2a1369beb6352354396a9cceaba35a47 to your computer and use it in GitHub Desktop.

Select an option

Save carneloot/2a1369beb6352354396a9cceaba35a47 to your computer and use it in GitHub Desktop.
A Sandpile class created in Python to simplify the calculations explained in this Numberphile video https://www.youtube.com/watch?v=1MtEUErz7Gg
'''Sandpile class'''
class Sandpile:
'''A mathmatical sandpile.'''
def __init__(self, pile, cols, rows):
self.cols = cols
self.rows = rows
self.pile = pile
def __str__(self):
string = ""
for i, item in enumerate(self.pile):
string += str(item) + " "
if (i + 1) % self.cols == 0:
string += "\n"
return string
def __add__(self, other):
if self.cols == other.cols and self.rows == other.rows:
pile = self.pile.copy()
for item in enumerate(pile):
pile[item[0]] += other.pile[item[0]]
return Sandpile(pile, self.cols, self.rows)
else:
raise ValueError("Size of the piles is different. Must be same size to add.")
def __sub__(self, other):
raise ArithmeticError("Cannot subtract sandpiles.")
def __pow__(self, exp):
pile = self.pile.copy()
for item in enumerate(pile):
pile[item[0]] = pile[item[0]] ** exp
return Sandpile(pile, self.cols, self.rows)
def topple(self):
'''This method topples the sandpile.'''
i = 0
while i < len(self.pile):
if self.pile[i] >= 4:
coords = self.get_coords(i)
self.distribute(coords)
i = 0
continue
i += 1
return self
def distribute(self, coords):
'''This function ditributes the 'sand' in the spot specified.'''
cell = self.get_index(coords)
times_four = self.pile[cell] // 4
self.pile[cell] -= 4 * times_four
for neighbor in Sandpile.get_neighbors(coords):
index = self.get_index(neighbor)
if index is not None:
self.pile[index] += times_four
def get_coords(self, index):
'''Gets an index and returns a tuple as Coords.'''
row = index // self.rows
col = index - (row * self.rows)
return (col, row)
def get_index(self, coords):
'''Gets coords and returns a index number.'''
col = coords[0]
row = coords[1]
if col < 0 or row < 0 or col > self.cols - 1 or row > self.rows - 1:
return None
return col + row * self.cols
@staticmethod
def get_neighbors(coords):
'''This functions returns the neighbors of the passed spot.'''
col = coords[0]
row = coords[1]
neighbors = [(col - 1, row), (col, row + 1), (col + 1, row), (col, row - 1)]
return neighbors
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment