Page 1 sur 2

Jeu touches clavier TI83

Message non luPosté: 27 Juin 2022, 08:52
de Fabien59
Bonjour,

J'ai imaginé un petit jeu de rapidité sur TI83 écrit en Python. L'idée est d'apprendre à utiliser les symboles sur le clavier de la calculatrice.

Pour cela, une lettre ou un symbole apparaît à l'écran et je joueur doit taper cette même lettre. Sur l'image d'un clavier est indiqué à chaque essai la touche à sélectionner. Un code couleur permet de savoir si la touche 2nde (bleue) ou alpha (vert) doit être utilisée. La partie s'arrête après 5 bonnes réponses. Le temps est comparé au meilleur score enregistré dans les listes de la calculatrice.
Pour vous donner une idée, voici une copie d'écran du résultat final. En pièce jointe, j'ai déposé dans un fichier zip le script et les images nécessaires (images obtenues avec img2calc)
Image

C'est fonctionnel mais mon script est très gourmand en mémoire. J'aimerai gagner de l'espace.
Dans ce script, j'utilise une liste de tuples qui prend certainement beaucoup d'espace mémoire. Chaque tuple correspond à un symbole sur le clavier.
Exemple : le symbole { : ("{",275,110,3)
Dans ce tuple, on voit 4 éléments : le symbole (ici "{"), les coordonnées (x,y) sur l'écran (ici (275,110)) et un code couleur (ici 3). Les coordonnées indiquent l'emplacement de la touche sur l'image du clavier afin d'y dessiner un cercle de couleur (noir, bleu ou vert selon la combinaison de touches nécessaire).

On peut sans aucun doute faire beaucoup mieux en qualité de programmation, j'aimerai donc bénéficier de vos conseils pour améliorer ce script et l'optimiser pour y inclure les symboles manquants : ici, les lettres majuscules. En effet, si j'ajoute dans la liste les tuples les 26 tuples manquants, cela provoque une erreur de dépassement de mémoire.

Merci pour vos conseils.

Fabien

Re: Jeu touches clavier TI83

Message non luPosté: 27 Juin 2022, 09:33
de critor
Très intéressant. :)

Je vais regarder, merci pour le partage.

Re: Jeu touches clavier TI83

Message non luPosté: 27 Juin 2022, 11:38
de Bisam
Tu peux gagner 16 octets de mémoire en remplaçant la liste par un tuple... mais ça n'est pas énorme.

Tu peux gagner quelques octets de mémoire sur le script en remplaçant :
x,y,code = symbol[a][1],symbol[a][2],symbol[a][3]
par
ch,x,y,code = symbol[a]
et plus loin symbol[a][0] par ch

Tu peux aussi utiliser la simplification if mem: record=mem[0] à la place de if len(mem)!=0: record=mem[0]

Je suis étonné par le symbole nommé "espace" et non " "... ça ne doit pas bien marcher lors du test if b==symbol[a][0]...

Re: Jeu touches clavier TI83

Message non luPosté: 27 Juin 2022, 13:27
de Fabien59
Merci à vous et merci Bisam pour ces remarques pertinentes.
Oui, le symbole nommé "espace" n'a effectivement pas de sens avec ce script. C'est remplacé par " " . Mais si ce caractère est appelé par le programme l'utilisateur verra écrit "Taper "... difficile de comprendre qu'il s'agit du symbole " "... à voir comment modifier cela.

