π
<-

Un démineur en python pour la NumWorks

Re: Un démineur en python pour la NumWorks

Unread postby Bisam » 27 Feb 2020, 11:05

Je pense clairement que ce qui plombe le script est l'utilisation répétée de p.append(...) et del p[0].
La gestion de la mémoire pour les listes Python est telle que lorsque l'on ne cesse de les faire changer de taille, la taille de stockage augmente.
En utilisant à la place 3 couples de coordonnées (actual, new, old), on y gagne forcément car les couples d'entiers ont une taille mémoire fixe.

Cet après-midi, je prendrai un peu de temps pour essayer de faire les modifications en ce sens.
User avatar
BisamAdmin
Niveau 15: CC (Chevalier des Calculatrices)
Niveau 15: CC (Chevalier des Calculatrices)
Level up: 69.6%
 
Posts: 5670
Joined: 11 Mar 2008, 00:00
Location: Lyon
Gender: Male
Calculator(s):
MyCalcs profile

Re: Un démineur en python pour la NumWorks

Unread postby critor » 27 Feb 2020, 12:30

J'ai un script qui marche avec les 16K de tas de la NumWorks, mais je n'ose pas le présenter encore parce que c'est du saccage. :p

Effectivement, sur NumWorks, à chaque fois que l'on a envie d'utiliser une liste/tuple ou pire comme ici liste de listes, il faut se demander si il n'y aurait pas moyen de s'en passer.
Image
User avatar
critorAdmin
Niveau 19: CU (Créateur Universel)
Niveau 19: CU (Créateur Universel)
Level up: 48%
 
Posts: 41981
Images: 15887
Joined: 25 Oct 2008, 00:00
Location: Montpellier
Gender: Male
Calculator(s):
MyCalcs profile
YouTube: critor3000
Twitter: critor2000
GitHub: critor

Re: Un démineur en python pour la NumWorks

Unread postby Extra44 » 27 Feb 2020, 12:37

Bisam wrote:Je pense clairement que ce qui plombe le script est l'utilisation répétée de p.append(...) et del p[0].
La gestion de la mémoire pour les listes Python est telle que lorsque l'on ne cesse de les faire changer de taille, la taille de stockage augmente.
En utilisant à la place 3 couples de coordonnées (actual, new, old), on y gagne forcément car les couples d'entiers ont une taille mémoire fixe.


Je dirais que ...
C'est bien vu !
:D

Donc
+1
User avatar
Extra44Premium
Niveau 11: LV (Légende Vivante)
Niveau 11: LV (Légende Vivante)
Level up: 58.4%
 
Posts: 591
Images: 1
Joined: 20 Jan 2011, 00:00
Gender: Male
Calculator(s):
MyCalcs profile
Class: S.I.

Re: Un démineur en python pour la NumWorks

Unread postby critor » 27 Feb 2020, 13:05

Extra44 wrote:
Bisam wrote:Je pense clairement que ce qui plombe le script est l'utilisation répétée de p.append(...) et del p[0].
La gestion de la mémoire pour les listes Python est telle que lorsque l'on ne cesse de les faire changer de taille, la taille de stockage augmente.
En utilisant à la place 3 couples de coordonnées (actual, new, old), on y gagne forcément car les couples d'entiers ont une taille mémoire fixe.


Je dirais que ...
C'est bien vu !
:D

Donc
+1


Non, ça ça ne joue pas, ou du moins pas pour l'instant.
L'erreur de mémoire étant immédiate au chargement du script, c'est-à-dire avec la simple création des fonctions et variables globales en mémoire.

Donc ce sont les fonctions ainsi que les structures de données choisies pour les variables globales qui seraient à optimiser.

Après, on pourra voir si une erreur de mémoire peut effectivement se déclencher en cours de partie.
Image
User avatar
critorAdmin
Niveau 19: CU (Créateur Universel)
Niveau 19: CU (Créateur Universel)
Level up: 48%
 
Posts: 41981
Images: 15887
Joined: 25 Oct 2008, 00:00
Location: Montpellier
Gender: Male
Calculator(s):
MyCalcs profile
YouTube: critor3000
Twitter: critor2000
GitHub: critor

Re: Un démineur en python pour la NumWorks

