This is my implementation of Conway's Game of Life in Python. Now since I am a novice coder, naturally I have some key doubts:
- The usage of idioms and code redundancies - Are there any small fragments of the program which can be better written?
- The usage of sys.argv - Is my usage of system arguments acceptable? Eg:
$ python 02 1000would mean taking input from 'input02.txt' and running until 1000 generations.
- Finally, in the get_input_matrix method, I use several reversals and appends in order to add empty rows and columns all around the input matrix. What could be better ways to approach this?
Along with all these, I am also wondering if variables are aptly named and the code is well-formatted/well-written, etc.
#!/usr/bin/python from time import sleep import sys # This method is used to input the contents of the input file. # If a matrix: # 0 0 # 0 1 # is present in the input file, # this generates: (adds 'buffer region' on all sides of the input) # 0 0 0 0 # 0 0 0 0 # 0 0 1 0 # 0 0 0 0 # and returns it to the program. def get_input_matrix(f='input.txt'): # Attempt opening user's input file. # If gives error, use default input file. try: inputFile = open(f, 'r') except: print r"Error: Invalid filename. Using 'input.txt'" inputFile = open('input.txt', 'r') finally: matrix = inputFile.readlines() temp =  for line in matrix: temp_line =  for element in line[:-1].split(' '): temp_line.append(int(element)) temp_line.append(0) temp.append(temp_line) buffer_array = [0 for i in range(len(temp_line))] temp.append(buffer_array) temp.reverse() temp.append(buffer_array) temp.reverse() return temp # Prints matrix # 0 1 # 1 0 # as # * # * def print_matrix(matrix, height, width): for i in range(1, height-1): for j in range(1, width-1): if matrix[i][j] == 1: print '*', else: print ' ', print "" def matrix_copy(matrix, height, width): mnew = [[matrix[i][j] for j in range(width)] for i in range(height)] return mnew # Creates the next generation of the matrix. def to_next_generation(matrix, height, width): temp = matrix_copy(matrix, height, width) for i in range(1, height-1): for j in range(1, width-1): count = matrix[i-1][j] + matrix[i-1][j-1] + \ matrix[i][j-1] + matrix[i+1][j-1] + matrix[i+1][j] + \ matrix[i+1][j+1] + matrix[i][j+1] + matrix[i-1][j+1] if count == 2: temp[i][j] = matrix[i][j] elif count == 3: temp[i][j] = 1 elif count < 2 or count > 3: temp[i][j] = 0 matrix = matrix_copy(temp, height, width) return matrix if __name__ == '__main__': # python main.py 02 # would open input02.txt if len(sys.argv) > 1: inputFile = "input" + sys.argv + ".txt" else: inputFile = raw_input("Input file: ") # main matrix for operations matrix = get_input_matrix(inputFile) height, width = (len(matrix), len(matrix)) # prints actual height and width of the computation region print "Height = %d\nWidth = %d" % (height - 2, width - 2) # python main.py xx 1000 # would run the code 1000 times if len(sys.argv) > 2: genLimit = genLimitOriginal = int(sys.argv) else: genLimit = genLimitOriginal = int(raw_input("Enter number \ of generations to be evaluated: ")) # list stores upto 9 previous generations # thus, has a queue like action prev_generations =  Generation = 0 while Generation <= genLimit: # pushing the current generation into the queue if len(prev_generations) < 10: prev_generations.append(matrix) else: prev_generations.remove(prev_generations) prev_generations.append(matrix) # printing the current generation print "## Generation %d ##" % Generation print_matrix(matrix, height, width) # moving to the next generation matrix = to_next_generation(matrix, height, width) # delay in computation sleep(0.05) # if the computation isn't halted before the computation limit # is reached, it may restart for the same amount of time if the # user wants. # Eg: if the number of generations to be evaluated was 1000 # and the user decides to continue, 1000 more generations will # be evaluated by the program. if Generation == genLimit: ch = raw_input("Do you want to continue? (Y/N): ") if ch == 'y' or ch == 'Y': genLimit += genLimitOriginal else: break Generation += 1 # if the current generation has occured in any of the past nine # generations, it will definitely repeat itself. Thus, if such a # case occus, the computation is halted. if matrix in prev_generations: Generation += 1 print "## Generation %d ##" % Generation print_matrix(matrix, height, width) print "Halted at Generation %d" % Generation break
Kindly also let me know if any other changes can be implemented to make this a better program.