Hi, i know there's a topic about the game of life called coding challenge, but i actually started this little project before that topic was there, and just want some constructive tips/critc on my little project.
In want to learn python a bit better; So i thought i should write the game of life. I've never actually wrote it before so i thaught it would be a good exercise. <br>
I also never looked at examples besides some stuff in the wikipedia article about GOF, so i might be doing some pretty stupid things, but i just wanted to see if i could implement it when only knowing the basic rules.
So far it's working pretty well, there only seems to be a bug with my corners. (that should wrap around to the other side, but for some reason i haven't found yet it doesn't do that correctly)
Starting the little project i took two basic rules;
- i don't want to iterate x,y a lot, because i rather not care where points actually are.
- everything in python is pass by reference, so let's make some use of that.
the current result of that is the following code:
#!/usr/bin/env python
import os
import random
import time
import sys;
class GameOfLife:
def __init__(self):
self.width=50;
self.height=50; # a place to keep all the points.
self.points = {};
self.short_list = []; # used to keep track of "set" points
self.construct_board();
def construct_board(self):
# create all the needed points on the board
x=1;
id=0;
while x<=self.width:
y=1;
empty_dict = {};
self.points.update({x:{}})
row = self.points[x];
while y<=self.height:
row.update({y:Point(id,x,y)})
id = id + 1;
y = y + 1;
x = x + 1;
# for fast lookup tell every point whom his neigbor is.
# (everything between -1,-1 and +1,+1
x=1;
while x<=self.width:
y=1;
while y<=self.height:
point = self.points[x][y];
if (x-1 <=0): x_minus = self.width;
else: x_minus = x-1;
if x+1 >=self.width: x_plus = 1
else: x_plus = x+1
if (y-1 <=0): y_minus = self.height;
else: y_minus = y-1;
if y+1 >=self.height: y_plus = 1
else: y_plus = y+1
try:
point.add_neighbor(self.points[x_minus][y])
point.add_neighbor(self.points[x_minus][y_minus])
point.add_neighbor(self.points[x_minus][y_plus])
point.add_neighbor(self.points[x][y_minus])
point.add_neighbor(self.points[x][y_plus])
point.add_neighbor(self.points[x_plus][y_minus])
point.add_neighbor(self.points[x_plus][y])
point.add_neighbor(self.points[x_plus][y_plus])
except:
print point.x,point.y
print "x_plus",x_plus
print "x_minus",x_minus
print "y_plus",y_plus
print "y_minus",y_minus
sys.exit();
set_alive=0;
#insert a glider.
if (
(y==11 and x==11)
or
(y==11 and x==12)
or
(y==11 and x==13)
or
(y==12 and x==11)
or
(y==13 and x==12)
): set_alive=1;
#fill the wall
if (
x==1
or
y==1
): set_alive=1
# put some random stuff in
if (random.randint(1,10)==1): set_alive=1;
if (set_alive==1):
status = 1
self.short_list.append(point);
else:
status =0
point.set_status(status);
y = y + 1;
x = x + 1;
def print_board(self,print_type):
y=1;
row = "";
while y<=self.height:
x=1;
row += "\n";
while x<=self.width:
if print_type==1:
if (self.points[x][y].status == 0):
row += " ";
else:
row += "X";
else:
if (self.points[x][y].score>0):
row += str(self.points[x][y].score);
else:
row += " "
x =x + 1;
y = y + 1;
print row;
def step(self):
begin_time = time.time();
gray_list = [];
list = {}; #list is used to keep track of what points we already added (huge lookup time saver)
for point in self.short_list:
if point.id not in list:
gray_list.append(point);
list.update({point.id:point.id});
begin_time_small = time.time();
for neighbor in point.neighbors:
id = neighbor.id;
neighbor.add_score();
if id not in list:
gray_list.append(neighbor);
list.update({id:id});
self.grey_list_time = time.time() - begin_time;
self.short_list = [];
# 1. Any live cell with fewer than two live neighbours dies, as if by loneliness.
# 2. Any live cell with more than three live neighbours dies, as if by overcrowding.
# 3. Any live cell with two or three live neighbours lives, unchanged, to the next generation.
# 4. Any dead cell with exactly three live neighbours comes to life.
## uncomment for point distribution debug ##
#self.print_board(0);
# @TODO this could be so much beter
for point in gray_list:
if (point.score<=1): #die of loneliness
point.status = 0;
point.score = 0;
elif (point.score>=4): #die of over population
point.status = 0;
point.score = 0;
elif (point.status==1 and point.score>=2 and point.score<=3): # has two or 3 neighbors and survives
point.status = 1;
point.score = 0;
self.short_list.append(point);
elif (point.status==0 and point.score==3):
point.status = 1;
point.score = 0;
self.short_list.append(point);
else:
point.status = 0;
point.score = 0;
class Point:
def __init__(self,id,x,y):
self.id=id;
self.x=x;
self.y=y;
self.status=0;
self.score=0;
self.neighbors = [];
def set_status(self,status):
self.status = status;
def add_neighbor(self,point):
self.neighbors.append(point);
def add_score(self):
self.score += 1;
GOL = GameOfLife();
#print "Going to first step";
GOL.print_board(1);
time.sleep(0.5);
resp = raw_input("press enter")
i=1;
while (i<=500):
begin = time.time();
GOL.step();
print time.time() - begin;
#print "step ",i
GOL.print_board(1);
time.sleep(0.2);
i += 1;
# resp = raw_input("press enter")
i'm really looking for comment on how i could have implemented it beter, especially on the part of python specific implementations
Also after i've solved why the borders don't work correctly, i'm probably going to try and make it borderless.
I'm all ready thinking of a idea by only creating the points that are 'alive', and not care much about where they are, but just give them the correct x and y coordinate, even if it's -20 or what not.
The displaying code would get a bit more difficult because of that, but that's not where the speed bottleneck is anyway.
edit:
mmm, aparently some white space lines got eaten in the code; Just so you know i don't actually put methods back to back :)