Unread postby critor » 27 Feb 2020, 13:21

Voici une version propre déjà nettement optimisée. Elle marche sous Omega, mais pas encore sous Epsilon.

Elle n'est pas loin de passer; si on commente les 8 dernières lignes de code l'erreur de mémoire au chargement disparaît (alors qu'avec la version d'origine il fallait commenter bien plus que ça).

Code: Select all
from ion import keydown
from kandinsky import *
from random import randint
from time import sleep

# couleurs
def c(i):
  f,h,n = 255,127,0
  l=(f<<16|f<<8|f, 45<<16|125<<8|210, 151<<16|204<<8|4, 238<<16|185<<8|2, 244<<16|93<<8|1, 215<<16|65<<8|167, n<<16|n<<8|n, n<<16|n<<8|n, n<<16|n<<8|n,h<<16|h<<8|h,192<<16|192<<8|192,96<<16|96<<8|96,253<<16|236<<8|185)
  return (l[i]>>16,(l[i]>>8)&((1<<8)-1),l[i]&((1<<8)-1))
nb0,nb1,nb2=17,0,0

# init
p=[[6,5],[7,5]]
m = []

def deminage():
  draw_string(str(nb1),12,2,c(2));draw_string("/"+str(150-nb0),42,2,c(1));
  draw_string("Demineur",120,2)
  draw_string("mines:"+str(nb0),220,2,c(5))
  if nb1+nb0>=150:draw_string("Gagné ! ",120,2)

def decouvre(x,y):
  i=1
  while i:
    chiffre(x,y)
    for p in range(x-(x>0),x+(x<14)+1):
      for q in range(y-(y>0),y+(y<9)+1):
        if m[p][q]>=100:chiffre(p,q)
        else:m[p][q]+=m[p][q]==0;
    i=0
    for p in range(15):
      for q in range(10):
        if m[p][q]%100==1:i=1;x=p;y=q;p=14;q=9

def terrain():
  fill_rect(8,21,300,200,c(9))
  for y in range(21,243,20):fill_rect(8,y,302,1,c(10))
  for x in range(8,320,20):fill_rect(x,21,1,202,c(10))

def chiffre(x,y):
  global nb1
  cl(x,y)
  nb1+=m[x][y]%100!=42
  i=m[x][y]//100
  m[x][y]=i*100+42
  if i>=1:draw_string(str(i),13+20*x,23+20*y,c(i),c(0))
  deminage()

def minage(b=nb0):
  global nb1,nb2
  if nb2==0:start()
  nb2+=1;terrain();m.clear();draw_string(" "*28,12,2)
  for x in range(15):m.append([0 for y in range(10)])
  nb1=0
  while b:
    x, y = randint(0,14),randint(0,9)
    if m[x][y]!=999:
      m[x][y]=999;b-=1
      for p in range(max(0,x-1),min(15,x+2)):
        for q in range(max(0,y-1),min(10,y+2)):
          m[p][q]+=(m[p][q]!=999) and 100
  deminage();drone()

def start():
  fill_rect(8,21,300,200,c(9))
  # Message d'accueil, crédit, touches, etc ...
  # while not keydown(4) or not keydown(52):
  #  pass


def explose():
  draw_string("perdu ! ",120,2)
  for x in range(15):
    for y in range(10):
      if m[x][y]==999:mine(x,y)

def marche(x,y):
  if m[x][y]>=999:explose()
  elif m[x][y]>=100:chiffre(x,y)
  else:decouvre(x,y)

def survol():
  [x, y] = p[1]
  #v = m[x][y]
  gps(x,y)
  # draw_string(str(int(v/100)),20,2)
  [x, y] = p[0]
  v = m[x][y]
  if p[1]!=[x,y]:gps(x,y,(v-42)%100 and 9)
  del p[0]

def gps(x,y,i=6):
  fill_rect(9+20*x,22+20*y,19,2,c(i));fill_rect(26+20*x,22+20*y,2,19,c(i));fill_rect(9+20*x,22+20*y,2,19,c(i));fill_rect(9+20*x,39+20*y,19,2,c(i))

