Skip to content

Instantly share code, notes, and snippets.

@jul
Last active October 11, 2024 10:25
Show Gist options
  • Save jul/65f958566a95b72b6ccff42e0b26db0b to your computer and use it in GitHub Desktop.
Save jul/65f958566a95b72b6ccff42e0b26db0b to your computer and use it in GitHub Desktop.
triangular game of life with settable rules
from time import time, sleep
import select
from subprocess import Popen, PIPE
import os
from operator import itemgetter
SZ=15
DIMX=50
DIMY=50
SSP=80
# let's talk to tk/tcl directly
p = Popen(['wish'], stdin=PIPE, stdout=PIPE, stderr=PIPE)
os.set_blocking(p.stdout.fileno(), False)
os.set_blocking(p.stdin.fileno(), False)
os.set_blocking(p.stderr.fileno(), False)
n=0
def puts(s):
global n
n+=1
for l in s.split("\n"):
select.select([], [p.stdin],[])
p.stdin.write((l + "\n").encode())
if back := p.stderr.read():
print(back.decode())
def gets():
ret=p.stdout.read()
if ret:
exec(ret, globals())
puts(f"""
package require Tk
set code [ catch {{
source /usr/share/tcltk/ttkthemes/themes/plastik/plastik.tcl
ttk::style theme use plastik
}} pass ]
set status 0
proc SaveAsC {{}} {{
set out [tk_getSaveFile]
set code [ catch {{.c postscript -file $out }} result ]
if {{$result != ""}} {{
error $result
}}
}}
proc SaveAsC2 {{}} {{
set out [tk_getSaveFile]
set code [ catch {{.c2 postscript -file $out }} result ]
if {{$result != ""}} {{
error $result
}}
}}
if {{$code}} {{
puts "print('theme not found, fallback to ugly tcl/tk look')"
puts "print('on debian : apt install tcl-ttkthemes to have ttkthemes installed')"
}}
pack [ ttk::frame .t ]
pack [ ttk::frame .tt1 ] -in .t -anchor s -side left
pack [ ttk::frame .tt2 ] -in .t -anchor s -side left
pack [ ttk::label .ll2 -text "board of the game of life" ] -in .tt1
pack [ canvas .c -width {DIMX*SZ*1.01} -height { DIMY*SZ*.87 } -bg white ] -in .tt1 -anchor s
pack [ttk::button .bc -text "Save as postscript" -command SaveAsC ] -in .tt1 -anchor s
pack [ ttk::label .ll1 -text "x,y = u(n-1),u(n) aka Takens Serie " ] -in .tt2 -anchor s
pack [ canvas .c2 -width {DIMX*SZ*1.01} -height { DIMY*SZ*.87 } -bg white ] -in .tt2 -anchor s
.c configure -bg white
pack [ttk::button .bc2 -text "Save as postscript" -command SaveAsC2 ] -in .tt2 -anchor s
pack [ ttk::frame .first ] -expand true -fill both -anchor s
pack [ ttk::label .s -textvariable status ] -anchor s -in .first
pack [ ttk::frame .f ] -anchor s -expand true -fill both
pack [ ttk::frame .center ] -anchor s -in .f
ttk::button .r -text Reset -command {{ puts seed() }}
ttk::button .b -text Pause -command {{ puts pause^=True }}
ttk::button .quit -text Quit -command {{ destroy . }}
pack .r .b .quit -in .center -anchor se -side left
pack [ ttk::labelframe .rules -text "rules change" ] -in .f -expand true -fill both -padx 5 -pady 5
pack [ ttk::frame .g ] -anchor s -expand true -fill both -in .rules -padx 5
pack [ ttk::checkbutton .v1 -text 1 -command {{ puts "seed();set_alive^=set({1,})" }}] -in .g -anchor w -side left
pack [ ttk::label .s1 -text " " ] -in .g -anchor w -side left
pack [ ttk::checkbutton .v2 -text 2 -command {{ puts "seed();set_alive^=set({2,})" }}] -in .g -anchor w -side left
pack [ ttk::label .s2 -text " " ] -in .g -anchor w -side left
pack [ ttk::checkbutton .v3 -text 3 -command {{ puts "seed();set_alive^=set({3,})" }}] -in .g -anchor w -side left
pack [ ttk::label .s3 -text " " ] -in .g -anchor w -side left
pack [ ttk::checkbutton .v4 -text 4 -command {{ puts "seed();set_alive^=set({4,})" }}] -in .g -anchor w -side left
pack [ ttk::label .s4 -text " " ] -in .g -anchor w -side left
pack [ ttk::checkbutton .v5 -text 5 -command {{ puts "seed();set_alive^=set({5,})" }}] -in .g -anchor w -side left
pack [ ttk::label .s5 -text " " ] -in .g -anchor w -side left
pack [ ttk::checkbutton .v6 -text 6 -command {{ puts "seed();set_alive^=set({6,})" }}] -in .g -anchor w -side left
pack [ ttk::label .s6 -text " " ] -in .g -anchor w -side left
pack [ ttk::label .v -text "neighbour alive to give life" ] -in .g -anchor w -side left
.v5 invoke
.v4 invoke
pack [ ttk::frame .h ] -anchor s -expand true -fill both -in .rules -padx 5
pack [ ttk::checkbutton .d1 -text 1 -command {{ puts "seed();set_dead^=set({1,})" }}] -in .h -anchor w -side left
pack [ ttk::label .t1 -text " " ] -in .h -anchor w -side left
pack [ ttk::checkbutton .d2 -text 2 -command {{ puts "seed();set_dead^=set({2,})" }}] -in .h -anchor w -side left
pack [ ttk::label .t2 -text " " ] -in .h -anchor w -side left
pack [ ttk::checkbutton .d3 -text 3 -command {{ puts "seed();set_dead^=set({3,})" }}] -in .h -anchor w -side left
pack [ ttk::label .t3 -text " " ] -in .h -anchor w -side left
pack [ ttk::checkbutton .d4 -text 4 -command {{ puts "seed();set_dead^=set({4,})" }}] -in .h -anchor w -side left
pack [ ttk::label .t4 -text " " ] -in .h -anchor w -side left
pack [ ttk::checkbutton .d5 -text 5 -command {{ puts "seed();set_dead^=set({5,})" }}] -in .h -anchor w -side left
pack [ ttk::label .t5 -text " " ] -in .h -anchor w -side left
pack [ ttk::checkbutton .d6 -text 6 -command {{ puts "seed();set_dead^=set({6,})" }}] -in .h -anchor w -side left
pack [ ttk::label .t6 -text " " ] -in .h -anchor w -side left
pack [ ttk::label .d -text "neighbour dead to give life" ] -in .h -anchor w -side left
.d2 invoke
pack [ ttk::frame .l ] -expand true -fill both -in .rules -padx 5 -pady 5
set seed 50
pack [ ttk::spinbox .sc -width 4 -from 0 -to 100 -textvariable seed -command {{
puts "dead_alive_percent=$seed;seed()"
}}
] -in .l -anchor w -side left
pack [ ttk::label .scl -text " re seed session with a different percentage of dead/alive ratio" ] -in .l -anchor w -side left
pack [ ttk::frame .k ] -expand true -fill both
pack [ ttk::checkbutton .tb -text "disable printing of board" -command "puts {{print_board^=True}}" ] -in .k -anchor w -side left -padx 5 -pady 5
pack [ ttk::frame .kk ] -expand true -fill both
pack [ ttk::checkbutton .tcv -text "disable saving of canvas" -command "puts {{save_canvas^=True}}" ] -in .kk -anchor w -side left -padx 5 -pady 5
""")
from random import randint
from os import system
system("rm *ps output2.mp4 ev*.jpg")
seed=int(time())
print("seed %d" % seed)
save_canvas = True
ORD=1
def save(name="save"):
global ORD, save_canvas
ORD+=1
puts(f"set status {ORD}")
puts(f""".c postscript -file {name}-{"%04d"% ORD}.ps""")
puts(f""".c2 postscript -file t{name}-{"%04d"% ORD}.ps""")
def cell(x,y, **kw):
hs=0.866 # heigth of an equilateral triangle
px,py=x/2-1/2*(y%2),y-2/3
#px,py=x-(y%2),y-2/3
xr,yr=px*SZ+SZ,py*hs*SZ+SZ
# triangle compliqué à dessiner
r=SZ/2
#from pdb import set_trace; set_trace()
puts(f"""
.c create oval {xr-r} {yr-r} {xr+r} {yr+r} -width 0 -outline "" {["","-fill black "][kw.get("state","dead")=="alive"]} -tags [ list "p:{x//2},{y}" ]\n""")
def get_neighbour(x,y):
ye = [(-1, -1), (1, 0), (0, -1), (-1, 1), (-1,0), (0, 1)]
yo= [(1, 1), (-1, 0), (0, -1), (1, 0), (0, 1), (1, -1) ]
return set( ((dxdy[0]+x)%DIMX,(y+dxdy[1])%DIMY) for dxdy in [yo,ye][y%2])
def clear():
global ORD
ORD=0
system("rm *ps output2.mp4 ev*.jpg")
puts(".c delete all")
puts(".c2 delete all")
pick_sample()
seen=set()
old_alive=set()
new_alive=set()
dead_alive_percent=50
def seed():
global seen, old_alive, dead_alive_percent
clear()
for x in range(0,DIMX*2,2):
for y in range(DIMY):
state = randint(0, 100) >= dead_alive_percent and "alive" or "dead"
if state=="alive":
old_alive.update(((x/2,y),),)
assert {(x,y)} not in seen
cell(
x,
y,
state=state,
outline="black")
seen.update(((x,y),),)
#assert get_real_neighbour(3,3)==get_neighbour(3,3)
def live_neighbour(x,y):
return sum(map(lambda x : x in old_alive,get_neighbour(x,y)))
old_old_sample=0
old_sample=0
sample = 0
sample_mask=set([])
def pick_sample():
global sample_mask
sample_mask=set([])
for i in range(SSP):
x, y=(randint(0, DIMX),randint(0, DIMY))
sample_mask |= set([( x, y, )])
def plot_sample():
global old_sample, old_old_sample,DIMY, sample_mask, new_alive, ORD, SZ, sample
old_old_sample=old_sample
old_sample = sample
sample = 0
for i, coord in enumerate(sample_mask):
if coord in old_alive:
sample |= 1<<i
_max = ((1<<(len(sample_mask)))/8)
r=_max/SZ//4
if ORD > 1:
_max = ((1<<(len(sample_mask))) // SZ*2)
puts(f""".c2 create oval {(old_sample-r)*DIMX*1.7//_max} {(sample-r)*1.7*DIMY//_max} {(old_sample+r)*DIMX*1.7//_max} {(sample+r)*DIMY*1.7//_max}""")
# puts(f""".c2 create line {(old_old_sample)*DIMX//_max} {(old_sample)*DIMY//_max} {(old_sample)*DIMX//_max} {(sample)*DIMY//_max}""")
set_alive=set([])
set_dead=set([])
def will_live(x,y):
global new_alive, old_alive, set_dead, set_alive
ostate = (x,y) not in old_alive and 'dead' or "alive"
lively = live_neighbour(x,y)
#print("%d-%d:%s:%d" % (x,y,ostate,lively))
state = ( ostate == "alive" and lively in set_alive ) or (
ostate == "dead" and lively in set_dead )
if(state): new_alive.update(((x,y),))
return state
ORD=0
save("ev")
pause=False
print_board=True
seed()
while True:
gets()
while pause:
sleep(.1)
gets()
for x in range(DIMX):
for y in range(DIMY):
will_live(x,y)
print_board and puts(f""".c itemconfigure "p:{x},{y}" -fill {["white", "black"][(x,y) in new_alive]}""")
plot_sample()
puts("update")
old_alive=new_alive
save("ev")
new_alive=set()
@jul
Copy link
Author

jul commented Oct 10, 2024

Fractal pseudo randomness

takens_life

@jul
Copy link
Author

jul commented Oct 10, 2024

All leads to sirpinsly
takens_life_notequi

@jul
Copy link
Author

jul commented Oct 10, 2024

50 shades of Sirpinsky drawn randomly

image

@jul
Copy link
Author

jul commented Oct 10, 2024

50 shades of sirpinsky triangles :D

sirpinsky2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment