Factors Game en python sur NumWorks

Projets

Factors Game est à l’origine un jeu indépendant jouable en ligne, donc directement depuis un site web. Ceci dit, les Numworks ne peuvent pas encore se connecter à internet… Mais pas de panique, nous nous sommes occupés de l’adaptation du jeu sur calculatrice ! On est sacrément sympa nous…
Arriveras tu à atteindre le niveau 404 ?

Développement

02/04
🧐 Bon, maintenant que t’as fini ton nyan_cat, résolu deux de mes énigmes, corrigé les bugs sur laboHelp, aidé au développement de pixChoice. Ça te dit de faire un jeu sur la calculatrice ?
🤓 Pourquoi pas !

Voici le jeu qui était demandé : Factors Game – The 🐐 of Fun Math Games (mnito.github.io)

🧐 On va afficher les nombres dans des tuiles de 42 pixels par 42 pixels

(2 jours plus tard)

🤓 J’ai fini le système de mouvement, et le système de génération aléatoire de la grille. Il y a juste le front qui est à revoir…


🧐 Bon, pas très UX les déplacements du haut vers le bas comme sur le jeu original avec la résolution de l’écran des calculatrices. On va les faire de gauche à droite du coup, tu dois réadapter le système de mouvement.
🤓 … D’accord

Parallèlement le codage des nombres a été intégré, il est d’Eric Schrafstetter, il est explicité sur cette vidéo.

Ce codage, celui du jeu 2048, dont nous avons amélioré le rendu a été réutilisé pour écrire F A C T O R S en haut à gauche de l’écran !

Petit récap’, mouvements OK, grille OK, maintenant il faut faire le système de calcul entre le curseur et les cases de la grille (vous savez, les divisons, les additions, tout ça tout ça. Ça se fait pas par magie malheureusement).

Aussitôt commencé, aussitôt terminé ! Moi qui redoutait cette phase du développement, ça avait été plus facile que prévu. Plus qu’à faire le système de détection de fin du niveau. Fastoche ! Si le curseur est égal à 1, ou que le curseur est positionné dans la dernière colonne, niveau terminé ! Et on relance la génération de la grille sans oublier d’incrémenter le niveau et calculer la moyenne.

Voilà. En quelques jours, le jeu est théoriquement jouable.

🤓 Plus que le menu, et le système de sauvegarde. Mais le jeu est jouable !
🧐 Ok, pour le menu, on va faire ça, ça, mais il faut ça s’il y a ça, ça ça doit donc s’activer et du coup réactiver ça si ça a été désactivé seulement si ça avait été activé et puis…
🤓 Et si on faisait un cahier des charges ? 😅
🧐 Je m’en occupe.

🤓 Le menu est terminé, il faut sauvegarder le score de chaque niveau ?
🧐 Oui, on va utiliser un dictionnaire.
🤓 Larousse ou Le Petit Robert ?

Menu

🧐Le dictionnaire sert à rien, on aurait pu faire ça avec un tableau, mais laissons le dictionnaire ! 😂

🤓 Bon, je taffe sur une transition entre les niveaux, car les coups de sleep(3), ça va 2 secondes… (3 !)

🧐 Parfait !

Et voilà, en une bonne semaine, le jeu est terminé, il manque plus que le système de sauvegarde, enfin c’est ce que je pensais…

🧐 Bon, ton code est illisible on ne comprend rien. Tu me redéveloppes toute la fonction principale en respectant ces contraintes :

  • Le moins de if imbriqués possibles
  • Chaque if doit donner lieu à 2,3 traitements maximum
  • 61 lignes pour une fonction c’est trop
  • Tout abus de booléen est à éviter

🤓 Mais ça nécessite de redévelopper quasiment toutes les fonctions. Donc tout le jeu…
🧐 Oui mais sinon on comprend rien.
🤓 Oui mais le jeu marche.
🧐 Oui mais on comprend rien.
🤓 J’ai compris…

Vous vous comprenez hein rassurez moi. À moins que j’ai un problème.