def drone():
  while not keydown(6):
    if keydown(0) or keydown(3) or keydown(1) or keydown(2):p.append([min(max(p[0][0]-keydown(0)+keydown(3),0),14),min(max(p[0][1]-keydown(1)+keydown(2),0),9)])
    if keydown(4):marche(p[0][0],p[0][1])
    if keydown(17) or keydown(16):drapeau(p[0][0],p[0][1])
    if keydown(52):nb2=0;nb0=22;minage(nb0);sleep(1)
    if keydown(45) or keydown(46):nb0=min(max(nb0+5*(keydown(46)-keydown(45)),10),90);minage(nb0);sleep(1)
    if len(p)>1:survol();sleep(0.120)

def drapeau(x,y):
  fill_rect(17+20*x,26+20*y,3,9,c(12)),fill_rect(17+20*x,36+20*y,3,3,c(12))

def mine(x,y):
  cl(x,y);fill_rect(12+20*x,36+20*y,13,4,c(9));fill_rect(14+20*x,34+20*y,9,2,c(11));fill_rect(17+20*x,32+20*y,3,2,c(5))

def cl(x,y):
  fill_rect(9+20*x,22+20*y,19,19,c(0))

minage(nb0)
Image
User avatar
critorAdmin
Niveau 19: CU (Créateur Universel)
Niveau 19: CU (Créateur Universel)
Level up: 48%
 
Posts: 41981
Images: 15887
Joined: 25 Oct 2008, 00:00
Location: Montpellier
Gender: Male
Calculator(s):
MyCalcs profile
YouTube: critor3000
Twitter: critor2000
GitHub: critor

Re: Un démineur en python pour la NumWorks

Unread postby cent20 » 27 Feb 2020, 13:48

Bisam wrote:Quelques commentaires sur le script :
  1. Pourquoi utiliser
    Code: Select all
    int(i/100)
    au lieu de
    Code: Select all
    i//100
    ?
    Le deuxième est plus précis, puisque ne passant pas par les nombres réels et demande probablement moins de mémoire également (car les entiers considérés dans le script sont petits) !
  2. On peut avantageusement remplacer
    Code: Select all
      i = m[x][y] - m[x][y]%100
      m[x][y] = i + 42
      if i >= 100: v = int(i/100); t(str(v),13+20*(x),23+20*(y),c[v],c[0])

    par
    Code: Select all
      v=m[x][y]//100
      m[x][y] = 100*v + 42
      if v: t(str(v),13+20*(x),23+20*(y),c[v],c[0])
  3. Plus loin, on trouve
    Code: Select all
    if (v-42)%100 == 0: gps(x,y,0)
        else: gps(x,y,9)
    . J'aurais plutôt écrit :
    Code: Select all
    gps(x,y, 0 if v%100 == 42 else 9)
    à la place de ces deux lignes.
  4. Tu peux utiliser la fonction d'unpacking de Python pour simplifier certaines lignes. Combiné avec les remarques ci-dessus,
    Code: Select all
    def survol():
      x, y = p[1][0], p[1][1]
      v = m[x][y]
      gps(x,y)
      # t(str(int(v/100)),20,2)
      x, y = p[0][0], p[0][1]
      v = m[x][y]
      if p[1][0]!=x or p[1][1]!=y:
        if (v-42)%100==0:gps(x,y,0)
        else:gps(x,y,9)
      del p[0]

    deviendrait
    Code: Select all
    def survol():
      x, y = p[1]
      v = m[x][y]
      gps(x,y)
      # t(str(v//100),20,2)
      x, y = p[0]
      v = m[x][y]
      if p[1]!=(x,y):
        gps(x,y,0 if v%100==42 else 9)
      del p[0]
  5. On peut certainement remplacer la liste p de positions par deux ou trois couples de nombres : cela prendrait BEAUCOUP moins de place en mémoire.
Voilà, c'est tout pour les remarques qui ne témoignent que du fait que tu ne penses pas à utiliser le "sucre syntaxique" de Python... mais absolument pas de la réflexion et du boulot formidable qu'il y a derrière ce script.
Par ailleurs, l'explication sur ton site est plutôt remarquable et très pédagogique. :bj:


