Skip to content

Instantly share code, notes, and snippets.

@vwood
Created February 16, 2012 04:12
Show Gist options
  • Save vwood/1841911 to your computer and use it in GitHub Desktop.
Save vwood/1841911 to your computer and use it in GitHub Desktop.
Schelling Model
#!/usr/bin/python
import Tkinter as Tk
import random
class Schelling():
"""A Schelling model.
This is a model of a city undergoing dynamic racial segregation."""
race_colors = ["#F9C", "#000", "#FF0", "#F00", "#533"]
def __init__(self, width, height, races = 2):
self.width = width
self.height = height
self.races = races
self.race_array = [[0] * height for x in range(width)]
self.tk_array = [[None] * height for x in range(width)]
self.empty_spaces = []
def populate(self):
self.empty_spaces = []
for x in range(self.width):
for y in range(self.height):
if random.randint(0, 9) == 0:
self.race_array[x][y] = 0
self.empty_spaces.append((x, y))
else:
self.race_array[x][y] = random.randint(1, self.races)
def use_canvas(self, canvas, w, h):
"""Fills the canvas with objects"""
self.canvas = canvas
self.canvas_w = w
self.canvas_h = h
tile_w = self.canvas_w / self.width
tile_h = self.canvas_h / self.height
for x in range(self.width):
for y in range(self.height):
if self.race_array[x][y] == 0:
self.tk_array[x][y] = None
else:
race = self.race_array[x][y]
self.tk_array[x][y] = \
self.canvas.create_rectangle(x * tile_w, y * tile_h,
(x+1) * tile_w, (y+1) * tile_h,
fill=Schelling.race_colors[race - 1])
def update(self, n):
"""Perform N iterations of the is_unhappy check."""
for i in range(n):
x = random.randint(0, self.width - 1)
y = random.randint(0, self.height - 1)
if self.is_unhappy(x,y):
self.move_to_empty(x, y)
def move_to_empty(self, x1, y1):
"""Moves to an empty cell."""
new_cell = random.randint(0, len(self.empty_spaces) - 1)
x2, y2 = self.empty_spaces[new_cell]
self.race_array[x1][y1], self.race_array[x2][y2] = self.race_array[x2][y2], self.race_array[x1][y1]
tile_w = self.canvas_w / self.width
tile_h = self.canvas_h / self.height
self.canvas.coords(self.tk_array[x1][y1], x2 * tile_w, y2 * tile_h, (x2+1) * tile_w, (y2+1) * tile_h)
self.tk_array[x1][y1], self.tk_array[x2][y2] = self.tk_array[x2][y2], self.tk_array[x1][y1]
self.empty_spaces[new_cell] = (x1,y1)
def is_unhappy(self, x, y):
"""A square is unhappy if it does not have at least two similar neighbours.
Empty squares are never unhappy."""
me = self.race_array[x][y]
if me == 0:
return False
count = 0
if x > 0 and self.race_array[x-1][y] == me:
count += 1
if x < self.width - 1 and self.race_array[x+1][y] == me:
count += 1
if y > 0 and self.race_array[x][y-1] == me:
count += 1
if y < self.height - 1 and self.race_array[x][y+1] == me:
count += 1
return count < 2
class SchellingApp():
def __init__(self, w = 400, h = 400):
self.root = Tk.Tk()
self.w = w
self.h = h
self.simulation = Schelling(100, 100, 4)
self.simulation.populate()
self.canvas = Tk.Canvas(self.root, width = w, height = h)
self.canvas.grid(column = 0, row = 0)
self.simulation.use_canvas(self.canvas, w, h)
self.canvas.after(8, self.update)
self.root.mainloop()
def update(self):
self.simulation.update(20)
self.canvas.after(8, self.update)
if __name__ == '__main__':
app = SchellingApp()
@aminehzad
Copy link

Hi,
Can you please explain why you did not use "agents" to create this agent-based model?
Thank you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment