conway_complet.py

Created by florian-allard

Created on February 18, 2021

7.71 KB

Cet automate cellulaire ou Jeu de la vie (Game of Life), dont le principe vient de John Horton Conway, simule l’évolution d’une colonie de cellules. Le plateau se comporte comme un tore, les bords se recollent. Le menu permet de choisir la forme des cellules, l’espacement entre les cellules, un placement initial aléatoire ou au choix de l’utilisateur, l’affichage en couleur du vieillissement des cellules, le nombre de cycles à effectuer et afficher, faire une pause à la fin de chaque cycle… Il permet également de modifier (avec les flèches haut et bas) les règles de naissance et de survie.


from kandinsky import draw_string,set_pixel,fill_rect
from random import randint
from ion import *
from time import sleep
kd = keydown
KL = KEY_LEFT
KR = KEY_RIGHT
KU = KEY_UP
KD = KEY_DOWN
KO = KEY_OK
KE = KEY_EXE
KS = KEY_SHIFT

def menu(chaine,var,dec,mode,choix1,choix2):
  draw_string(chaine,10,v,'orange')
  draw_string("<"+" "*(5+dec)+">",10+len(chaine)*10,v,'blue')
  while not (kd(KE) or kd(KO)):
    if mode == "nombre":
      sleep(0.08)
      var = (var-mini+kd(KR)-kd(KL)+10*kd(KU)-10*kd(KD))%(maxi-mini+1)+mini
      draw_string(" "+str(var)+" "+"px "*(dec>0),(len(chaine)+2)*10+5*dec-5*len(str(var))+15*(dec==0),v,'purple')
    else:#mode booléen
      draw_string([choix2,choix1][var],(len(chaine)+3)*10,v,'purple')
      if kd(KL) or kd(KR):
        var = not var
        while kd(KL) or kd(KR):True
  while kd(KE) or kd(KO):True
  return var

def curseur(couleur):
  for pos in [0,1]:
    fill_rect(dg+d*col+pos*(c+(s==3))+(s==1)+4*(s==2)-(s==3),dh+d*lig-2*(s==0)+5*(s==1)+2*(s==2)-(s==3),1,c+(s==3),couleur)
    fill_rect(dg+d*col+(s==1)+4*(s==2)-(s==3),dh+d*lig+pos*(c-(s==1)+(s==3))-2*(s==0)+5*(s==1)+2*(s==2)-(s==3),1+c+(s==3),1,couleur)

def carre(i,j,couleur):
  if rapide:
    for u in D:
      for v in D:
        set_pixel(dg+d*j+u,dh+d*i+v,couleur)
  else:
    fill_rect(dg+d*j,dh+d*i,c,c,couleur)