1. Parce que je n'ai jamais utilisé l'opérateur // jusqu'à maintenant, mais oui il est évident que c'est plus propre.
2. Jolie astuce
Code: Select all
if v:
qui traite v comme un booléen !
3.
Code: Select all
0 if v%100 == 42 else 9
ça m'impressionne toujours cette souplesse que permet python.
4. là encore, je ne connaissais pas cette fonction d'unpacking faute de l'avoir exploité précédemment.
5. Vu que ma liste ne contient jamais plus de 2 élément, je pensais que c'était neutre en utilisation mémoire mais au vu de la discussion qui a suivi je comprend qu'ajouter / enlever des élèments dans une liste est une mauvaise idée.

Bref j'intègre toutes ses modifications dans quelques minutes.

Merci de tes explications pointues et précise !
Image
Enseignant de mathématiques et d'informatique. Spécialité NSI : Des projets, des tutos, mais aussi de l'art
Calculatrice NumWorks : Des applications et des jeux, scripts, 📙 Découvrir la NumWorks
User avatar
cent20VIP++
Niveau 14: CI (Calculateur de l'Infini)
Niveau 14: CI (Calculateur de l'Infini)
Level up: 48.3%
 
Posts: 1047
Images: 67
Joined: 17 May 2012, 09:49
Location: Avignon
Gender: Male
Calculator(s):
MyCalcs profile
Twitter: nsi_xyz

Re: Un démineur en python pour la NumWorks

Unread postby cent20 » 27 Feb 2020, 13:50

Hamza.S wrote:Vous venez de le briser moralement et psychologiquement :troll:


Mais non, ne t'inquiète pas.

J'espère juste que ça ne servira pas d'excuse aux core développeur de Epsilon pour conclure que finalement, 16ko pour python ça suffit !
Image
Enseignant de mathématiques et d'informatique. Spécialité NSI : Des projets, des tutos, mais aussi de l'art
Calculatrice NumWorks : Des applications et des jeux, scripts, 📙 Découvrir la NumWorks
User avatar
cent20VIP++
Niveau 14: CI (Calculateur de l'Infini)
Niveau 14: CI (Calculateur de l'Infini)
Level up: 48.3%
 
Posts: 1047
Images: 67
Joined: 17 May 2012, 09:49
Location: Avignon
Gender: Male
Calculator(s):
MyCalcs profile
Twitter: nsi_xyz

Re: Un démineur en python pour la NumWorks

Unread postby critor » 27 Feb 2020, 13:51

Léger progrès, il n'y a plus que les 7 dernières lignes de code à commenter pour que ça passe : :)
Code: Select all
from ion import keydown
from kandinsky import *
from random import randint
from time import sleep

# couleurs
def c(i):
  f,h,n = 255,127,0
  l=(f<<16|f<<8|f, 45<<16|125<<8|210, 151<<16|204<<8|4, 238<<16|185<<8|2, 244<<16|93<<8|1, 215<<16|65<<8|167, n<<16|n<<8|n, n<<16|n<<8|n, n<<16|n<<8|n,h<<16|h<<8|h,192<<16|192<<8|192,96<<16|96<<8|96,253<<16|236<<8|185)
  return (l[i]>>16,(l[i]>>8)&((1<<8)-1),l[i]&((1<<8)-1))
nb0,nb1,nb2=17,0,0

# init
p=[[6,5],[7,5]]
m = []

def deminage():
  draw_string(str(nb1),12,2,c(2));draw_string("/"+str(150-nb0),42,2,c(1));
  draw_string("Demineur",120,2)
  draw_string("mines:"+str(nb0),220,2,c(5))
  if nb1+nb0>=150:draw_string("Gagné ! ",120,2)

def decouvre(x,y):
  i=1
  while i:
    chiffre(x,y)
    for p in range(x-(x>0),x+(x<14)+1):
      for q in range(y-(y>0),y+(y<9)+1):
        if m[p][q]>=100:chiffre(p,q)
        else:m[p][q]+=m[p][q]==0;
    i=0
    for p in range(15):
      for q in range(10):
        if m[p][q]%100==1:i=1;x=p;y=q;p=14;q=9

def terrain():
  fill_rect(8,21,300,200,c(9))
  for y in range(21,243,20):fill_rect(8,y,302,1,c(10))
  for x in range(8,320,20):fill_rect(x,21,1,202,c(10))

def chiffre(x,y):
  global nb1
  cl(x,y)
  nb1+=m[x][y]%100!=42
  i=m[x][y]//100
  m[x][y]=i*100+42
  if i>=1:draw_string(str(i),13+20*x,23+20*y,c(i),c(0))
  deminage()

def minage(b=nb0):
  global nb1,nb2
  if nb2==0:start()
  nb2+=1;terrain();m.clear();draw_string(" "*28,12,2)
  for x in range(15):m.append([0 for y in range(10)])
  nb1=0
  while b:
    x, y = randint(0,14),randint(0,9)
    if m[x][y]!=999:
      m[x][y]=999;b-=1
      for p in range(x-(x>0),x+(x<14)+1):
        for q in range(y-(y>0),y+(y<9)+1):
          m[p][q]+=(m[p][q]!=999) and 100
  deminage();drone()

def start():
  fill_rect(8,21,300,200,c(9))
  # Message d'accueil, crédit, touches, etc ...
  # while not keydown(4) or not keydown(52):
  #  pass


def explose():
  draw_string("perdu ! ",120,2)
  for x in range(15):
    for y in range(10):
      if m[x][y]==999:mine(x,y)

def marche(x,y):
  if m[x][y]>=999:explose()
  elif m[x][y]>=100:chiffre(x,y)
  else:decouvre(x,y)

def survol():
  [x, y] = p[1]
  #v = m[x][y]
  gps(x,y)
  # draw_string(str(int(v/100)),20,2)
  [x, y] = p[0]
  v = m[x][y]
  if p[1]!=[x,y]:gps(x,y,(v-42)%100 and 9)
  del p[0]

def gps(x,y,i=6):
  fill_rect(9+20*x,22+20*y,19,2,c(i));fill_rect(26+20*x,22+20*y,2,19,c(i));fill_rect(9+20*x,22+20*y,2,19,c(i));fill_rect(9+20*x,39+20*y,19,2,c(i))

def drone():
  while not keydown(6):
    if keydown(0) or keydown(3) or keydown(1) or keydown(2):p.append([min(max(p[0][0]-keydown(0)+keydown(3),0),14),min(max(p[0][1]-keydown(1)+keydown(2),0),9)])
    if keydown(4):marche(p[0][0],p[0][1])
    if keydown(17) or keydown(16):drapeau(p[0][0],p[0][1])
    if keydown(52):nb2=0;nb0=22;minage(nb0);sleep(1)
    if keydown(45) or keydown(46):nb0=min(max(nb0+5*(keydown(46)-keydown(45)),10),90);minage(nb0);sleep(1)
    if len(p)>1:survol();sleep(0.120)

def drapeau(x,y):
  fill_rect(17+20*x,26+20*y,3,9,c(12)),fill_rect(17+20*x,36+20*y,3,3,c(12))

def mine(x,y):
  cl(x,y);fill_rect(12+20*x,36+20*y,13,4,c(9));fill_rect(14+20*x,34+20*y,9,2,c(11));fill_rect(17+20*x,32+20*y,3,2,c(5))

def cl(x,y):
  fill_rect(9+20*x,22+20*y,19,19,c(0))

minage(nb0)
Image
User avatar
critorAdmin
Niveau 19: CU (Créateur Universel)
Niveau 19: CU (Créateur Universel)
Level up: 48%
 
Posts: 41981
Images: 15887
Joined: 25 Oct 2008, 00:00
Location: Montpellier
Gender: Male
Calculator(s):
MyCalcs profile
YouTube: critor3000
Twitter: critor2000
GitHub: critor

Re: Un démineur en python pour la NumWorks

Unread postby cent20 » 27 Feb 2020, 13:54

critor wrote:Effectivement, sur NumWorks, à chaque fois que l'on a envie d'utiliser une liste/tuple ou pire comme ici liste de listes, il faut se demander si il n'y aurait pas moyen de s'en passer.


Ma matrice (liste de liste) de 150 cases contenant 150 entiers et ne changeant jamais de taille occupe tant de place en mémoire que ça ? J'y suis suis attaché un peu quand même car m[x][y] est facilement compréhensible, interprétable, et facilite, il me semble, grandement la lecture du code.
Image
Enseignant de mathématiques et d'informatique. Spécialité NSI : Des projets, des tutos, mais aussi de l'art
Calculatrice NumWorks : Des applications et des jeux, scripts, 📙 Découvrir la NumWorks
User avatar
cent20VIP++
Niveau 14: CI (Calculateur de l'Infini)
Niveau 14: CI (Calculateur de l'Infini)
Level up: 48.3%
 
Posts: 1047
Images: 67
Joined: 17 May 2012, 09:49
Location: Avignon
Gender: Male
Calculator(s):
MyCalcs profile
Twitter: nsi_xyz

Re: Un démineur en python pour la NumWorks

Unread postby cent20 » 27 Feb 2020, 14:09

critor wrote:
Code: Select all
# couleurs
def c(i):
  f,h,n = 255,127,0
  l=(f<<16|f<<8|f, 45<<16|125<<8|210, 151<<16|204<<8|4, 238<<16|185<<8|2, 244<<16|93<<8|1, 215<<16|65<<8|167, n<<16|n<<8|n, n<<16|n<<8|n, n<<16|n<<8|n,h<<16|h<<8|h,192<<16|192<<8|192,96<<16|96<<8|96,253<<16|236<<8|185)
  return (l[i]>>16,(l[i]>>8)&((1<<8)-1),l[i]&((1<<8)-1))


Là je suis en train de me faire un noeud dans le cerveau.
ça me parait beaucoup plus complexe que mon gentil tableau statique.

Code: Select all
# couleurs
f,h,n = 255,127,0
c=[co(f,f,f), co(45,125,210), co(151,204,4), co(238,185,2), co(244,93,1), co(215,65,167), co(n,n,n), co(n,n,n), co(n,n,n),
   co(h,h,h),co(192,192,192),co(96,96,96),co(253,236,185)]


Cette fonction coûte de la mémoire non ? Le code f<<16|f<<8|f me laisse de marbre.

| : ou logique, ok admettons.
<< : décalage à droite. De quoi ? de qui ?

Je comprend que return renvoie un triplet, là dessus aucun doute.
Mais alors le reste c'est de la sorcellerie pour moi.
Image
Enseignant de mathématiques et d'informatique. Spécialité NSI : Des projets, des tutos, mais aussi de l'art
Calculatrice NumWorks : Des applications et des jeux, scripts, 📙 Découvrir la NumWorks
User avatar
cent20VIP++
Niveau 14: CI (Calculateur de l'Infini)
Niveau 14: CI (Calculateur de l'Infini)
Level up: 48.3%
 
Posts: 1047
Images: 67
Joined: 17 May 2012, 09:49
Location: Avignon
Gender: Male
Calculator(s):
MyCalcs profile
Twitter: nsi_xyz

PreviousNext

Return to Programmation Python

Who is online

Users browsing this forum: ClaudeBot [spider] and 0 guests

-
Search
-
Social TI-Planet
-
Featured topics
Comparaisons des meilleurs prix pour acheter sa calculatrice !
"1 calculatrice pour tous", le programme solidaire de Texas Instruments. Reçois gratuitement et sans aucune obligation d'achat, 5 calculatrices couleur programmables en Python à donner aux élèves les plus nécessiteux de ton lycée. Tu peux recevoir au choix 5 TI-82 Advanced Edition Python ou bien 5 TI-83 Premium CE Edition Python.
Enseignant(e), reçois gratuitement 1 exemplaire de test de la TI-82 Advanced Edition Python. À demander d'ici le 31 décembre 2024.
Aidez la communauté à documenter les révisions matérielles en listant vos calculatrices graphiques !
1234
-
Donations / Premium
For more contests, prizes, reviews, helping us pay the server and domains...
Donate
Discover the the advantages of a donor account !
JoinRejoignez the donors and/or premium!les donateurs et/ou premium !


Partner and ad
Notre partenaire Jarrety Calculatrices à acheter chez Calcuso
-
Stats.
880 utilisateurs:
>865 invités
>8 membres
>7 robots
Record simultané (sur 6 mois):
6892 utilisateurs (le 07/06/2017)
-
Other interesting websites
Texas Instruments Education
Global | France
 (English / Français)
Banque de programmes TI
ticalc.org
 (English)
La communauté TI-82
tout82.free.fr
 (Français)