#!/usr/bin/python print """A minimal implementation of Conway's Game of Life. Each cell's survival depends on the number of occupied nearest and next-nearest neighbours (calculated in Grid::step). A living cell dies of overcrowding or loneliness if it has more than three or fewer than two neighbours; a dead cell is brought to life if it has exactly three neighbours (determined in Cell::setNextState). Iain Haslam, June 2005. """ print """For larger scale demo, see http://www.youtube.com/watch?v=JRQGeVxfYmg """ from Tkinter import * root = Tk() class Cell(Label): DEAD = 0 LIVE = 1 def __init__(self,parent): Label.__init__(self,parent,relief="raised",width=2,borderwidth=1) self.bind("<Button-1>", self.toggle) self.displayState(Cell.DEAD) def toggle(self,event): self.displayState(1-self.state) def setNextState(self,numNeighbours): """Work out whether this cell will be alive at the next iteration.""" if self.state==Cell.LIVE and \ (numNeighbours>3 or numNeighbours<2): self.nextState = Cell.DEAD elif self.state==Cell.DEAD and numNeighbours==3: self.nextState = Cell.LIVE else: self.nextState = self.state def stepToNextState(self): self.displayState(self.nextState) def displayState(self,newstate): self.state = newstate if self.state==Cell.LIVE: self["bg"] = "black" else: self["bg"] = "white" class Grid: def __init__(self,parent,sizex,sizey): self.sizex = sizex self.sizey = sizey #numpy.zeros(sizex,sizey) is a better choice, #but an additional dependency might be rude... self.cells = [] for a in range(0,self.sizex): rowcells = [] for b in range(0,self.sizey): c = Cell(parent) c.grid(row=b, column=a) rowcells.append(c) self.cells.append(rowcells) if sizex>10 and sizey>10: #Start with a glider self.cells[10][9].displayState(Cell.LIVE) self.cells[11][10].displayState(Cell.LIVE) self.cells[9][11].displayState(Cell.LIVE) self.cells[10][11].displayState(Cell.LIVE) self.cells[11][11].displayState(Cell.LIVE) def step(self): """Calculate then display the next iteration of the game of life. This function uses wraparound boundary conditions. """ cells = self.cells for x in range(0,self.sizex): if x==0: x_down = self.sizex-1 else: x_down = x-1 if x==self.sizex-1: x_up = 0 else: x_up = x+1 for y in range(0,self.sizey): if y==0: y_down = self.sizey-1 else: y_down = y-1 if y==self.sizey-1: y_up = 0 else: y_up = y+1 sum = cells[x_down][y].state + cells[x_up][y].state + \ cells[x][y_down].state + cells[x][y_up].state + \ cells[x_down][y_down].state + cells[x_up][y_up].state + \ cells[x_down][y_up].state + cells[x_up][y_down].state cells[x][y].setNextState(sum) for row in cells: for cell in row: cell.stepToNextState() def clear(self): for row in self.cells: for cell in row: cell.displayState(Cell.DEAD) if __name__ == "__main__": frame = Frame(root) frame.pack() grid = Grid(frame,25,25) bottomFrame = Frame(root) bottomFrame.pack(side=BOTTOM) buttonStep = Button(bottomFrame,text="Step",command=grid.step) buttonStep.pack(side=LEFT) buttonClear = Button(bottomFrame,text="Clear",command=grid.clear) buttonClear.pack(side=LEFT,after=buttonStep) root.mainloop()