1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267
|
# Initialization script executed by using "import glife".
# Based on python/life/__init__.py in Eugene Langvagen's PLife.
import golly
import sys
import time
__doc__ = """High-level scripting aids for Golly.""";
# --------------------------------------------------------------------
class rect(list):
"""A simple class to make it easier to manipulate rectangles."""
def visible(self):
"""Return true if rect is completely visible in viewport."""
return golly.visrect( [self.x, self.y, self.wd, self.ht] )
def __init__(self, R = []):
if len(R) == 0:
self.empty = True
elif len(R) == 4:
self.empty = False
self.x = self.left = R[0]
self.y = self.top = R[1]
self.wd = self.width = R[2]
self.ht = self.height = R[3]
if self.wd <= 0: raise ValueError("rect width must be > 0")
if self.ht <= 0: raise ValueError("rect height must be > 0")
self.right = self.left + self.wd - 1
self.bottom = self.top + self.ht - 1
else:
raise TypeError("rect arg must be [] or [x,y,wd,ht]")
list.__init__(self, R)
# --------------------------------------------------------------------
# Define some useful synonyms:
# for golly.clear and golly.advance
inside = 0
outside = 1
# for golly.flip
left_right = 0
top_bottom = 1
up_down = 1
# for golly.rotate
clockwise = 0
anticlockwise = 1
# for golly.setcursor (must match strings in Cursor Mode submenu)
draw = "Draw"
pick = "Pick"
select = "Select"
move = "Move"
zoomin = "Zoom In"
zoomout = "Zoom Out"
# --------------------------------------------------------------------
# Define some transformation matrices:
identity = ( 1, 0, 0, 1)
flip = (-1, 0, 0, -1)
flip_x = (-1, 0, 0, 1)
flip_y = ( 1, 0, 0, -1)
swap_xy = ( 0, 1, 1, 0)
swap_xy_flip = ( 0, -1, -1, 0)
# Rotation:
rcw = ( 0, -1, 1, 0)
rccw = ( 0, 1, -1, 0)
# --------------------------------------------------------------------
def rule(s = "B3/S23"):
"""\
Set the rule for the Game of Life.
Although it affects subsequent calls to pattern.evolve(),
only the last call to this function matters for the viewer."""
golly.setrule(s)
# --------------------------------------------------------------------
def description(s):
"""Supply a textual description to the whole pattern."""
for line in s.split("\n"):
print "#D", line
# --------------------------------------------------------------------
def compose(S, T):
"""\
Return the composition of two transformations S and T.
A transformation is a tuple of the form (x, y, A), which denotes
multiplying by matrix A and then translating by vector (x, y).
These tuples can be passed to pattern.__call__()."""
x = S[0]; y = S[1]; A = S[2]
s = T[0]; t = T[1]; B = T[2]
return (x * B[0] + y * B[1] + s, x * B[2] + y * B[3] + t,
(A[0] * B[0] + A[2] * B[1], A[1] * B[0] + A[3] * B[1],
A[0] * B[2] + A[2] * B[3], A[1] * B[2] + A[3] * B[3]))
# --------------------------------------------------------------------
class pattern(list):
"""This class represents a cell list."""
def __add__(self, q):
"""Join patterns."""
return pattern(golly.join(self, q))
def __getitem__(self, N):
"""\
The __getitem__() function is an alias to evolve().
It allows to access the pattern's phases as elements of an array."""
return self.evolve(N)
def __call__(self, x, y, A = identity):
"""The same as 'apply(A).translate(x, y)'."""
return pattern(golly.transform(self, x, y, *A))
def translate(self, x, y):
"""Translate the pattern."""
return self(x, y)
def apply(self, A):
"""\
Apply a matrix transformation to the pattern.
Predefined matrices are:
identity, flip, flip_x, flip_y, swap_xy, swap_xy_flip,
rcw (rotate clockwise) and rccw (rotate counter-clockwise)."""
return self(0, 0, A)
def put(self, x = 0, y = 0, A = identity):
"""Paste pattern into current universe."""
golly.putcells(self, x, y, *A)
def display(self, title = "untitled", x = 0, y = 0, A = identity):
"""Paste pattern into new universe and display it all."""
golly.new(title)
golly.putcells(self, x, y, *A)
golly.fit()
golly.setcursor(zoomin)
def save(self, fn, desc = None):
"""\
Save the pattern to file 'fn' in RLE format.
An optional description 'desc' may be given."""
golly.store(self, fn, desc)
def evolve(self, N):
"""\
Return N-th generation of the pattern.
Once computed, the N-th generation is remembered and quickly accessible.
It is also the base for computing generations subsequent to N-th."""
if N < 0:
raise ValueError("backward evolving requested")
if self.__phases.has_key(N):
return self.__phases[N]
M = 0
for k in self.__phases.keys():
if M < k < N: M = k
p = self.__phases[N] = pattern(golly.evolve(self.__phases[M], N - M))
return p
def __init__(self, P = [], x0 = 0, y0 = 0, A = identity):
"""\
Initialize a pattern from argument P.
P may be another pattern, a cell list, or a multi-line string.
A cell list should look like [x1, y1, x2, y2, ...];
a string may be in one of the two autodetected formats:
'visual' or 'RLE'.
o 'visual' format means that the pattern is represented
in a visual way using symbols '*' (on cell), '.' (off cell)
and '\\n' (newline), just like in Life 1.05 format.
(Note that an empty line should contain at least one dot).
o 'RLE' format means that a string is Run-Length Encoded.
The format uses 'o' for on-cells, 'b' for off-cells and
'$' for newlines.
Moreover, any of these symbols may be prefixed by a number,
to denote that symbol repeated that number of times.
When P is a string, an optional transformation
(x0, y0, A) may be specified.
"""
self.__phases = dict()
if type(P) == list:
list.__init__(self, P)
elif type(P) == pattern:
list.__init__(self, list(P))
elif type(P) == str:
list.__init__(self, golly.parse(P, x0, y0, *A))
else:
raise TypeError("list or string is required here")
self.__phases[0] = self
# --------------------------------------------------------------------
def load(fn):
# note that top left cell of bounding box will be at 0,0
return pattern(golly.load(fn))
# --------------------------------------------------------------------
def getminbox(patt):
# return a rect which is the minimal bounding box of given pattern;
# note that if the pattern is a multi-state list then any dead cells
# are included in the bounding box
minx = sys.maxint
maxx = -sys.maxint
miny = sys.maxint
maxy = -sys.maxint
clist = list(patt)
clen = len(clist)
inc = 2
if clen & 1 == 1:
# multi-state list (3 ints per cell)
inc = 3
# ignore padding int if it is present
if clen % 3 == 1: clen -= 1
for x in xrange(0, clen, inc):
if clist[x] < minx: minx = clist[x]
if clist[x] > maxx: maxx = clist[x]
for y in xrange(1, clen, inc):
if clist[y] < miny: miny = clist[y]
if clist[y] > maxy: maxy = clist[y]
return rect( [ minx, miny, maxx - minx + 1, maxy - miny + 1 ] )
# --------------------------------------------------------------------
def validint(s):
# return True if given string represents a valid integer
if len(s) == 0: return False
s = s.replace(",","")
if s[0] == '+' or s[0] == '-': s = s[1:]
return s.isdigit()
# --------------------------------------------------------------------
def getposint():
# return current viewport position as integer coords
x, y = golly.getpos()
return int(x), int(y)
# --------------------------------------------------------------------
def setposint(x,y):
# convert integer coords to strings and set viewport position
golly.setpos(str(x), str(y))
# --------------------------------------------------------------------
def getstring(prompt):
# this routine is deprecated
golly.warn("Change the script to use the getstring() command\n"+
"from golly rather than from glife.")
golly.exit("")
|