def envelope (): # draw stacked layers using same location and scale g.setoption("stacklayers", 1) g.show("Hit escape key to stop script...") while True: g.dokey( g.getkey() ) g.run(1) if g.empty(): g.show("Pattern died out.") break # copy current pattern to envelope layer; # we temporarily disable event checking so thumb scrolling # and other mouse events won't cause confusing changes currpatt = g.getcells(g.getrect()) g.check(0) g.setlayer(envindex) g.putcells(currpatt) g.setlayer(currindex) g.check(1) step = 1 exp = g.getstep() if exp > 0: step = g.getbase()**exp if int(g.getgen()) % step == 0: # display all 3 layers (envelope, start, current) g.update()
def gofast(newgen, delay): ''' Fast goto ''' #Save current settings oldbase = g.getbase() # oldhash = g.setoption("hashing", True) g.show('gofast running, hit escape to abort') oldsecs = time() #Advance by binary powers, to maximize advantage of hashing g.setbase(2) for i, b in enumerate(intbits(newgen)): if b: g.setstep(i) g.step() g.dokey(g.getkey()) newsecs = time() if newsecs - oldsecs >= delay: # do an update every sec oldsecs = newsecs g.update() if g.empty(): break g.show('') #Restore settings # g.setoption("hashing", oldhash) g.setbase(oldbase)
def slideshow (): oldalgo = g.getalgo() oldrule = g.getrule() message = "Hit space to continue or escape to exit the slide show..." g.show(message) for root, dirs, files in os.walk(g.getdir("app") + "Patterns"): for name in files: if name.startswith("."): # ignore hidden files (like .DS_Store on Mac) pass else: fullname = join(root, name) g.open(fullname, False) # don't add file to Open/Run Recent submenu g.update() if name.endswith(".pl") or name.endswith(".py"): # reshow message in case it was changed by script g.show(message) while True: ch = g.getkey() if ch == " ": break g.dokey(ch) # allow keyboard interaction sleep(0.01) # avoid hogging cpu if "CVS" in dirs: dirs.remove("CVS") # don't visit CVS directories # if all patterns have been displayed then restore original algo and rule # (don't do this if user hits escape in case they want to explore pattern) g.new("untitled") g.setalgo(oldalgo) g.setrule(oldrule)
# count all cell states in r g.show("Counting cell states...") counted = 0 totalcells = r.wd * r.ht statecount = [0] * g.numstates() oldsecs = time() for row in xrange(r.top, r.top + r.height): for col in xrange(r.left, r.left + r.width): counted += 1 statecount[g.getcell(col, row)] += 1 newsecs = time() if newsecs - oldsecs >= 1.0: # show % done every sec oldsecs = newsecs done = 100.0 * float(counted) / float(totalcells) g.show("Counting cell states... %.2f%%" % done) g.dokey(g.getkey()) statecount = [int(10 * math.log((x + 1), 2)) for x in statecount] totalcells = sum(statecount) if statecount[0] == counted: g.exit("Selection is empty.") # save current layer's info before we switch layers currname = g.getname() currcursor = g.getcursor() currcolors = g.getcolors() currstates = g.numstates() deads, deadr, deadg, deadb = g.getcolors(0) # create histogram in separate layer g.setoption("stacklayers", 0) g.setoption("tilelayers", 0)
# we first write the commands to a string, and then to the grid # (we start off facing right, at the bottom-left of the construction area) # write the cells that are in state 1 (can ignore the zeros) # (still plenty of room for optimisation here) tape = '11' for row in xrange(r.top, r.top + r.height): # if large selection then give some indication of progress newsecs = time() if newsecs - oldsecs >= 1.0: oldsecs = newsecs g.update() # also allow keyboard interaction g.dokey( g.getkey() ) for col in xrange(r.left, r.left + r.width): if g.getcell(col, row)==1: tape += extend*(4+col-r.left) + extend_left + extend*(r.top+r.height-row) tape += mark tape += retract*(r.top+r.height-row) + retract_left + retract*(4+col-r.left) elif g.getcell(col,row)!=0: g.exit('Cells in the selected area must be in states 0 or 1 only.') # finally we sheath and trigger and retract tape += extend_left + extend*4 + extend_right + extend tape += inject_sheath + '1'*50 + inject_trigger tape += retract*2 + retract_right + retract*4 + retract_left # now write the tape out
def burp(): test_signal=pattern(""" 40bo$41bo$39b3o17$40bo4bo4bo4bo4bo$41bo4bo4bo4bo4bo$39b3o2b3o2b3o2b3o 2b3o3$40bo4bo4bo4bo4bo$41bo4bo4bo4bo4bo$39b3o2b3o2b3o2b3o2b3o3$40bo4bo 4bo4bo4bo$41bo4bo4bo4bo4bo$39b3o2b3o2b3o2b3o2b3o3$40bo4bo4bo4bo4bo$41b o4bo4bo4bo4bo$39b3o2b3o2b3o2b3o2b3o3$bo38bo4bo4bo4bo4bo18bo$2bo38bo4bo 4bo4bo4bo18bo$3o36b3o2b3o2b3o2b3o2b3o16b3o37$40bo$41bo$39b3o!""") prepare_burp() ticks=0 tickstep=5 last_signal=-99999 viewport_speed=16 sel_speed=0.0 delta_sel=0.0 delay=-1.0 run_flag=False ch="" selx=600.0 sely=365.0 place_signal=3 helpstring="""Use ENTER and SPACE to run or halt the pattern; use + and - to change the step size or delay value; use arrow keys and mouse tools to pan and zoom in any pane; T toggles between a tiled view and a single-pane view; S creates another signal fleet near the detection mechanism; R resets the Heisenburp device to its initial state; Q quits out of the script and restores original settings.""" instr="Press H for help. " g.show(instr + str(tickstep)) g.select([selx,sely,50,50]) # keyboard handling while lower(ch)<>"q": if place_signal>0: if ticks-last_signal>1846: test_signal.put(-150,60) last_signal=ticks place_signal-=1 if place_signal>0 and run_flag==True: show_status_text("Next signal placement in " \ + str(1847 - ticks + last_signal) + " ticks. " + instr, delay, tickstep) else: show_status_text(instr,delay,tickstep) ch = g.getkey() if lower(ch)=="r": prepare_burp() ticks=0 last_signal=-99999 viewport_speed=16 sel_speed=0 run_flag=False selx=600.0 sely=365.0 place_signal=3 g.select([selx,sely,50,50]) elif lower(ch)=="h": g.note(helpstring) elif lower(ch)=="t": g.setoption("tilelayers",1-g.getoption("tilelayers")) elif ch=="=" or ch=="+": if delay>.01: delay/=2 elif delay==.01: delay=-1 else: if tickstep==1: tickstep=3 elif tickstep<250: tickstep=(tickstep-1)*2+1 elif ch=="-" or ch=="_": if delay==-1: if tickstep==1: delay=.01 else: if tickstep==3: tickstep=1 else: tickstep=(tickstep-1)/2+1 else: if delay<1: delay*=2 elif ch==" ": run_flag=False elif ch==chr(13): run_flag=not run_flag elif lower(ch)=="s": place_signal+=1 else: g.dokey(ch) # just pass any other keypresses through to Golly # end of keyboard handling # generation and selection speed handling if ch==" " or run_flag==True: g.run(tickstep) currlayer = g.getlayer() if currlayer != 4: # user has switched layer so temporarily change it back # so we only change location of bottom right layer g.check(False) g.setlayer(4) x, y = getposint() oldticks=ticks ticks+=tickstep delta_view=int(ticks/viewport_speed) - int(oldticks/viewport_speed) if delta_view <> 0: # assumes diagonal motion for now setposint(x + delta_view, y + delta_view) sel = g.getselrect() if len(sel)<>0: x, y, w, h = sel if int(selx)<>x: # user changed selection # prepare to move new selection instead (!?!) # -- use floating-point selx, sely to account for fractional speeds selx=x sely=y else: selx+=sel_speed*tickstep sely+=sel_speed*tickstep g.select([selx, sely, w, h]) else: g.select([selx, sely, 50, 50]) if currlayer != 4: g.setlayer(currlayer) g.check(True) # change viewport speed at appropriate times to follow the action if oldticks<4570 and ticks>=4570: sel_speed=.666667 # one-time correction to catch up with the signal at high sim speeds g.select([600+(ticks-4570)*1.5, 365+(ticks-4570)*1.5, w, h]) if selx>2125: sel_speed=0 g.select([2125, sely+2125-selx, w, h]) if oldticks<4750 and ticks>=4750: viewport_speed=1.5 if oldticks<6125 and ticks>=6125: viewport_speed=16 if oldticks>=11995: viewport_speed=99999.9 # stop automatically after the last signal passes through the device if oldticks - last_signal<8705 and ticks - last_signal>=8705: run_flag=False if run_flag==True and delay>0: sleep(delay) g.update()
# store hash/gen/pop/box info at same position in various lists hashlist.insert(pos, h) genlist.insert(pos, int(g.getgen())) poplist.insert(pos, int(g.getpop())) boxlist.insert(pos, pbox) return False # -------------------------------------------------------------------- def fit_if_not_visible(): # fit pattern in viewport if not empty and not completely visible r = rect(g.getrect()) if (not r.empty) and (not r.visible()): g.fit() # -------------------------------------------------------------------- g.show("Checking for oscillation... (hit escape to abort)") oldsecs = time() while not oscillating(): g.run(1) g.dokey( g.getkey() ) # allow keyboard interaction newsecs = time() if newsecs - oldsecs >= 1.0: # show pattern every second oldsecs = newsecs fit_if_not_visible() g.update() fit_if_not_visible()
def goto(gen): currgen = int(g.getgen()) if gen[0] == '+': n = int(gen[1:]) newgen = currgen + n elif gen[0] == '-': n = int(gen[1:]) if currgen > n: newgen = currgen - n else: newgen = 0 else: newgen = int(gen) if newgen < currgen: # try to go back to starting gen (not necessarily 0) and # then forwards to newgen; note that reset() also restores # algorithm and/or rule, so too bad if user changed those # after the starting info was saved; # first save current location and scale midx, midy = g.getpos() mag = g.getmag() g.reset() # restore location and scale g.setpos(midx, midy) g.setmag(mag) # current gen might be > 0 if user loaded a pattern file # that set the gen count currgen = int(g.getgen()) if newgen < currgen: g.error("Can't go back any further; pattern was saved " + "at generation " + str(currgen) + ".") return if newgen == currgen: return g.show("Hit escape to abort...") oldsecs = time() # before stepping we advance by 1 generation, for two reasons: # 1. if we're at the starting gen then the *current* step size # will be saved (and restored upon Reset/Undo) rather than a # possibly very large step size # 2. it increases the chances the user will see updates and so # get some idea of how long the script will take to finish # (otherwise if the base is 10 and a gen like 1,000,000,000 # is given then only a single step() of 10^9 would be done) g.run(1) currgen += 1 # use fast stepping (thanks to PM 2Ring) for i, d in enumerate(intbase(newgen - currgen, g.getbase())): if d > 0: g.setstep(i) for j in xrange(d): if g.empty(): g.show("Pattern is empty.") return g.step() g.dokey( g.getkey() ) # allow keyboard interaction newsecs = time() if newsecs - oldsecs >= 1.0: # do an update every sec oldsecs = newsecs g.update() g.show("")