import golly as g
import random
import math 

def mean(data):
    """Return the sample arithmetic mean of data."""
    n = len(data)
    if n < 1:
        raise ValueError('mean requires at least one data point')
    return sum(data)/n # in Python 2 use sum(data)/float(n)

def _ss(data):
    """Return sum of square deviations of sequence data."""
    c = mean(data)
    ss = sum((x-c)**2 for x in data)
    return ss

def stddev(data, ddof=0):
    """Calculates the population standard deviation
    by default; specify ddof=1 to compute the sample
    standard deviation."""
    n = len(data)
    if n < 2:
        raise ValueError('variance requires at least two data points')
    ss = _ss(data)
    pvar = ss/(n-ddof)
    return pvar**0.5
	
def rand_rule(prob):

	isotropicsetS = isotropicsetB = {"0",
					 "1c", "1e",
					 "2c", "2e", "2k", "2a", "2i", "2n",
					 "3c", "3e", "3k", "3a", "3i", "3n", "3y", "3q", "3j", "3r",
					 "4c", "4e", "4k", "4a", "4i", "4n", "4y", "4q", "4j", "4r", "4t", "4w", "4z",
					 "5c", "5e", "5k", "5a", "5i", "5n", "5y", "5q", "5j", "5r",
					 "6c", "6e", "6k", "6a", "6i", "6n",
					 "7c", "7e",
					 "8"}
	
	isotropicsetB.remove("2a")
	isotropicsetB.remove("0")
	
	rulestr = "B"

	for i in isotropicsetB:
		if random.random() > prob:
			rulestr += i

	rulestr = rulestr + "/S"

	for i in isotropicsetS:
		if random.random() > prob:
			rulestr += i

	g.setrule(rulestr)
	

def radius():
			
	rs = []

	for i in range(18):
		rs.append(r_data())
		g.step()
	
	return mean(rs)
	
def r_data():
	rs = [0.0 for i in range(100)]		
	cells = g.getcells(g.getrect())
		
	for i in range(1, len(cells)):
		x = cells[i - 1]
		y = cells[i]
		
		r = math.sqrt(x * x + y * y)
		t = int(50 * (math.atan2(y, x) / math.pi + 0.999))
		
		rs[t] = max(rs[t], r)
		
	return int(1000 * stddev(rs) / mean(rs))

def is_circular():
		
	r_prev = radius()
	rs = [] 
	violations = 0 
	
	for i in range(16):
		if int(g.getpop()) > 120000:
			break 
		
		g.step()
		r_cur = radius()
		rs.append(r_cur)
		
		if r_cur < 20:
			return (True, rs)
			
		if r_cur > r_prev and r_cur >= 25:
			violations += 1
			
		if violations >= 2: 
			return (False, rs)
		
		r_prev = r_cur
	
	if r_cur < 25:
		return (True, rs)
	else: 
		return (False, rs)

for iter in range(10000000): 

	p_rule= 0.6

	rand_rule(p_rule)
	g.new("")
	g.setbase(2)
	g.setstep(6)
	g.select([-5, -5, 11, 11])
	g.randfill(50)
	g.step()
	
	rect = g.getrect()
	
	if len(rect) == 0:
		continue 
	
	if rect[2] >= 120 and rect[3] >= 120:
		continue
	
	g.step()
	g.step()
	g.step()
	
	rect = g.getrect()
	
	if len(rect) == 0:
		continue 
	
	if rect[2] < 30 or rect[3] < 30:
		continue 
		
	g.setstep(3)
	flag, rs = is_circular()
	if flag:
		g.save(g.getdir("files") + "/Circular/{0}.rle".format(iter), "rle")
	
	g.fit()
	g.show(str((iter, flag, rs)))
	g.update()
