Last active
October 11, 2024 10:25
-
-
Save jul/65f958566a95b72b6ccff42e0b26db0b to your computer and use it in GitHub Desktop.
triangular game of life with settable rules
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Fractal pseudo randomness