def init():
  global v,mini,maxi,dg,dh,col,lig,a,b,A,B,d,D,c,e,s,S,alea,clr,N,Naissance,Survie,Liste,rapide,pause
  v = 10
  S = ['o',chr(215),chr(176),' ']
  s = 3
  draw_string("Forme des cellules : ",10,v,'orange')
  draw_string("<   >",22*10,v,'blue')
  while not (kd(KE) or kd(KO)):
    if s == 3:
      fill_rect(24*10+3,v+6,5,5,'purple')
    if kd(KL) or kd(KR):
      s = (s+kd(KR)-kd(KL))%len(S)
      draw_string(S[s],24*10-2*(s==2),v+4*(s==2)-2*(s==0),'purple')
      while kd(KL) or kd(KR):True
  while kd(KE) or kd(KO):True

  vv = 23-4*(s==3)
  v += vv
  alea = menu("Disposition : ",True,6,"booléen","aléatoire","à choisir")

  v += vv
  clr = menu("Vieillissement : ",True,7,"booléen","en couleur","monochrome")

  c = 9-2*s
  mini = (s+2)%4+1+(s==2)

  if s == 3:
    v += 20
    rapide = menu("Placement : ",True,3,"booléen","rapide","fluide")
    v += 20
    mini = 1
    maxi = 15
    c = menu("Taille des cellules : ",7,2,"nombre","","")
    mini = max(0,5-c) #espacement minimal sans avoir d'erreur de mémoire saturée

  maxi = 9

  v += vv
  e = menu("Espacement : ",4,1,"nombre","","")

  Naissance = [3]
  Survie = [2,3]
  v += vv
  draw_string("Nombre de voisins pour",10,v,'orange')
  for k in [0,1]:
    etape = [Naissance,Survie][k]
    v += 20-2*(s==3)
    draw_string(["naître : ","survivre : "][k],20,v,'orange')
    for n in range(9):
      draw_string(str(n),130+20*n,v,['grey','purple'][n in etape])
    pos = 3
    while not (kd(KE) or kd(KO)):
      if kd(KL) or kd(KR):
        for m in [-1,1]:
          draw_string(" ",130+20*pos+10*m,v)
        pos = (pos+(kd(KR)-kd(KL)))%9
      draw_string("[",130+20*pos-10,v,'blue')
      draw_string("]",130+20*pos+10,v,'blue')
      sleep(0.08)
      if kd(KU) or kd(KD):
        if pos in etape:
          etape.remove(pos)
        else:
          etape.append(pos)
        draw_string(str(pos),130+20*pos,v,['grey','purple'][pos in etape])
        while kd(KU) or kd(KD):True
    while kd(KE) or kd(KO):True

  v += vv
  mini = 1
  maxi = 999
  N = menu("Nombre de cycles : ",50,0,"nombre","","")

  v += vv
  pause = menu("Pause en fin de cycle : ",False,0,"booléen","oui","non")

  d = c+e
  D = range(c)
  a = 222//d
  b = 320//d
  A = range(a)
  B = range(b)
  dg = (320%d+e)//2-2*(s==1)-4*(s==2)
  dh = (222%d+e)//2-5*(s==1)-2*(s==2)+(s==0)
  Liste = [[0 for col in B] for lig in A]
  fill_rect(1,1,320,222,'white')

  if alea:
    for lig in A:
      for col in B:
        Liste[lig][col] = 2*randint(0,1)
        if Liste[lig][col] == 2:
          if s < 3:
            draw_string(S[s],dg+d*col,(dh+d*lig)*(1-2*(s==0))+207*(s==0),'blue')
          else:
            carre(lig,col,'blue')
  else:
    col = b//2
    lig = a//2
    while not (kd(KU) or kd(KD) or kd(KL) or kd(KR) or kd(KE) or kd(KO) or kd(KS)):
      draw_string("Flèches pour se déplacer",40,30,'orange')
      draw_string("EXE ou OK pour afficher/cacher",10,48,'orange')
      draw_string("SHIFT pour lancer la partie",25,66,'orange')
    fill_rect(10,30,300,84,'white')
    while not kd(KS):
      sleep(0.08)
      curseur('orange')
      K = kd(KR)-kd(KL)
      L = kd(KD)-kd(KU)
      if K != 0 or L != 0:
        curseur('white')
        lig = (lig+L)%a 
        col = (col+K)%b
        if s == 3 and e == 0:
          for rangl in [-2,-1,0,1,2]:
            for rangc in [-2,-1,0,1,2]:
              if Liste[(lig+rangl)%a][(col+rangc)%b] > 0:
                carre(lig+rangl,col+rangc,'blue')

      if kd(KE) or kd(KO):
        Liste[lig*(1-2*(s==0))+(a-1)*(s==0)][col*(1-2*(s==2))+(b-1)*(s==2)] = 2-Liste[lig*(1-2*(s==0))+(a-1)*(s==0)][col*(1-2*(s==2))+(b-1)*(s==2)]
        couleur = ['white','blue'][Liste[lig*(1-2*(s==0))+(a-1)*(s==0)][col*(1-2*(s==2))+(b-1)*(s==2)] > 0]
        if s < 3:
          draw_string(S[s],dg+d*col,dh+d*lig-7*(s==0),couleur)
          if s == 0 and e < 5 and lig > 0:
            for rang in range(a-lig,a):
              if Liste[rang][col] == 0:break
              draw_string(S[s],dg+d*col,dh+d*(a-rang-1)-7*(s==0),'blue')
          if s == 1 and e < 5:
            for rang in range(lig+1,a):
              if Liste[rang][col] == 0:break
              draw_string(S[s],dg+d*col,dh+d*rang,'blue')
          if s == 2:
            for rangc in range(b-col-1,b-col*(e>3)):
              for rangl in range(lig,a):
                if Liste[rangl][rangc] > 0: 
                  draw_string(S[s],dg+d*(b-1-rangc),dh+d*rangl,'blue')
        else:
          carre(lig,col,couleur)
      while kd(KE) or kd(KO):True
  curseur('white')

def main():
  for gen in range(N):
    for i in A:
      for j in B:
        Voisins = 0
        for k in [-1,0,1]:
          for l in [-1,0,1]:
            if [k,l] != [0,0] and Liste[(i+k)%a][(j+l)%b]**2 > 3:
              Voisins += 1
        if (Liste[i][j] == 0 and Voisins in Naissance) or (Liste[i][j] > 0 and Voisins in Survie):
          Liste[i][j] += 1
          couleur = (clr*min(25*Liste[i][j]-25,255),0,max(0,255+clr*(25-25*Liste[i][j])))
        else:
          Liste[i][j] *= -1
          couleur = 'white'
        if Liste[i][j] != 0:
          if s < 3:
            draw_string(S[s],dg+d*j*(1-2*(s==2))+d*(b-1)*(s==2),(dh+d*i)*(1-2*(s==0))+207*(s==0),couleur)
          else:
            carre(i,j,couleur)
    for i in A:
      for j in B:
        Liste[i][j] = 2*((max(0,Liste[i][j])+1)//2)

    aff = 0
    while kd(KS) or (pause and not (kd(KE) or kd(KO))):
      draw_string(str(gen+N*relance+1)*kd(KS),160,110,'red')
      aff = max(aff,kd(KS))
    draw_string(" "*len(str(gen+N*relance+1))*aff,160,110)

choix = 0
while 1:
  if choix == 0:
    init()
    relance = -1
  relance += 1
  main()
  while not (kd(KE) or kd(KO)):True
  while kd(KE) or kd(KO):
    draw_string("Maintenir SHIFT en pleine partie",0,30,'orange')
    draw_string("pour mettre en pause et afficher",0,48,'orange')
    draw_string("le numéro du cycle terminé.",0,64,'orange')
    draw_string(" Cycle : "+str(N*(relance+1))+" ",110-5*len(str(N*(relance+1))),102,'red')
    draw_string("   Poursuivre   ",80,122,'purple')
    draw_string("   Retour au menu   ",60,140,'purple')
  while not (kd(KE) or kd(KO)):
    draw_string("[",70+20*choix,140-18*choix,'blue')
    draw_string("]",240-20*choix,140-18*choix,'blue')
    if kd(KD) or kd(KU):
      draw_string(" ",70+20*choix,140-18*choix)
      draw_string(" ",240-20*choix,140-18*choix)
      choix = 1-choix
      while kd(KD) or kd(KU):True
  while kd(KE) or kd(KO):True
  fill_rect(0,30*choix,320,222-158*choix,'white')
  fill_rect(90,102,180,56,'white')