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 1000
would 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 = [0]
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[1] + ".txt"
else:
inputFile = raw_input("Input file: ")
# main matrix for operations
matrix = get_input_matrix(inputFile)
height, width = (len(matrix), len(matrix[0]))
# 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[2])
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[0])
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.