Created
February 16, 2017 02:23
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| '''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