J'ai modifié le script avec les améliorations proposées.
En ajoutant les symboles manquants (lettres majuscules, " et \), le problème d'espace mémoire persiste malheureusement, j'ai le message d'erreur suivant : "memory allocation failed, allocating 184 bytes".
C'est ce script complet que j'ai mis ici en pièce jointe.

Re: Jeu touches clavier TI83

Message non luPosté: 27 Juin 2022, 14:29
de Bisam
Je pense qu'on peut gagner pas mal avec l'astuce suivante.
Il s'agit de coder tout ton tuple "symbol" en une seule chaîne de caractères.

Pour le codage, tu le fais sur ordi et tu fais ainsi :
Code: Tout sélectionner
ns = "".join("".join((a, chr(b//5+20), chr(c//5+20), str(d))) for (a,b,c,d) in symbol)

Le principe est de coder tes 3 derniers nombres le plus simplement possible.
"chr" transforme un nombre entre 0 et 255 en caractère... mais certains n'étant pas transcriptible, j'ai décalé de 20 après avoir divisé par 5 (puisque les deux premiers nombres sont multiples de 5)
Le 3ème nombre, je l'ai simplement converti en chaine de caractère directement.

On obtient ainsi une chaîne de 4*len(symbol) caractères.
En faisant le test, j'obtiens avec le tuple actuel une taille de 385 octets au lieu des 696 du tuple.

Tu enregistres donc cette chaîne en dur dans ton script, puis pour retrouver ce dont tu as besoin, tu fais l'opération inverse :
Code: Tout sélectionner
a = randint(0, len(ns)//4 - 1)
ch, x, y, code = ns[4*a], 5*ord(ns[4*a+1])-100, 5*ord(ns[4*a+2])-100, int(ns[4*a+3])

Cela devrait fonctionner.

Re: Jeu touches clavier TI83

Message non luPosté: 27 Juin 2022, 14:38
de critor
Pour l'espace, on peut changer la ligne d'affichage comme ça :
b=input("Taper "+(ch==" " and "espace" or ch)+"\n")

Les caractères pourraient de plus être tous réunis au sein d'une même chaîne à part. Cela vaudrait mieux que de créer une chaîne pour chaque caractère.

Re: Jeu touches clavier TI83

Message non luPosté: 27 Juin 2022, 14:58
de Bisam
La syntaxe usuelle en Python pour la structure ternaire est plutôt b = input("Taper " + ("espace" if ch=" " else ch) + "\n")
On sent le côté TI-Basic dans ce que tu proposes, critor.

Re: Jeu touches clavier TI83

Message non luPosté: 27 Juin 2022, 15:26
de critor
Fabien59 a écrit:J'ai modifié le script avec les améliorations proposées.
En ajoutant les symboles manquants (lettres majuscules, " et \), le problème d'espace mémoire persiste malheureusement, j'ai le message d'erreur suivant : "memory allocation failed, allocating 184 bytes".


C'est la difficulté quand on développe des projets Python pour TI-83 Premium CE ; la capacité du tas / heap est absolument ridicule.
Il faut se montrer malin et ruser.

Voici ci-dessous un script où j'ai réorganisé toutes tes structures de données globales selon l'idée précédente (ne pas recréer un objet Python supplémentaire pour chaque touche), tout en prenant soin à ce que le script reste éditable facilement pour un lecteur humain.
Maintenant il passe sans problème sur machine. :)

Code: Tout sélectionner
from random import randint
from time import *
from ti_image import load_image,show_image
from ti_system import wait_key,store_list,recall_list,disp_clr,disp_wait
from ti_draw import draw_circle,set_color,set_pen

symbol_char =  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz,()/789*456-=123+0.@\" :?\\{}[]#'_"
#               A B C D E F G H I J K L M N O P Q R S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z , ( ) / 7 8 9 * 4 5 6 - = 1 2 3 + 0 . @ \"  : ? \\{ } [ ] # ' _
symbol_col  = b"\0\1\2\0\1\2\3\4\0\1\2\3\4\0\1\2\3\4\0\1\2\3\4\0\1\2\0\1\2\0\1\2\3\4\0\1\2\3\4\0\1\2\3\4\0\1\2\3\4\0\1\2\1\2\3\4\1\2\3\4\1\2\3\4\0\1\2\3\4\1\2\3\4\1\2\3\4\2\3\4\4\3\4\3"
symbol_lgn  = b"\0\0\0\1\1\1\1\1\2\2\2\2\2\3\3\3\3\3\4\4\4\4\4\5\5\5\0\0\0\1\1\1\1\1\2\2\2\2\2\3\3\3\3\3\4\4\4\4\4\5\5\5\2\2\2\2\3\3\3\3\4\4\4\4\5\5\5\5\5\6\6\5\5\6\6\6\1\2\2\3\4\5\5\6"
symbol_mod  = b"\2\2\2\2\2\2\2\2\2\2\2\2\2\2\2\2\2\2\2\2\2\2\2\2\2\2\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\1\1\1\1\3\3\3\3\3\3\3\3"

def symbol_x(i): return (240, 255, 275, 290, 305)[symbol_col[i]]
def symbol_y(i): return (70, 90, 110, 125, 145, 165, 185)[symbol_lgn[i]]

def aide(x,y,code):
  load_image("Clavier")
  show_image(230,0)
  if code==0:set_color(0,0,0)
  if code==1:set_color(0,255,0)
  if code==2:set_color(0,125,255)
  if code==3:set_color(0,0,255)
  draw_circle(x,y,13)
 
# == PROG PRINCIPAL ==
t0=monotonic()
dt=0
score=0
max=5

mem=recall_list("5")
if mem:record=mem[0]
else:record=10000

disp_clr()
print("Taper les symboles\nle plus vite possible\n")
print("touche alpha vert :\n1 appui=> minuscule\n2 appuis => MAJUSCULE")
print("\n\n\nAppuyer 1 touche pour commencer")

wait_key()
set_pen("thick","solid")

while score<max:
  a=randint(0,len(symbol_char)-1)
  ch,x,y,code=symbol_char[a], symbol_x(a), symbol_y(a), symbol_mod[a]
  ok=0
  while ok==0:
    disp_clr()
    print("Score = {}/{}\n".format(score,max))
    aide(x,y,code)
    b=input("Taper  "+(ch==" " and "espace" or ch)+"\n")
    if b==ch:
      ok=1
      score+=1
      print("\nCorrect :-)")
      load_image("Good")
      show_image(75,75)
    else:
      print("\nErreur :-(")
      load_image("Bad")
      show_image(70,70)
      if score>0:score-=1
    sleep(0.8)
    dt=monotonic()-t0
 
print("\nVotre temps = {:.1f} s".format(dt))

if dt<record:
  print("Nouveau record !")
  store_list("5",[dt])
else:print("Record = {:.1f} s".format(record))

print("==> APPUVER SUR annul")
set_color(255,0,0)
draw_circle(305,72,13)
disp_wait()


Et très beau projet en passant, bravo ! :bj:

Re: Jeu touches clavier TI83

Message non luPosté: 27 Juin 2022, 17:32
de Fabien59
Un grand merci pour votre aide et ces solutions trouvées si rapidement. C'est très astucieux et efficace 👍️
Je vais prendre le temps de bien comprendre le code utilisé, pour en apprendre encore un peu plus sur Python grâce à vous 🥰 .

Re: Jeu touches clavier TI83

Message non luPosté: 27 Juin 2022, 17:56
de critor
De rien.

Je ne crée que 4 grosses structures de données Python :
  • une chaîne avec tous les caractères à taper dans le jeu
  • une liste d'octets avec dans le même ordre les numéros de colonne des touches correspondant à chaque caractère
  • une liste d'octets avec dans le même ordre les numéros de ligne des touches correspondant à chaque caractère
  • une liste d'octets avec dans le même ordre le numéro de modificateur (2nde, alpha, etc.) nécessaire à la saisie pour chaque touche

Je n'ai presque rien changé dans le reste du code.

Mais si tu as des questions, n'hésite pas. :)