def factors(): # Ceci est l'ancien code incompréhensible !
    global cursor, pos, level_current, retry
    gui()
    menu()
    level_in_progress, in_menu, re_menu, last_key, end, go, input_await = False, False, False, None, False, False, False
    while not keydown(5):
        if not level_in_progress:
            if not in_menu:
                menu(0)
                start_level(1)
                cursor, pos, end, input_await = level_current, [51 + 44 * 1, 13 + 44 * 1], False, False
                aff(level_current, pos[0] + 44 // 2 + center(level_current)[0],
                    pos[1] + 44 // 2 + center(level_current)[1], black_color)
                level_in_progress = True
            if not re_menu and in_menu:
                menu(1)
                start_level(0)
                re_menu = True
        if keydown(1) and pos[1] >= 51 and last_key != 1:
            if not in_menu:
                move(0, -1)
            if in_menu and level_current != level_max:
                level_current += 1
                re_menu = False
            last_key = 1
        if keydown(2) and pos[1] <= 51 + 44 * 2 and last_key != 2:
            if not in_menu:
                move(0, 1)
            if in_menu and level_current != 1:
                level_current -= 1
                re_menu = False
            last_key = 2
        if keydown(3) and last_key != 3:
            if not in_menu:
                move(1, 0)
            if in_menu:
                level_in_progress, in_menu, re_menu = False, False, False
            if input_await:
                go = True
                fill_rect(pos[0] + 42, pos[1] + 42, 0 - 220, 0 - 176, (255, 255, 255))
            last_key = 3
        if keydown(0) and last_key != 0:
            if pos[0] != 51 + 44 or input_await:
                level_in_progress = False
                retry = True
                if input_await:
                    fill_rect(pos[0] + 42, pos[1] + 42, 0 - 176, 0 - 176, (255, 255, 255))
            if not in_menu and pos[0] == 51 + 44:
                level_in_progress, in_menu = False, True
            last_key = 0
        if not (keydown(0) or keydown(1) or keydown(2) or keydown(3)):
            last_key = None
        if not (pos[0] != 51 + 44 * 5 and (cursor != 1 or pos[0] == 51 + 44)):
            end = True
        if end:
            if not input_await:
                level_transition(cursor)
                input_await = True
            if go:
                next_level()
                level_in_progress, retry, input_await, go = False, False, False, False

Finalement, presque tout le jeu a donc été redéveloppé pour améliorer la lisibilité des fonctions python.
Vous pouvez donc désormais comprendre le code ! Sauf le système de sauvegarde, ça vous vous débrouillez ! 🤫

🧐 Oui enfin le système de sauvegarde est codé pour être incompréhensible, c’est une fonctionnalité pour éviter qu’un joueur lambda ne génère trop facilement une clé de sauvegarde.

🤓 À noter, le code a été compressé pour passer de 10.2 ko à 8.42 ko, et désormais il ne respecte plus PEP 8 – Style Guide for Python Code (EnFr)

Fonctionnement

La plupart des différents événements sont lancés grâce à la liste pos[x, y]. Cette liste correspond aux coordonnées x, et y du curseur :

La position par défaut du curseur est donc [0, 1] ! Oui, l’axe vertical est inversé. 🙄

Ainsi, si pos vaut [-1, y], on lance le menu, si pos[4, 0], on termine le niveau, etc. L’affichage sur l’écran est géré par la fonction d_p(), qui va convertir pos en coordonnées réelles (celles de l’écran), car évidemment, les coordonnées de pos sont virtuelles ! Le (0 ; 0) de l’écran lui se situe tout en haut à gauche !

Fonctionnalités délaissées

Beaucoup de fonctionnalités ont été retirés pour réduire au plus la taille du fichier ainsi que la mémoire utilisée ou pour d’autres raisons.
Un histogramme dynamique avec le score des 20 derniers niveaux a été par exemple testé mais abandonné, le système de chargement d’une sauvegarde sur la couche graphique est lui aussi retiré, remplacé par une fonctionnalité équivalente mais exploitant le console python.

À toi de jouer !

Ce jeu est disponible sur https://nsi.xyz/factors

Nous te mettons au défi d’atteindre le niveau 404. Mais y arriveras tu ? 😱