"""File: life_except1.py Purpose: Play John Conway's game of life. This version will simply exit when the user types Ctrl-C Run: python life_except1.py Input: 1. The number of rows and columns in the world 2. The maximum number of generations to display (0 for infinite) 3. Whether the user is entering a probability that an initial cell is alive, or the initial configuration of cells 4. Either (a) The probability that an initial cell is alive, or (b) The initial configuration 5. Whether to pause and wait for input before drawing new generations Output: Prompts for input Each new generation until either all cells have died or the maximum number of generations has been reached. Rules: 1. A living cell with 0 or 1 neighbors dies 2. A living cell with 2 or 3 neighbors survives 3. A living cell with 4 or more neighbors dies 4. A vacant cell with exactly 3 neighbors comes to life Notes: 1. The world is a list of strings. The border of the world (top edge, bottom edge, left edge, right edge) is padded with blank spaces. 2. User input is *not* checked for errors. 3. This version is more modular than the original. """ from random import random from sys import exit #---------------------------------------------------------------------- def gen_world(rows, cols): """Use a random number generator to create the initial world""" world = [] blank_row = (cols+2)*" " world.append(blank_row) prob = float(raw_input("What's the probability of a live cell?\n ")) for i in xrange(rows): row = ' ' for j in xrange(cols): r_prob = random() if r_prob < prob: row = row + 'X' else: row = row + ' ' row = row + ' ' world.append(row) world.append(blank_row) return world #---------------------------------------------------------------------- def read_world(rows, cols): """Read the initial generation from the keyboard. Note that there's no error-checking of user input""" world = [] blank_row = (cols+2)*" " world.append(blank_row) print print "Enter each row of the world: 'X' for living, space for vacant" print "When you've entered the last living cell in a row, hit enter" for i in xrange(rows): input_line = raw_input("") remaining_row_len = cols - len(input_line) row = ' ' + input_line + remaining_row_len*' ' + ' ' world.append(row) world.append(blank_row) return world #---------------------------------------------------------------------- def get_input(): """Get the various user input and create the initial generation""" rows = int(raw_input("How many rows in world?\n ")) cols = int(raw_input("How many columns in world?\n ")) max_gens = int(raw_input("What's max no. of gens (0 for infinite)?\n ")) prob_or_world = raw_input("Probability (p) or initial world (w)?\n ") if prob_or_world == 'p': world = gen_world(rows, cols) else: world = read_world(rows, cols) print "Should program wait (w) or continue (c) after printing world?" wait_char = raw_input(" ") if wait_char == 'w': wait_after_print = True else: wait_after_print = False return (rows, cols, max_gens, world, wait_after_print) #---------------------------------------------------------------------- def print_world(world, rows, cols, wait_after_print, gen): """Print the current generation. If wait_after_print is true, don't continue until the user hits enter.""" for row in world[1:rows+1]: print row[1:cols+1] # print "Done with", gen if wait_after_print: c = raw_input("Hit enter to continue") #---------------------------------------------------------------------- def count_nbhrs(world, i, j, rows, cols): """Determine the number of living neighbors for the cell in row i and column j. Note that cell ij is not a neighbor to itself.""" n_count = 0 for ii in range(i-1,i+2): for jj in range(j-1, j+2): if ii != i or jj != j: if world[ii][jj] == 'X': n_count = n_count + 1 return n_count #---------------------------------------------------------------------- def apply_rules(curr_cell, n_count): """On the basis of what's in the current cell (curr_cell) and its number of neighbors (n_count) determine what will happen in the next generation to this cell""" if n_count < 2: return " " elif n_count > 3: return " " elif n_count == 2: return curr_cell else: # n_count == 3 return "X" #---------------------------------------------------------------------- def find_next_row(world, rows, cols, i): """Create the string corresponding to the next generation in row i.""" row = '' for j in xrange(1,cols+1): n_count = count_nbhrs(world, i, j, rows, cols) what_happens = apply_rules(world[i][j], n_count) row = row + what_happens row = ' ' + row + ' ' return row #---------------------------------------------------------------------- def find_next_gen(world, rows, cols): """Given the current world use the Life rules to find the next generation""" blank_row = (cols+2)*' ' new_world = [blank_row] for i in xrange(1,rows+1): row = find_next_row(world, rows, cols, i) new_world.append(row) new_world.append(blank_row) return new_world #---------------------------------------------------------------------- def somethings_alive(world, rows, cols): """Determine whether at least one cell is alive""" for i in xrange(1, rows+1): for j in xrange(1, cols+1): if world[i][j] == 'X': return True return False #---------------------------------------------------------------------- def play_life(world, rows, cols, max_gens, wait_after_print): """Create successive generations. Generation 0 is the initial generation. The first generation the program computes is generation 1.""" curr_gen = 1 try: while curr_gen != max_gens and somethings_alive(world, rows, cols): world = find_next_gen(world, rows, cols) print_world(world, rows, cols, wait_after_print, curr_gen) curr_gen = curr_gen + 1 except: print "\nBye!" #---------------------------------------------------------------------- if __name__ == "__main__": rows, cols, max_gens, world, wait_after_print = get_input() print_world(world, rows, cols, wait_after_print, 0) play_life(world, rows, cols, max_gens, wait_after_print)