Planète Casio - Actualités - Flux RSS http://www.planet-casio.com Programmes Casio, Jeux, Cours pour Calculatrices Casio fr-FR https://www.planet-casio.com/images/logo.gif Planète Casio - Actualités - Flux RSS http://www.planet-casio.com 55 50 Programmes Casio, Jeux, Cours pour Calculatrices Casio. Sun, 17 Oct 2021 09:24:22 GMT Sun, 17 Oct 2021 09:24:22 GMT contact@planet-casio.com (Planet Casio) contact@planet-casio.com (Planet Casio) 5 IA Synchro-donjon #3: Optimisations locales https://www.planet-casio.com/Fr/forums/topic16907--.html Dans le cadre de notre concours de rentrée 2021 avec TI-Planet, nous te proposons de résoudre deux jeux codés en Python avec ta calculatrice graphique : La geste d'Alrys et Synchro-donjon. ;) concours-rentree-2021-banner.png Pour t'aider à aborder Synchro-donjon et à apprendre des choses nouvelles sur la programmation et l'intelligence artificielle, je te présente en détail les IAs groupées avec le programme, de la plus simple à une modérément perfectionnée. Aujourd'hui, on regarde `ia3greed.py` ! N'oublie pas de lire les règles de Synchro-donjon et de tester le programme sur ta calculatrice avant de lire cet article, sinon tu seras vite perdu·e. `ia3greed.py` est une amélioration de `ia2_path.py` qui a déjà un article explicatif, je te conseille de commencer par là. ^^ Voilà le code entier qu'on va disséquer. from polycal4 import get_infos from synchrod import * # Ordre des joueurs à sortir ordre_de_sortie = [0, 2, 1, 3] # Position du joueur qu'on veut sortir dans ordre_de_sortie joueur_courant_id = 0 # Chemin pour le sortir chemin = [] def tour(plateau, joueurs, evenements): global joueur_courant_id, chemin for (x, y, ev, joueur) in evenements: if ev == NOUVELLE_PARTIE: joueur_courant_id = 0 chemin = [] # Si le joueur est arrivé à sa destination, on passe au suivant while joueurs[ordre_de_sortie[joueur_courant_id]] == -1: joueur_courant_id += 1 chemin = [] joueur_courant = ordre_de_sortie[joueur_courant_id] # Chemin du joueur actuel vers sa sortie if chemin == []: case_sortie = plateau.index(SORTIE + joueur_courant) chemin = calculer_chemin(plateau, joueurs[joueur_courant], case_sortie) # S'il y a des monstres autour mais pas de piège, attaquer monstres_autour = False pieges_autour = False for joueur in joueurs: # On ne compte pas les joueurs qui ont déjà sortis if joueur != -1: if est_un(plateau[joueur-1], MONSTRE) or \ est_un(plateau[joueur+1], MONSTRE) or \ est_un(plateau[joueur-16], MONSTRE) or \ est_un(plateau[joueur+16], MONSTRE): monstres_autour = True if est_un(plateau[joueur-1], PIEGE) or \ est_un(plateau[joueur+1], PIEGE) or \ est_un(plateau[joueur-16], PIEGE) or \ est_un(plateau[joueur+16], PIEGE): pieges_autour = True if monstres_autour and not pieges_autour: return ATTAQUER # Prochaine étape mouvement = chemin[0] chemin = chemin[1:] return mouvement play_game(tour, blind=True) Comme tu peux le voir, le début ressemble beaucoup à `ia2_path.py`. Le principe est toujours le même : on commence par sélectionner un premier joueur, on cherche un chemin pour le faire sortir avec `calculer_chemin()` et on le suit ; puis on passe à un autre joueur jusqu'à avoir fini. ;) Sortir les joueurs dans le bon ordre Si tu regardes la position initiale des joueurs sur le plateau ci-dessus, tu verras que les faire sortir dans l'ordre 0, 1, 2, 3 (à savoir Jaune, Rouge, Bleu, Vert) n'est pas optimal. concours-rentree-2021-synchrod-ia2-c0ffee.png C'est parce que pour faire sortir Jaune il faut déjà traverser tout l'écran vers la droite ; puis pour faire sortir Rouge il faut retraverser tout l'écran vers la gauche ; et on recommence encore une fois avec Bleu puis Vert. Clairement, il est plus rentable d'emmener à la fois Jaune et Bleu vers la droite puis Rouge et Vert vers la gauche. Autrement dit, de faire sortir les joueur dans l'ordre 0, 2, 1, 3. C'est ce qu'on commence à prévoir dès le début du code : ordre_de_sortie = [0, 2, 1, 3] Pour suivre notre progrès, on ne regarde du coup pas le numéro du joueur actuel mais plutôt la position où on en est dans l'ordre de sortie. C'est le rôle de la variable `joueur_courant_id`. Quand on démarre une nouvelle partie ou qu'on passe au joueur suivant, on modifie `joueur_courant_id`, et ensuite on détermine de quel joueur il s'agit en indexant la liste : joueur_courant = ordre_de_sortie[joueur_courant_id] Avec ça, le score augmente déjà beaucoup ! On faisait 2171 points avec `ia2_path.py` et l'ordre moins bon ; Et là on fait 3730 points rien qu'en évitant des allers-retours. Et on n'a pas fini ! Attaquer les ennemis quand ce n'est pas dangereux Actuellement le programme prend encore beaucoup de dégâts, ce qu'on peut voir juste en regardant les premiers plateaux : #0: 12648430 Bravo! 39T 50D -> 61 #1: 594213422 Bravo! 67T 90D -> -7 #2: 236840551 Bravo! 70T 40D -> 40 #3: 2464859390 Bravo! 62T 60D -> 28 Il y a au moins un type de dégâts qu'on peut éviter facilement : les monstres. C'est parce que si on rentre dedans c'est qu'on était à côté au tour précédent, et si on est à côté... on peut les détruire. ;) Attaquer les monstres a cependant l'effet secondaire gênant d'activer les pièges à proximité des joueurs, ce qui peut faire des dégâts ou faire apparaître d'autres pics, monstres et pièges. Donc on va essayer d'attaquer s'il y a des monstres à côté d'un joueur, mais pas de pièges. Pour ça, on prend tous les joueurs qui sont sur le plateau et on regarde les cases autour d'eux. On peut identifier les cases autour d'un joueur en regardant comment elles sont numérotées : concours-rentree-2021-synchrod-board.png On peut voir si le joueur est sur la case n, les cases de gauche et droite sont numérotées n-1 et n+1, et les cases au-dessus et en-dessous sont numérotées n-16 et n+16. Il suffit donc de tester si un monstre se trouve à chacune de ces positions : monstres_autour = False pieges_autour = False for joueur in joueurs: # On ne compte pas les joueurs qui ont déjà sortis if joueur != -1: if est_un(plateau[joueur-1], MONSTRE) or \ est_un(plateau[joueur+1], MONSTRE) or \ est_un(plateau[joueur-16], MONSTRE) or \ est_un(plateau[joueur+16], MONSTRE): monstres_autour = True if est_un(plateau[joueur-1], PIEGE) or \ est_un(plateau[joueur+1], PIEGE) or \ est_un(plateau[joueur-16], PIEGE) or \ est_un(plateau[joueur+16], PIEGE): pieges_autour = True if monstres_autour and not pieges_autour: return ATTAQUER Alors que donne cette astuce ? Pas moins de 5475 points, ce qui la place bien au-delà des IAs précédentes. 2171 points avec `ia2_path.py` ; 3730 points en évitant des allers-retours ; 5475 points en tuant les monstres sur le chemin. Les plus observateurs d'entre vous auront remarqué que cette dernière astuce est en fait commentée dans `ia3greed.py`, ce qui a à un moment détrôné plusieurs participations soumises. :p Autres pistes d'améliorations Cette IA montre que de petites améliorations intuitives peuvent faire une grosse différence. Voici quelques idées ! Actuellement on n'essaie même pas d'esquiver les piques... on pourrait le faire même sans modifier `calculer_chemin()`. On consomme un tour pour attaquer les monstres même si on ne fait que passer à côté d'eux sans les toucher ou si le joueur qui les croise est immunisé. On pourrait trouver encore un meilleur ordre de sortie. On ne tient pas comptes des piques qui peuvent apparaître quand un piège est activé. Bon courage pour explorer ces pistes (ou d'autres) :) Sat, 16 Oct 2021 20:52:21 +0200 [Concours] À La Limite Du Raisonnable #4 https://www.planet-casio.com/Fr/forums/topic16906--.html Salut à tous programmeurs fous, et bienvenue dans la 4ème édition du concours À La Limite Du Raisonnable ! ALLDR-4-banner.png Les règles sont simples : vous devez programmer un jeu de votre choix avant Dimanche soir (17 Octobre) à 23h59, en respectant les règles suivantes. Les programmes seront notés semi-informellement sur 10 avec les critères du CPC (voir les règles du CPC #27). :here: Les caractères 0...9, +, -, × et ÷ sont interdits. Bien sûr, vous aurez besoin de nombres et d'arithmétique... mais vous devrez les faire autrement. :p :here: Vous ne pouvez utiliser qu'une liste au plus, et aucune matrice. Toutes les variables exotiques, Str, fn, et autres méthodes de stockages sont autorisées. :here: Goto/Lbl sont interdits, sauf si vous n'utilisez que ça. Vous pouvez prendre la pilule bleue et écrire un programme qui ne contient aucun Goto/Lbl. Ou vous pouvez prendre la pilule rouge et n'utiliser que ça, auquel cas seuls Goto, Lbl, Isz et Prog sont autorisés pour les tests et sauts (Return, Dsz, ⇒ sont interdits en particulier, en plus évidemment de tous les If, For, While, Do, etc). En cas de doute demandez-moi si une instruction est autorisée. 1 point bonus si vous prenez la deuxième option. :here: Soit écran texte uniquement (avec au moins un ASCII art) soit écran graphique uniquement (avec au moins une Picture). La qualité du pixel art ou de la Picture n'importe pas pour le respect de la règle, mais il y a des points de graphismes... x3 Le meilleur programme remportera une batterie portable CASIO grâce au soutien de CASIO Éducation ! ;) goodies-2021-2.jpg https://www.casio-education.fr/wp-content/themes/casio/assets/images/logo.svg À vos calculatrices !! :bounce: Fri, 15 Oct 2021 15:13:57 +0200 CGDoom 1.0 : DOOM finalement porté sur Graph 90+E https://www.planet-casio.com/Fr/forums/topic16905--.html DOOM est un grand classique du jeu vidéo, un titre de 1993 qui a défini toute une histoire de jeux en 3D par un succès commercial fou et un héritage très riche. C'est aussi un jeu admirablement bien programmé, qui peut tourner sur une grande gamme de plateformes, et désormais aussi sur la Graph 90+E. :D Pour les impatients : Page du projet avec les téléchargements. CGDoom-DOOM-1.png À gauche : E1M7 (Computer Station), à droite : E2M7 (Spawning Vats) Porter DOOM sur des calculatrices graphiques n'est pas une idée nouvelle ; il y a d'abord eu nDoom sur TI-Nspire (de Mrakoplaz), puis nDoom 2 (de Critor), ensuite une première version de CGDoom (0.03) sur la Prizm (de Martin Poupe), et enfin une version revisitée de CGDoom (1.0) que j'ai programmée récemment avec l'aide de Computer_Freak_2004. CGDoom 1.0 permet non seulement de jouer à Ultimate Doom, mais supporte aussi officiellement Doom II, et peut lancer plein d'autres jeux indépendants construits sur le moteur de Doom (... même si ça peut crasher de temps en temps :P). Beaucoup de fonctionnalités ont été ajoutées pour en faire un version agréable et pertinente de la série ! ;) https://www.planet-casio.com/storage/staff/CGDoom-E1M1-Lephe.mp4 Visualisation d'un démo de E1M1 joué sur Graph 90+E. Support des titres et RAM Par rapport au port original pour Prizm, CGDoom exploite plus de RAM avec des modifications précises du code de gestion mémoire et permet donc de charger des niveaux plus gros. La totalité d'Ultimate Doom peut être jouée en utilisant la RAM standard de la Prizm (environ 1 Mo en plusieurs parties). Mais ce n'est pas tout : la Graph 90+E possède une puce RAM de 8 Mo (au lieu de 2 Mo pour la Prizm) et CGDoom est le premier add-in à utiliser cette RAM supplémentaire. L'option Use experimental RAM permet de récupérer environ 3 Mo de mémoire supplémentaire et ainsi de jouer à des très gros niveaux comme ceux de Doom II ! ^^ CGDoom-doomu-menu.png` `CGDoom-doom2-menu.png Ultimate Doom (1993) et Doom II: Hell on Earth (1995) Il y a plein d'autres jeux officiels et indépendants à tester, et nul doute que CGDoom supportera officiellement d'autres titres dans le futur. Performances Doom est super bien codé, mais atteindre les 35 FPS nécessaire pour faire tourner le jeu à pleine vitesse est assez difficile. Beaucoup d'optimisations ont été faites, notamment sur le chargement des WADs, la mémoire de dessin, l'interface avec l'écran, l'allocation... Par défaut CGDoom saute un frame sur deux et tourne de façon stable à 18 FPS, ce qui permet de jouer à la vitesse normale. En overclockant avec Ptune3, on peut atteindre 35 FPS sans sauter de frames dans la plupart des endroits, ce qui donne l'expérience fluide de Doom sans concessions ! :D Contrôles CGDoom supporte plusieurs jeux de contrôles par défaut, que vous pouvez tous customiser individuellement (attention au ghosting cependant !). Les contrôles, tout comme le reste des options, sont sauvegardés dans la mémoire de stockage d'un lancement de l'add-in à l'autre. CGDoom-Controls-1.png` `CGDoom-Controls-2.png Sauvegarde de parties La fonctionnalité de sauvegarde de parties est aussi disponible, via les entrées Save Game et Load Game du menu du jeu. Pour chaque WAD, jusqu'à 6 parties peuvent être sauvegardées dans des fichiers `.dsg`. Les sauvegardes peuvent être rechargées bien sûr, mais aussi échangées entre plusieurs calculatrices et même sur le PC pourvu que le même WAD soit utilisé partout. ;) Les jeux de la série Doom sont longs et relativement difficiles donc quelques points de sauvegarde ne seront pas de trop en attendant que vous arriviez à les finir en moins de 30 minutes. :p Enregistrement/replay de démos Une autre fonctionnalité très utile est l'enregistrement et le replay de fichiers démos ! Vous pouvez enregistrer vos saisies au clavier dans un fichier, et ensuite les rejouer directement sur la calculatrice, sur un PC, et ou même partager les démos avec d'autres joueurs qui pourront les visualiser sur leur propre calculatrice. C'est comme ça que la vidéo ci-dessus est obtenue. S'il y a des gens intéressés, j'ai ouvert un petit leaderboard sur le topic du projet, avec quelques runs de E1M1 UV-Max. x3 Conclusion et téléchargements L'implémentation de CGDoom a été toute une aventure (pas encore tout à fait finie d'ailleurs !) et les résultats sont bien au-delà de mes espoirs initiaux. Il y a beaucoup de jeux à explorer avec ce moteur, j'espère qu'il vous plaira ! o/ Téléchargement de CGDoom, des WADs, et instructions À bientôt sur Planète Casio ! ;) Thu, 14 Oct 2021 09:33:30 +0200 TDM 22 : Optimisations de stratégie en Basic https://www.planet-casio.com/Fr/forums/topic16904--.html Le Tutoriel du Mercredi (TDM) est une idée proposée par Ne0tux, qui recouvre tous les usages de la calculatrice - des applications de Casio à la conception de jeux en passant par la production artistique. Aujourd'hui, on s'intéresse à des optimisations en temps et espace de programmes Basic ! Niveau ★ ★ ★ ☆ ☆ Tags : Listes, Complexes, Équations, Probabilités, Basic Bienvenue, chers lecteurs, dans cette 22ème édition du TDM. Avec le déroulement animé de la 1kBCJ#4 et de la 1kBCJ#5, j'ai eu l'occasion de refaire un peu de Basic récemment, et je voulais profiter de l'occasion pour partager des stratégies d'optimisation. Les techniques que je présente ici ont été utilisées dans mes participations (Fiery Fighter et Prison Gelée), donc je m'en servirai d'exemples concrets pour ne pas juste parler de code. La plupart des optimisations répandues en Basic sont locales et correctes : omission de parenthèses fermantes (gain d'espace), usage de `List1`...`List6`, `⇒` (réduction du temps de lecture du code), stockage dans les variables de valeurs redondantes (gain de temps d'évaluation)... toutes ces astuces sont locales parce qu'elles agissent à petite échelle et ne nécessitent pas de comprendre le programme entier pour fonctionner ; et elles sont correctes car elles ne changent pas le comportement du programme. Les optimisations qui m'intéressent ici, et que j'appelle « optimisations de stratégie » (ce n'est pas un terme technique), consistent à modifier le modèle du programme et son calcul quitte à modifier son comportement en échange d'un gain d'espace ou de performances plus conséquent. ;) De façon générale, je trouve que ce sont des transformations difficiles à faire sur des programmes déjà finis, car il est compliqué de changer le comportement d'un programme bien poli. À la place, je les trouve utiles durant le prototypage, à un stade où on peut encore se permettre de modifier le concept du programme en échange de meilleurs performances. Sur ce, à l'attaque ! En plus des stratégies je rappellerai quelques mécanismes, qui sont les outils Basic performants que l'on veut utiliser et qui motivent les stratégies. Mécanisme : calcul parallèle sur les listes Stratégie : privilégier les comportements homogènes Mécanisme : calcul vectoriel avec des complexes Stratégie : coordonnées dans le plan avec des complexes Stratégie : simplifier les boucles critiques Stratégie : utiliser des objets définis par des équations Stratégie : actions probabilistes Mécanisme : calcul parallèle sur les listes On ne présente quasiment plus le « calcul listique », une forme de calcul sur les listes que possède le Basic Casio. (Pour la petite histoire, le terme est apparu sur le forum ; « monadique » serait plus précis mais trop pédant, et à défaut d'une bonne alternative, on continue d'employer l'original.) Calculer avec tous les éléments d'un coup. Le principe est simple : une seule opération utilise ou modifie tous les éléments d'une liste à la fois. Par exemple, l'opération « carré » (`²`) est étendue aux listes et peut calculer le carré de tous les éléments d'une liste à la fois. {1,2,3,4,5→List 1 List 1²→List 1 # = {1,4,9,16,25} Ce calcul produit le même résultat que stocker à la main le carré de chaque élément. For 1->I To Dim List 1 List1²→List 1 Next Ce qu'on peut voir aussi, et c'est un avantage qui n'est pas évident quand on pense juste aux opérations, c'est que si on ne spécifie pas de destination le résultat est stocké dans `List Ans`, ce qui évite d'avoir à créer une nouvelle liste si on a besoin de conserver l'originale. # Avec le carré étendu et List Ans List 1² # Avec le carré étendu, sans List Ans List 1²→List 2 # Sans le carré étendu Dim List 1 Ans→Dim List 2 For 1→I To Ans List 1²→List 2 Next L'usage des opérations étendues sur les liste est crucial pour optimiser à la fois la vitesse du programme et sa taille. Les boucles sont naturellement les parties les plus chargées des programmes, donc les éliminer au profit de calculs sur les listes est presque toujours bénéfique. Quant à l'espace, le gain est évident. Sans compter que moins il y a de code plus ça va vite en général (Basic oblige). Combinaisons de listes et de constantes. Le calcul sur les listes ne se limite pas qu'aux listes entre elles : on peut aussi utiliser des constantes dans les opérations. {1,2,3,4,5→List 1 2List 1+7→List 1 # = {9,11,13,15,17} Ça marche même avec des constantes complexes (détaillées ci-dessous), ce qui permet à une très vaste classe de tâches d'être optimisée avec du calcul parallèle sur les listes. ;) Aperçu rapide des fonctions. Il faudrait rentrer dans beaucoup de détails pour donner une vue exhaustive de toutes les opérations qu'on peut faire sur les listes, mais vous pouvez avoir une intuition avec les quelques outils suivants : Réductions : `Min()`, `Max()`, `Sum` (parfois utiles : `Mean()`, `Median()`, `Prod`) Génération de listes : `Seq()`, `Augment()` Arithmétique : `+ - × ÷`, `Int÷`, `Rmdr`, `Abs` Opérations logiques : comparaisons, `And`, `Or`, etc Essentiellement toutes les fonctions courantes sur les réels et complexes C'est tellement puissant qu'en fait si vous pouvez représenter votre calcul comme la répétition uniforme d'un calcul unique sur plein de valeurs, alors vous pouvez presque automatiquement le paralléliser et exploser les performances ! :O Vous savez peut-être (c'est un peu le méta en Basic) que la majorité du temps passé dans l'exécution d'un programme par PRGM est dans la lecture du code (ou, si vous faites beaucoup de dessin, dans le rafraîchissement permanent de l'écran). Une des stratégies quasi-universelles est donc d'utiliser les instructions les plus puissantes possibles pour faire le maximum de travail avec le minimum de code. Le calcul sur les listes atteint très élégamment cet objectif en exprimant avec peu de code ce qu'on veut calculer. Ainsi, au lieu de perdre du temps à lire les instructions entre le `For` et le `Next` des dizaines de fois, PRGM va utiliser une boucle for codée directement dans l'interpréteur, qui va beaucoup plus vite, surtout si les calculs à faire sont intensifs. Stratégie : privilégier les comportements homogènes Pour pouvoir mettre en oeuvre le calcul parallèle sur les listes, il faut éviter les exceptions : tous les éléments de la liste doivent avoir le même rôle pour qu'on puisse faire un seul calcul pour tout le monde, sinon on se retrouve à gaspiller du temps et du code précieux à gérer les cas particuliers. Pour donner un exemple qui marche bien, dans Fiery Fighter, il y a une petite dizaine de projectiles dont la position est stockée dans deux listes, `List1` pour les abscisses et `List2` pour les ordonnées. Le joueur est à la position `A,B`. On veut calculer s'il y a une collision, à savoir un projectile à moins de 3 pixels du joueur, et le calcul parallèle sur les listes trivialise complètement la tâche : Abs (List1-A+i(List2-B 3>Min(List Ans⇒Goto L En plus des listes il y a un peu de complexes là-dedans (j'en reparle plus tard), mais vous pouvez voir que le calcul parallèle est utilisé 5 fois sur la première ligne : `List1-A` et `List2-B` calculent la position des projectiles par rapport au joueur (2 opérations) ; `...+i(...` donne un complexe (vecteur) qui combine la position en abscisse/ordonnée (2 opérations) ; `Abs ...` calcule la distance au joueur (1 opération). À la fin de la première ligne on obtient donc dans la `List Ans` la distance entre le joueur et chaque projectile, et ensuite on regarde si le plus près est à moins de 3 pixels. Il y a un autre exemple parlant dans Prison Gelée, concernant la génération de la map. Cette fois il n'y a pas de calcul direct sur les listes, mais il y a une boucle qui est grandement simplifiée en évitant les cas particuliers. Dans ce jeu, la map est découpée en trois faces carrées de 5x5 : TDM22-prisongelee-1.png La map est stockée sous la forme suivante, avec les 3 faces côte-à-côté (sur la face 3 les lignes sont en direction de la face 2, les colonnes en direction de la face 1). 40010 10110 20000 00400 10000 00404 00100 04080 11000 10101 01100 00000 60102 00000 01010 Pour dessiner la map il faut regarder toutes les cases voisines et mettre un trait là où il y a des murs. Le problème se pose au niveau des transitions de face, particulièrement celles de la face haute (la 3). Visuellement, le bord bas de la face haute donne sur la face gauche (la 1), mais dans la matrice la face 1 est tout au début. Visuellement, le bord droit de la face haute (qui est vertical) donne sur la première ligne de la face droite (qui est horizontale). Pour accéder aux bonnes informations dans la matrice, il y a donc pas mal de petits calculs à faire pour trouver quelle case est à côté de quelle case, ce qui est à la fois fastidieux et lent. L'alternative qui est employée dans Prison Gelée consiste à dupliquer l'information pour la mettre à la place attendue. La matrice est étendue comme ceci : 40010 10110 20000 0 00400 10000 00404 1 00100 04080 11000 1 10101 01100 00000 0 60102 00000 01010 1 ..... ..... 40010 Ainsi la première ligne de la face 1 est dupliquée sous la face 3, et la première ligne de la face 2 est dupliquée et recopiée à droite de la face 3. (Les points sont des valeurs quelconques inutilisées par le programme.) Avec cette modification, le dessin devient beaucoup plus facile, parce qu'on peut trouver toutes les cases adjacentes en regardant à droite en bas dans la matrice sans se soucier des conditions de bord, ce qui est à la fois plus rapide et économe en espace. Mécanique : Calcul vectoriel avec des complexes Je sais qu'on en parle beaucoup, mais utiliser les complexes pour faire des coordonnées 2D est un des outils le plus pétés en Basic. C'est parce la théorie mathématique des nombres complexes est incroyablement riche, et contient énormément d'opérations utiles qui sont très utiles pour bouger des objets dans le plan. Elle a aussi des liens extrêmement forts avec la théorie des vecteurs 2D et donc on peut s'en servir pour faire plein de géométrie. ;) Des paires de réels. L'intuition la plus simple c'est de voir un nombre complexe comme une paire de nombres réels. Le premier est appelé partie réelle du nombre complexe, et le second est appelé partie imaginaire. On pourrait écrire la paire (x,y), mais on préfère utiliser un nombre spécial noté i et écrire x+iy. Le nombre i n'est pas un réel donc on ne peut pas simplifier iy (un peu comme si j'écrivais « x pommes + y tomates », on ne peut pas mélanger les deux). Bien sûr si vous avec deux nombres vous pouvez toujours les interpréter comme les coordonnées d'un point du plan, comme sur la figure de gauche ci-dessous. On appelle ça des coordonnées cartésiennes, et du coup x+iy est appelé la forme cartésienne d'un nombre complexe. TDM22-complexes-1.png Formes cartésienne et polaire d'un nombre complexe. Ce n'est pas tout, cependant. Un point du plan vous pouvez aussi le désigner par la distance qui le sépare de l'origine (appelée rayon et notée r), combinée avec l'angle entre la direction du point et l'axe horizontal (noté θ), comme sur la figure de droite. On appelle ça les coordonnées polaires, et il y a aussi une forme polaire des complexes, qu'on écrit r`∠`θ. (Pour les curieux, c'est juste une notation pour le nombre complexe r·e^(iθ). Mais là ça devient compliqué.) Le fait que les complexes aient ces deux formes montre déjà à lui tout seul qu'on peut utiliser les complexes pour calculer des positions dans le plan (avec x et y), des mouvements (aussi avec x et y), des distances (avec r), et des angles (avec θ). Opérations de corps. Sans rentrer trop dans les détails, vous pouvez additioner, multiplier et diviser les nombres complexes, et toutes les propriétés dont vous avez l'habitude marchent (commutatitivé, associativité, distributivité, etc). Si vous additionez x+iy avec z+it, vous récupérez, sans trop de surprise, (x+z)+i(y+t). Ce que ça veut dire c'est qu'une seule addition de complexe peut faire deux additions de nombres réels. On peut donc, par exemple, stocker dans une variable la position d'un objet sous forme de complexe, dans une autre sa vitesse, et faire une seule addition pour calculer le déplacement. 64+32i→P # L'objet est à la position (64,32) 3+5i→V # On se déplace de 3 pixels/frame en X, 5 pixels/frame en Y P+V→P # Pouf, déplacement fini ! Ça peut sembler anodin avec un seul point mais ça devient redoutable quand on fait des listes de complexes et qu'on remplace les additions par des opérations parallèles sur ces listes. Oui les stratégies de ce tutoriel se combinent ! :lol: Pour information, il y a quatre fonctions qui permettent de calculer les coordonnées (et qui marchent sur les listes) : `ReP` calcule x, `ImP` calcule y, `Abs` calcule r, et `Arg` calcule θ. Vous pouvez totalement créer un complexe dans sa forme cartésienne et ensuite récupérer r/θ (calcul de distance/angle entre deux objets), ou créer un complexe dans sa forme polaire et ensuite récupérer x/y (calcul de trigonométrie et tracé, parce que oui il y a aussi de la trigonométrie là-dedans). :p Stratégie : coordonnées dans le plan avec des complexes Les complexes sont utiles pour calculer dans le plan y compris dans des situations inattendues. Par exemple, le bord du cube dans Prison Gelée forme un hexagone régulier. On le dessine en Super DrawStat en même temps que les murs, et donc on a besoin de calculer la position des 6 points de cet hexagone. Eh bien ça se fait avec des complexes et du calcul sur les listes ! 1∠(π{1,3,5,7,9,11,1}÷6→List1 La plupart des usages utiles des complexes proviennent du fait qu'avec une seule variable, ou une seule liste, on peut stocker les positions à la fois en abscisses et en ordonnées, et donc chaque calcul fait plus de travail. Dans ce cas on utilise juste les coordonnées cartésiennes, ce qui est déjà pas mal, et donne de bons résultats. Par exemple une fois la `List1` crée comme ci-dessous et étendue pour contenir les murs, on peut la dessiner en une seule ligne comme ceci. Graph(X,Y)=(ReP List1,ImP List1[T Mais pour donner un autre exemple assez fort, dans Fiery Fighter il y a régulièrement des projectiles créés qui volent dans la direction du joueur à une vitesse choisie aléatoirement. Ici, le joueur est à la position (A,B) et le projectile apparaît à la position E (complexe). Le projectile doit avoir une vitesse de `3Ran# +1` et aller dans la direction du joueur. On calcule `A+iB-E` pour connaître la position relative du joueur et du projectile, ensuite on obtient l'angle avec `Arg` et on utilise la notation `∠` pour créer le vecteur vitesse à partir de cet angle et de la vitesse aléatoire. (3Ran# +1)∠Arg (A+iB-E→List 7[I On obtient un complexe dont la partie réelle (le x) est la vitesse horizontale du projectile, et la partie imaginaire (le y) est la vitesse verticale. Cette information est réutilisée à chaque tour pour calculer la nouvelle position des projectiles par une simple addition. ReP List 7+List1→List1 # Abscisses ImP List 7+List2→List2 # Ordonnées Et ainsi, on passe des coordonnées cartésiennes (A,B et E) aux polaires (vitesse/angle) aux cartésiennes (position/vitesse), ce qui permet de programmer sans effort une mécanique de jeu pas tout à fait évidente. :) Projections, déformations, perspectives. J'ai mentionné que la théorie des nombres complexes se rapprochait beaucoup de celle des vecteurs 2D. Ce n'est pas un hasard, et on pourrait passer des heures à détailler toutes les raisons mathématiques qui provoquent ce lien. Mais pour l'instant j'ai surtout parlé des complexes et pas beaucoup des opérations vectorielles. Parmi les choses utiles que la théorie des vecteurs (ou algèbre linéaire pour les intimes) apporte, il y a de quoi faire des rotations et déformations du plan. Pour reprendre l'exemple du cube de toute à l'heure, il y a 3 faces planes avec 3 « projections » différentes. Dans le code le dessin est fait en 2D normalement et ensuite une transformation est appliquée pour déformer le résultat pour donner l'effet 3D. Ça prend quelques multiplications, le plus long c'est d'indiquer pour chaque face la position du coin haut droite et les directions horizontale et verticale. Bien comprendre les complexes (... et l'algèbre linéaire) est assez difficile mathématiquement parlant, mais il y a pas mal de choses utiles qu'on peut apprendre à faire avec un peu de pratique, et ça devient vite un outil incontournable. ^^ Stratégie : simplifier les boucles critiques J'ai mentionné plus haut qu'optimiser en espace aide à optimiser en temps. C'est parce que le code n'est pas compilé ; PRGM passe son temps à lire les instructions, chercher les retours à la ligne, et chercher les fins de blocs. Par exemple, si vous avez une condition qui est fausse dans un `If`, PRGM va quand même devoir lire tout le code du `If` pour déterminer s'il y a un `Else` et trouver le `IfEnd`. Ça veut dire qu'on ne peut pas se contenter de regarder le code exécuté pour optimiser la vitesse d'un programme, il faut aussi regarder le code non exécuté. Et sur ce point, les structures de contrôle habituelles (`If`, `For`, `While`, etc) ne sont pas bonnes parce que tout le code est à l'intérieur du bloc. Pour qu'une boucle critique tourne rapidement il faut descendre le plus vite possible du haut vers le bas et maximiser le temps passé à faire des choses utiles. Lire du code qui n'est pas exécuté n'est pas utile, donc le code qui n'est pas exécuté souvent ne doit pas être dans la boucle critique. Dans Fiery Fighter, la boucle critique déplace le joueur, les missiles, et calcule les collisions entre le joueur, la map, et les missiles. Le joueur n'attaque pas souvent, donc le code n'a pas besoin d'être dans la boucle. Les missiles n'apparaissent pas souvent, donc le code n'a pas besoin d'être dans la boucle. Et le joueur ne peut mourir qu'une fois donc évidemment ce code-là n'est pas dans la boucle non plus. À la place, les conditions sont calculées et le code détaillé est lié via un label. While 1 ... Collision⇒Goto C Lbl D ... WhileEnd Lbl C ... Goto D De cette façon, lorsque la condition n'est pas remplie (ie. quasiment tout le temps), la boucle critique peut continuer immédiatement sans avoir à lire tout le code du Lbl C, ce qui prend du temps même s'il n'est pas exécuté. ;) Cette technique est la plus notable que j'ai à mentionner en rapport avec les boucles critiques spécifiquement, mais bien sûr réduire la taille du code exécuté avec n'importe laquelle des techniques précédentes est tout aussi important. Stratégie : utiliser des objets définis par des équations Le Basic est très orienté maths, et il est assez facile de faire des calculs compliqués avec peu de code tant qu'ils rentrent dans un cadre mathématique. Par exemple, la map de Fiery Fighter a 5 côtés qu'on peut représenter par des droites : TDM22-fiery-1.png y ≤ 1.5x + 6 y ≤ 56 y ≤ -0.5x + 96 y ≥ -0.25x + 20 y ≥ 0.5x - 26 Pour chaque droite, j'ai noté si c'est les valeurs de y au-dessous (≤) ou au-dessus (≥) de la droite qui sont dans la map. On peut représenter toutes les droites avec 3 listes : une pour le coefficient de x, une pour le coefficient constant, et une pour la direction. {1.5,0,-.5,-.25,.5→List4 {6,56,96,20,-26→List5 {1,1,1,0,0→List6 Comme on peut utiliser des comparaisons dans le calcul parallèle sur les listes, on peut déterminer assez facilement si une position (A,B) est du bon côté de chaque droite : AList4+List5≥B≠List6 Ce calcul donne une liste où chaque valeur vaut 0 si le point (A,B) est du bon côté de la droite et 1 sinon. Pour savoir si le point (A,B) est dans la map il faut tester s'il y a un 1 dans la liste. Il y a plusieurs moyens de faire ça, par exemple en ajoutant toutes les valeurs : 0=Sum(AList4+List5≥B≠List6 # = 1 si (A,B) est dans la map, 0 si collision Le résultat de ce calcul est utilisé pour gérer les collisions joueur/map. Dans le jeu, on est en (A,B) et on veut savoir si on peut aller en (A+2C,B+2D), donc le test se fait à cet endroit-là. Si le test renvoie 1, on met à jour la position. 0=Sum ((A+2C)List4+List5≥B+2D≠List6 A+2CAns→A B+2DAns→B Voyez le peu de code nécessaire pour le système complet de déplacement/collisions du joueur ! :p Stratégie : actions probabilistes L'aléatoire est un outil très polyvalent. On s'en sert le plus souvent dans les jeux, pour donner de la variété, mais on peut aussi s'en servir pour optimiser en réduisant la quantité de travail à faire. Dans Fiery Fighter, la liste des projectiles a une taille fixe, et les projectiles sont « recyclés » quand ils sortent de la map pour pouvoir être re-tirés plus tard. Il faut donc collecter les projectiles quand ils sortent de la map, ce qui se fait par un calcul de collision. Le calcul de collision utilise des listes pour tester tous les bords de la map en même temps (voir la partie précédente), donc on ne peut pas en plus tester tous les projectiles en même temps. Mais tester les 8 projectiles individuellement à chaque frame (0.5s environ) est beaucoup trop long, surtout qu'ils ne sortent pas souvent de la map. Chacun son tour, au hasard. Une solution à ce problème est de tester aléatoirement un projectile à chaque frame. Comme ça on réduit drastiquement le temps de calcul, et comme le générateur aléatoire est « équilibré » tous les projectiles sont testés régulièrement. Du coup les projectiles peuvent rester quelques temps hors de la map avant d'être testés et recyclés, mais ce n'est pas grave. Le temps de calcul économisé permet d'ailleurs d'en rajouter ! Bien sûr, ce n'est possible que pour les actions qui sont assez rares et assez peu importes. Hors de question de faire ça pour tester les collisions avec le joueur par exemple, parce que tous les projectiles qu'on ne regarde pas seraient libres de passer à travers le joueur ! ^^ Conclusion Voilà qui conclut ce tour d'horizon de quelques « optimisations de stratégie » en Basic. Même si la plupart d'entre elles ne nécessitent pas de modifier le comportement du programme, j'ai trouvé que c'est bien plus facile de les mettre en oeuvre si le programme est conçu et ajusté pour bien les utiliser. J'espère que ça servira pour les prochaines 1kBCJ ! ^^ À bientôt sur Planète Casio ! ;) Voir le TDM précédent : TDM #21 : Les animations et les structures de données Voir tous les Tutoriels du Mercredi Wed, 13 Oct 2021 13:40:12 +0200 Annonce : À La Limite Du Raisonnable du 15 au 17 Octobre https://www.planet-casio.com/Fr/forums/topic16901--.html Bonsoir à vous, bande de programmeurs dans l'âme ! C'est le moment parfait pour découvrir À La Limite Du Raisonnable, un court concours de programmation Basic Casio avec des prémisses vraiment borderline. x3 Cette édition sera la quatrième (#1 en 2012, #2 en 2013, #3 en 2013), et c'est vrai que sans l'avatar de Ray on n'est pas vraiment dans l'ambiance, donc voilà l'avatar de Ray. :p https://www.planet-casio.com/storage/avatars/3912.png Pour cette édition, vous aurez entre Vendredi 15 (au matin) et Dimanche 17 (au soir) pour écrire un programme respectant des contraintes délirantes mais gérables ; pour vous donner un avant-goût, les contraintes concernent : La rédaction du code : quels caractères vous avez le droit ou pas le droit d'utiliser. La structure du code : quelles fonctions, variables, etc. vous avez le droit ou pas le droit d'utiliser. Et le contenu du jeu : ce qui est présenté à l'écran. Comme précédemment, libre cours sera laissé à votre imagination, laquelle se verra aussi confier la tâche de contourner les contraintes pour arriver à vos fins. :) Le meilleur programme (jugé par mes soins) remportera une batterie portable CASIO grâce au soutien de CASIO Éducation ! ;) goodies-2021-2.jpg https://www.casio-education.fr/wp-content/themes/casio/assets/images/logo.svg Sur ce, à Vendredi prochain ! :bounce: Thu, 07 Oct 2021 20:49:54 +0200 IA Synchro-donjon #2 : Recherche de chemin https://www.planet-casio.com/Fr/forums/topic16895--.html Dans le cadre de notre concours de rentrée 2021 avec TI-Planet, nous te proposons de résoudre deux jeux codés en Python avec ta calculatrice graphique : La geste d'Alrys et Synchro-donjon. ;) concours-rentree-2021-banner.png Pour t'aider à aborder Synchro-donjon et à apprendre des choses nouvelles sur la programmation et l'intelligence artificielle, je te présente en détail les IAs groupées avec le programme, de la plus simple à une modérément perfectionnée. Aujourd'hui, on regarde `ia2_path.py` ! N'oublie pas de lire les règles de Synchro-donjon et de tester le programme sur ta calculatrice avant de lire cet article, sinon tu seras vite perdu·e ! ^^ Allez voilà, je te mets le code entier ici si tu veux tenter de le lire tout seul, et puis on va expliquer ce qui se passe et le tester ensemble. :) from polycal4 import get_infos from synchrod import * # Joueur qu'on veut sortir joueur_courant = 0 # Chemin pour le sortir chemin = [] def tour(plateau, joueurs, evenements): global joueur_courant, chemin # Réinitialisation en début de partie for (x, y, ev, joueur) in evenements: if ev == NOUVELLE_PARTIE: joueur_courant = 0 chemin = [] # Si le joueur est arrivé à sa destination, on passe au suivant. # Il arrive que plusieurs joueurs sortent en un seul tour, si ça se produit # on continue de passer au joueur suivant (il en reste forcément un qui # n'est pas sorti sinon la partie serait finie). while joueurs[joueur_courant] == -1: joueur_courant += 1 chemin = [] # Chemin du joueur actuel vers sa sortie if chemin == []: case_sortie = plateau.index(SORTIE + joueur_courant) chemin = calculer_chemin(plateau, joueurs[joueur_courant], case_sortie) # Prochaine étape mouvement = chemin[0] chemin = chemin[1:] return mouvement play_game(tour, blind=True) Le principe de cette IA est tout simple : on fait sortir chaque joueur dans l'ordre. ;) D'abord on détermine le chemin pour emmener Jaune de sa position initiale à sa sortie. À chaque tour on donne une étape du chemin jusqu'à ce que Jaune soit sorti. À ce moment-là, on détermine le chemin pour emmener Rouge de sa position courante jusqu'à sa sortie, et on refait pareil. Une fois Rouge sorti, on fait la même chose pour Bleu et Vert. Trouver un chemin n'est pas évident, mais `synchrod.py` peut le faire à ta place avec la fonction `calculer_chemin()`. Tu n'as pas donc à t'en soucier ! Voyons comment on code cette IA ! ^^ Conserver des informations entre chaque tour Notre IA a une stratégie "globale" qui dure toute la partie : elle traite les joueurs dans un ordre défini : Jaune, Rouge, Bleu, Vert. Elle doit donc se souvenir d'où elle en est quand on lui demande sa prochaine action. Il faut donc avoir des variables qui gardent leur valeur entre deux appel à notre fonction `tour()`, et pour ça on va utiliser des variables globales. ;) Ton professeur d'informatique/NSI t'as probablement enseigné qu'utiliser des variables globales est souvent un mauvais choix. Il/elle a raison ! Ici je m'en sers parce que les autres options compliqueraient beaucoup le code. joueur_courant = 0 chemin = [] def tour(plateau, joueurs, evenements): global joueur_courant, chemin # ... Notre IA ... Comme tu peux le voir, j'ai créé deux variables `joueur_courant` et `chemin`, et elles sont globales parce qu'elles ne sont pas dans une fonction. Dans la fonction `tour()` où je vais coder notre IA, j'indique à Python que je veux les utiliser avec la commande `global`, sinon Python refuserait de les modifier. Avec ça, on peut commencer à jouer ! Trouver et exploiter un chemin pour sortir Jaune Pour trouver un chemin, on peut utiliser la fonction `calculer_chemin()` qui est fournie par `synchrod.py`. Son fonctionnement est le suivant : chemin = calculer_chemin(plateau, case_de_depart, case_d_arrivee) Le plateau est celui qui est donné en premier paramètre de `tour` (il n'y en a qu'un de toute façon !). Les cases de depart et d'arrivée sont des nombres entiers, comme on a vu dans la présentation du problème. ^^ La réponse de `calculer_chemin()` est une liste de directions qui emmène de le case de départ à la case d'arrivée (et c'est le plus court chemin possible !). Mais comme une image vaut 1000 mots, voici le premier niveau que `synchrod.py` te donne (si tu ne changes pas la génération aléatoire) : concours-rentree-2021-synchrod-ia2-c0ffee.png On veut emmener Jaune de sa position initiale (ligne 1, colonne 1, de valeur 16×1+1=17) à sa sortie (ligne 2, colonne 15, de valeur 16×2+15=47). On appelle donc : chemin = calculer_chemin(plateau, 17, 47) Et la liste qu'on récupère est la suivante : chemin # [ALLER_DROITE, ALLER_DROITE, ALLER_DROITE, ALLER_DROITE, # ALLER_DROITE, ALLER_DROITE, ALLER_DROITE, ALLER_BAS, # ALLER_BAS, ALLER_DROITE, ALLER_DROITE, ALLER_DROITE, # ALLER_DROITE, ALLER_HAUT, ALLER_DROITE, ALLER_DROITE, # ALLER_DROITE] On peut visualiser le chemin comme ceci (cette visualisation utilise une version modifiée de `synchrod.py`). concours-rentree-2021-synchrod-ia2-c0ffee-path.png Voilà une base solide ! Maintenant, comment est-ce qu'on utilise la liste ? Voilà l'idée : la variable globale `chemin` va indiquer quelle chemin il nous reste à parcourir. Comme ça, à chaque tour, on peut choisir comme action le premier mouvement du chemin, retirer ce mouvement de la liste, et tout sera prêt pour le prochain tour ! C'est ce qu'on fait à la fin de la fonction : mouvement = chemin[0] chemin = chemin[1:] return mouvement Maintenant, il reste à agencer tout ça pour que tout le monde puisse sortir, pas juste Jaune. ;) Traiter tous les joueurs dans l'ordre On a quatre joueurs à faire sortir : Jaune, Rouge, Bleu et Vert (qui sont représentés par quatre entiers 0, 1, 2 et 3). C'est pour ça qu'on a deux variables globales : `joueur_courant` indique quel joueur on est en train de faire sortir. `chemin` indique quels mouvements ils restent pour qu'il sorte. Si `chemin` est vide c'est qu'on ne l'a pas encore calculé. On commence donc avec `joueur_courant=0` (Jaune) et `chemin=[]` (pas encore calculé), jusque-là c'est cohérent ! Au début du tour, la première chose à faire est de tester si le joueur courant vient de sortir. On peut le savoir en inspectant la liste `joueurs` (le deuxième paramètre de `tour()`), qui indique la position de chaque joueur. Cette position est un nombre entre 0 et 127 si le joueur est sur le plateau, et vaut -1 si le joueur est sorti. Donc, si le joueur courant est sorti, on passe au suivant et on réinitialise `chemin` pour bien le recalculer. if joueurs[joueur_courant] == -1: joueur_courant += 1 chemin = [] Il y a une subtilité, cela dit : parfois deux joueurs peuvent sortir en même temps (si Vert et Bleu sont tous les deux à gauche de leur sortie et qu'on choisit `ALLER_DROITE` par exemple). Dans ce cas, `joueur_courant+=1` n'est pas suffisant, parce que `joueur_courant+1` est peut-être déjà sorti ! Pour éviter ça, on change le `if` en `while`, comme ça si `joueur_courant+1` est déjà sorti, eh bien on passe au suivant ! while joueurs[joueur_courant] == -1: joueur_courant += 1 chemin = [] Il ne reste plus qu'à calculer le chemin à prendre quand `chemin=[]`. (On pourrait le calculer à chaque tour, mais c'est inutile : le chemin reste le même jusqu'à ce que le joueur courant soit sorti !) if chemin == []: case_sortie = plateau.index(SORTIE + joueur_courant) chemin = calculer_chemin(plateau, joueurs[joueur_courant], case_sortie) Comme précédemment, j'utilise `calculer_chemin()`. Comme case de départ, on prend la position du joueur courant, et comme case d'arrivée, la position sur le plateau de sa sortie. `.index()` est une méthode de liste qui te donne la position dans la liste d'une valeur choisie, ce qui te permet ici de chercher des objets sur le plateau. :) Avec ça, l'IA est presque complète ! Rénitialiser à chaque nouvelle partie La fonction `play_game()` réalise toute une série de parties en une seule exécution du programme (par défaut, 100). Il faut donc s'assurer que l'IA est nettoyée entre chaque partie sinon les variables seront fausses. Pour ça, on peut utiliser le troisième et dernier paramètres de la fonction `tour` : la liste `evenements`. Cette liste indique ce qui se passe sur le plateau, et t'informe de quand les nouvelles parties commencent (et des effets des pièges). Au début de l'IA, on prend donc soin de réinitialiser nos deux variables globales à chaque début de partie, pour pas que les valeurs de la partie précédente ne viennent perturber le code. ^^ for (x, y, ev, joueur) in evenements: if ev == NOUVELLE_PARTIE: joueur_courant = 0 chemin = [] Et voilà ! Avec tout ça, le code est complet. Tu peux le voir de nouveau en entier : from polycal4 import get_infos from synchrod import * # Joueur qu'on veut sortir joueur_courant = 0 # Chemin pour le sortir chemin = [] def tour(plateau, joueurs, evenements): global joueur_courant, chemin # Réinitialisation en début de partie for (x, y, ev, joueur) in evenements: if ev == NOUVELLE_PARTIE: joueur_courant = 0 chemin = [] # Si le joueur est arrivé à sa destination, on passe au suivant. # Il arrive que plusieurs joueurs sortent en un seul tour, si ça se produit # on continue de passer au joueur suivant (il en reste forcément un qui # n'est pas sorti sinon la partie serait finie). while joueurs[joueur_courant] == -1: joueur_courant += 1 chemin = [] # Chemin du joueur actuel vers sa sortie if chemin == []: case_sortie = plateau.index(SORTIE + joueur_courant) chemin = calculer_chemin(plateau, joueurs[joueur_courant], case_sortie) # Prochaine étape mouvement = chemin[0] chemin = chemin[1:] return mouvement play_game(tour, blind=True) L'IA en action Il est temps de lancer cette IA et de voir de quoi elle est capable. Ce qui est sûr c'est que la méthode de faire sortir chaque joueur dans l'ordre doit permettre de résoudre toutes les plateaux (pas forcément rapidement). Lançons `ia2_path.py`... voilà ce que ça donne en interactif ! concours-rentree-2021-synchrod-ia2-anim.gif C'est pas mal du tout. Et voilà le résultat dans la console : #0: 12648430 Bravo! 39T 50D -> 61 #1: 594213422 Bravo! 75T 90D -> -15 #2: 236840551 Bravo! 80T 50D -> 20 #3: 2464859390 Bravo! 73T 90D -> -13 #4: 3280879791 Bravo! 87T 70D -> -7 #5: 3426230116 Bravo! 92T 120D -> -62 #6: 2269403964 Bravo! 64T 140D -> -54 #7: 1618746239 Bravo! 77T 30D -> 43 #8: 1236680090 Bravo! 80T 60D -> 10 #9: 3351370485 Bravo! 68T 80D -> 2 #10: 553563167 Bravo! 68T 10D -> 72 #11: 2315605486 Bravo! 72T 30D -> 48 #12: 1036554885 Bravo! 74T 30D -> 46 #13: 1875589748 Bravo! 62T 40D -> 48 #14: 2184596687 Bravo! 64T 80D -> 6 #15: 541455511 Bravo! 71T 80D -> -1 #16: 167669688 Bravo! 81T 70D -> -1 #17: 4207823168 Bravo! 97T 120D -> -67 #18: 1105457756 Bravo! 82T 50D -> 18 #19: 2614210402 Bravo! 58T 50D -> 42 #20: 2529202849 Bravo! 81T 50D -> 19 #21: 3055039143 Bravo! 68T 60D -> 22 #22: 2127226719 Bravo! 83T 130D -> -63 #23: 3082902456 Bravo! 41T 90D -> 19 #24: 4205257665 Bravo! 82T 30D -> 38 #25: 199407319 Bravo! 72T 30D -> 48 #26: 3746711289 Bravo! 83T 40D -> 27 #27: 878032796 Bravo! 74T 30D -> 46 #28: 4092570800 Bravo! 64T 30D -> 56 #29: 2286764744 Bravo! 66T 130D -> -46 #30: 1171391719 Bravo! 64T 110D -> -24 #31: 2776227355 Bravo! 78T 20D -> 52 #32: 894346068 Bravo! 63T 20D -> 67 #33: 4198606884 Bravo! 72T 90D -> -12 #34: 1999695195 Bravo! 72T 60D -> 18 #35: 3064761848 Bravo! 77T 70D -> 3 #36: 1746501463 Bravo! 60T 70D -> 20 #37: 3486740195 Bravo! 76T 160D -> -86 #38: 1456243622 Bravo! 70T 70D -> 10 #39: 4011916507 Bravo! 90T 40D -> 20 #40: 3151169566 Bravo! 80T 60D -> 10 #41: 940545148 Bravo! 71T 40D -> 39 #42: 3446077346 Bravo! 64T 80D -> 6 #43: 883263786 Bravo! 78T 70D -> 2 #44: 394521061 Bravo! 67T 20D -> 63 #45: 3141843215 Bravo! 66T 40D -> 44 #46: 1333750067 Bravo! 83T 90D -> -23 #47: 596029757 Bravo! 64T 60D -> 26 #48: 4053873450 Bravo! 81T 40D -> 29 #49: 716746680 Bravo! 64T 90D -> -4 #50: 1252794865 Bravo! 79T 70D -> 1 #51: 3501098597 Bravo! 78T 50D -> 22 #52: 3328255349 Bravo! 77T 20D -> 53 #53: 1238029435 Bravo! 85T 80D -> -15 #54: 3864774413 Bravo! 70T 50D -> 30 #55: 1518239785 Bravo! 85T 30D -> 35 #56: 91852842 Bravo! 64T 100D -> -14 #57: 3878397276 Bravo! 69T 100D -> -19 #58: 782363206 Bravo! 90T 20D -> 40 #59: 1793375283 Bravo! 85T 50D -> 15 #60: 3387026551 Bravo! 59T 40D -> 51 #61: 1748811549 Bravo! 66T 190D -> -106 #62: 2533799161 Bravo! 64T 50D -> 36 #63: 404853182 Bravo! 74T 60D -> 16 #64: 3616886901 Bravo! 66T 50D -> 34 #65: 2377478389 Bravo! 74T 80D -> -4 #66: 520238391 Bravo! 81T 50D -> 19 #67: 3718574493 Bravo! 96T 110D -> -56 #68: 832990622 Bravo! 81T 30D -> 39 #69: 428843202 Bravo! 79T 30D -> 41 #70: 769357530 Bravo! 75T 30D -> 45 #71: 3649605739 Bravo! 66T 80D -> 4 #72: 3740321927 Bravo! 66T 120D -> -36 #73: 3852969101 Bravo! 79T 80D -> -9 #74: 3256289293 Bravo! 64T 70D -> 16 #75: 3038448294 Bravo! 63T 90D -> -3 #76: 904654193 Bravo! 87T 40D -> 23 #77: 2018615892 Bravo! 75T 80D -> -5 #78: 2794925654 Bravo! 66T 110D -> -26 #79: 3312369991 Bravo! 71T 100D -> -21 #80: 241453064 Bravo! 70T 20D -> 60 #81: 109767354 Bravo! 68T 20D -> 62 #82: 4168036525 Bravo! 83T 100D -> -33 #83: 2534421228 Bravo! 85T 40D -> 25 #84: 2185394352 Bravo! 86T 10D -> 54 #85: 3553770696 Bravo! 108T 150D -> -108 #86: 2393592041 Bravo! 76T 70D -> 4 #87: 1625609068 Bravo! 64T 60D -> 26 #88: 3540367519 Bravo! 64T 50D -> 36 #89: 2216609637 Bravo! 66T 100D -> -16 #90: 2291443810 Bravo! 68T 60D -> 22 #91: 4284680541 Bravo! 72T 40D -> 38 #92: 3688132900 Bravo! 70T 30D -> 50 #93: 4091713635 Bravo! 68T 10D -> 72 #94: 4216499651 Bravo! 76T 110D -> -36 #95: 1079331201 Bravo! 70T 130D -> -50 #96: 2738161974 Bravo! 73T 60D -> 17 #97: 2206455251 Bravo! 85T 30D -> 35 #98: 3529942408 Bravo! 83T 140D -> -73 #99: 2009880399 Bravo! 80T 20D -> 50 Games solved: 100 Score: 2171 Bingo ! Comme tu peux le voir, tous les plateaux ont été résolus. Il y a plein de plateaux où le résultat est très mauvais (négatif, ce qui ajoute 0 au score), et on prend beaucoup de dégâts à cause des pièges et des monstres, mais c'est un bon début ! :D Le score de cette IA n'est pas moins de 2171, soit presque 22 points par plateau. La prochaine fois, on verra comment de toutes petites améliorations sur ce code permettent de faire un score beaucoup, beaucoup plus élevé. o/ Tue, 28 Sep 2021 21:08:24 +0200 La Revue des Projets – 218 https://www.planet-casio.com/Fr/forums/topic16892--.html Bonjour à tous ! Vous l'avez réclamé, vous l'avez attendu avec impatience, vous l'avez même crié dans la rue, voici la Revue des Projets 218 ! Malgré vos attentes, nous n'avons pas beaucoup de projets en ce moment. Certainement lié à un truc récent : La rentrée des classes :lol: En attendant nous avons tout de même 2 projets. Commençons par celui d'Inikiwi et son moteur de jeu pour calculatrice monochrome Du doux nom de ekiwi, le logiciel encore en cours de développement est capable de générer du code compatible avec gint de Lephenixnoir. Pour l'instant, peu de fonctionnalités et peu d'extravagance. Nous savons tout de même que cet éditeur (je me permets de l'appeler de la sorte) est capable de gérer les textures ainsi que le placement sur l'écran. Programmé avec Tkinter, l'interface incruste une prévisualisation de l'écran en cours ainsi que certains paramètres disponibles en fonction du type de l'objet sélectionné. Voyez par vous-même : https://i.imgur.com/7WvjK7Y.png Inikiwi ne semble pas vouloir s'arrêter là. Dans un récent message sur le topic de gint il nous parle de son moteur de collision encore en développement. L'objectif principal étant de rajouter une gestion de la gravité. Comme nous l'apprenons dans ce dernier message, l'auteur semble vouloir reprogrammer l'ensemble de son logiciel par la suite. Une décision étonnante mais sûrement réfléchie ? Je t'invite à expliquer ta décision en commentaire ;) Une chose est sûre, Inikiwi semble déterminé à pousser son projet le plus loin possible. Encore dans le flou pour certaines choses, nous pouvons nous poser plusieurs questions : :here: Comment comptes-tu gérer plusieurs écrans ? :here: As-tu prévu de rajouter des animations ? :here: Quelles actions seront disponibles pour le programmeur ? La possibilité d'ajouter du code à la manière d'un Scratch ? Et d'autres questions que je préfère garder pour l'instant :) Je vous invite à aller voir le topic du projet dans l'attente d'un dépot git :) Bon courage dans la programmation ! << topic du projet >> Et ce n'est pas fini ! Ce n'est pas réellement un projet vu qu'il possède déjà une version stable. Mais Thebigbadboy souhaitait mettre en avant son programme de calcul de limite. En effet vous ne pouvez pas l'avoir manqué, ces derniers temps Thebigbadboy travaillait d'arrache-pied pour perfectionner son programme. Et c'est chose réussie ! Une nouvelle version est depuis le 20 septembre, et le programme a été entièrement réécrit ! Les améliorations de cette version ? Eh bien c'est simple, l'auteur les a listées ! Toutes les améliorations de cette version-ci : :here: support des sauts de fonction pour les limites en un réel (comme "(1-cos x)/x²" qd x→0) :here: support des erreurs math dues à des dépassements arithmétiques :here: affichage du résultat sous forme de fraction (avec ou sans facteur π) :here: remaniement complet des algos pour différencier log log log x→+∞ tandis que 1E9/x→0 :here: Et tellement d'autres choses ! Pour donner une idée, log log log x, sin log x, sin x*e^x et 1E9/x qd x→∞ donnent tous les 4 une bonne réponse . https://www.planet-casio.com/storage/program-images/3735-Calcul_Limites.gif Concrètement, ce n'est pas possible de lister l'ensemble des modifications apportées par cette version. Je ne peux que vous conseiller d'essayer ce programme extrêmement pratique peut importe les situations ! Le taux d'erreur est très bas, et pour un programme basic, Thebigbadboy a fait des miracles ! :D Si vous souhaitez en apprendre davantage, que ce soit sur le plan technique que sur le plan mathématique, je vous conseille fortement d'aller voir la page du programme ainsi que ces derniers commentaires (oui oui le concours de pavé avec Lephenixnoir :lol:) Qu'attendez-vous ? Profitez de ce programme pour vérifier vos limites ! (Bien que je vous conseille fortement d'apprendre à les calculer :lol:) Je ne sais pas si Thebigbadboy a prévu de continuer son programme. Nous pouvons observer une liste d'amélioration possibles sur la page du programme, as-tu prévu d'essayer de les appliquer ? En attendant si vous trouvez un bug quelconque, n'hésitez pas à le signaler, il sera investigué de A à Z ! En attendant bravo pour cette mise à jour majeure. Toujours un plaisir de voir autant de détermination dans un programme pour la communauté ! << page du programme >> Et c'est sur ces deux projets que nous nous quittons pour aujourd'hui. Des projets de qualité guidés par la motivation de leurs auteurs ! Souhaitons leur bon courage ! Ils le méritent :D En attendant, A bientôt sur Planète Casio ;) Depuis la dernière RdP, 2 programmes ont été postés : :here: Shooter - Space Fight de Nitsugua38 :here: Cut The Rope de ROY Lire la RdP précédente : La Revue des Projets – 217 Besoin d'aide ? Une idée ? Un projet ? Un article ! Sun, 26 Sep 2021 19:24:34 +0200 La Revue des Projets – 217 https://www.planet-casio.com/Fr/forums/topic16888--.html Bonsoir à toutes et à tous ! On se retrouve pour l'éternelle Revue des Projets, pour présenter ce soir de petites avancées sur des grands chantiers ! Il fait pas beau en ce moment, vous trouvez pas ? On a eu une assez belle rentrée – que ce soit aussi bien sur un plan météorologique que évènementiel. En effet, lors la semaine dernière a été lancé le concours de rentrée annuel, que je vous invite fortement à regarder. Au programme, les deux épreuves traditionnelles, j'ai nommé l'optimisation d'itinéraire et la création d'IA – m'enfin pourquoi changer une équipe qui gagne, me direz-vous ? À la clé, de nombreux lots, et il n'y en aura pas pour tout le monde. Lancez-vous ! En piochant dans la liste des mentions de la RdP, nous n'avons qu'un seul post, de Dark Storm et d'Eragon. Mais pas des moindres, car ils nous annoncent en effet l'avancée sur un pont entre la shoutbox et l'IRC de la v5, à la manière du pont shoutbox <-> Discord de TI-Planet. Le code est déjà fonctionnel, en voici la démonstration : https://www.planet-casio.com/storage/forums/Capture-184408.png https://www.planet-casio.com/storage/forums/Screenshot%202021-09-10%20at%2014-51-44%20hs%20-%20PCshoutbox%20%C2%B7%20Plan%C3%A8te%20Casio-184409.png Ça semble être entièrement fonctionnel, ma foi ! Parfait pour les petits loups qui préfèrent rester sur les recoins sombres d'IRC... Je ne donnerai pas de nom. Selon Dark Storm, il resterait de petites améliorations à effectuer pour améliorer la lisibilité et ne pas gêner ni les utilisateurs de la shout, ni les utilisateurs d'IRC. Bonne chance à vous deux ! :) Nous continuons ensuite dans le domaine obscur de la chasse aux posts cachés surgis de nulle part. Tiens on va embêter Lephenixnoir qui poste sur CGDoom sans tagguer la RdP >:) Pour rappel, CGDoom, c'est ce tout petit programme, adapté par Lephenixnoir, d'après le travail de Martin poupe : https://www.planet-casio.com/storage/staff/CGDOOM-Graph90-1.mp4 Lephenixnoir continue toujours tranquillement son port de CGDoom sur Graph 90+E, avec l'aide de Computer_Freak_2004, dans des posts ultra-longs en anglais assez chiants à lire sur Cemetech. Voici un petit changelog résumant les dernières nouveautés apportées : Plein d'effets graphiques rétablis Le menu principal est de retour (avec les démos si on veut, mais elles ne sont pas pour la même version du jeu donc elles meurent vite) Les WADs avec les épisodes individuels d'Ultimate Doom ont été revisités et allégés (-1 MB ou -2 MB en moyenne) En utilisant la mémoire de la puce 8 Mo de la Graph 90+E (autorisé sur OS ≤ 3.60 pour éviter les mauvaises surprises dans le futur), mémoire infinie donc plein de jeux marchent : le shareware, Ultimate Doom, Doom II, on peut même viser Heretic et quelques autres (là il reste des bugs, ça vient). Quelques améliorations de performance Sauvegarde/restauration de partie (le jeu quitte après une sauvegarde, et bien sûr il ne faut recharger la partie qu'avec le même WAD) TL;DR : Harder, Better, Faster, Stronger— On attend le label de qualité, hein :) Pour finir, on va parler du Casio Basic Web Interpreter de Kevro_, qui se paye le luxe d'être mis à jour. Pour rappel, le CBWI (permettez-moi de l'appeler ainsi) est un outil permettant de lire du code en Basic Casio directement sur navigateur, ni plus, ni moins. Il s'est illustré récemment durant la 1KBCJ#5 avec la participation de Ptitjoz avec son jeu Dynamite, l'utilisant. Au programme de cette mise à jour, quelques petites améliorations. L'instruction `Menu` est à nouveau fonctionnelle, et des petits boutons pour insérer des caractères spéciaux ont été ajoutés, à la manière de Planète Casio. Enfin, le code et les librairies utilisées ont été mises à jour. Merci de prendre encore soin de ce projet Kevro_, et bonne continuation :) Pas vraiment un projet, mais Casio a publié récemment la mise à jour 3.50/3.60 de son OS, ajoutant une toute nouvelle application, Probabilités. Je vous invite à lire la news dédiée. https://www.planet-casio.com/storage/staff/prob-g90pe-lois.pngY'a écrit poisson alors c'est forcément cool, nan ? Sur ce, je vous souhaite une excellente fin de soirée ainsi qu'une bonne semaine. Et en espérant qu'il fasse plus beau, non mais... À bientôt ! Aucun programme n'a été posté depuis la dernière RdP. Lire la RdP précédente : La Revue des Projets – 216 Besoin d'aide ? Une idée ? Un projet ? Un article ! Sun, 19 Sep 2021 18:48:05 +0200 Nouveau menu Probabilités (mise à jour 3.50/3.60) https://www.planet-casio.com/Fr/forums/topic16886--.html CASIO a publié il y a un peu plus d'une semaine une nouvelle mise à jour de l'OS avec un menu Probabilités. La mise à jour est disponible en téléchargement : Pour Graph 90+E (OS version 3.60) : Windows et Mac Pour Graph 35+E II (OS version 3.50) : Windows Pour simulateurs USB : Graph 35+E II ou Graph 90+E Tutoriel détaillant l'installation sur le site de CASIO La nouvelle fonctionnalité dans cette version c'est donc cette application de probabilités, à l'aide de laquelle on peut calculer des propriétés des lois de probabilité classiques sans avoir à passer par les fonctions classiques comme `BinomialCD()` ou `InvNormCD()` qui sont un peu obscures à trouver et dures à retenir. ;) prob-g35pe2-menu.png prob-g90pe-menu.png Le menu principal permet de choisir la distribution à étudier, avec les options habituelles : Loi binominale (discrète, somme de Bernoulli) Loi normale (continue) Loi de Poisson (discrète, sans mémoire) Loi géométrique (continue, sans mémoire) Loi hypergéométrique Loi de Student Loi du χ² Loi de Fisher prob-g35pe2-lois.png prob-g90pe-lois.png Une fois la loi sélectionnée, on peut entrer les paramètres et indiquer le type de requête qu'on veut : P(X ≤ ...), P(... ≤ X ≤ ...), ou P(X ≥ ...) principalement. Pour les lois discrètes on peut aussi chercher P(X = ...). prob-g35pe2-options1.png prob-g90pe-options1.png Par exemple pour cette loi normale centrée réduite, je cherche la probabilité de tirer une valeur qui est dans un écart-type autour de la moyenne (un résultat très classique et qui ne dépend pas des paramètres de la loi normale). Quand on lance l'exécution, on obtient un graphe de la loi, la zone concernée par la requête, et le résultat : environ 68%. ;) prob-g35pe2-graphe1.png prob-g90pe-graphe1.png On peut faire pareil avec une loi discrète, par exemple une loi binomiale. Ici je cherche la probabilité d'avoir entre 47 et 53 pile dans une série de pile ou face, et le résultat est environ 52%. prob-g35pe2-options2.png prob-g90pe-options2.png prob-g35pe2-graphe2.png prob-g90pe-graphe2.png Voilà le genre de choses qu'on peut faire avec cette nouvelle application. Personnellement j'aime beaucoup (et je m'en servirai occasionnellement même si je ne suis plus au lycée !) parce que je n'arrivais jamais à me souvenir exactement de la disposition des anciennes fonctions dans le menu à onglets ni de l'ordre et le sens de leurs arguments. ^^ À bientôt sur Planète Casio ! ;) Sat, 18 Sep 2021 14:00:59 +0200 Concours de rentrée 2021 - Synchro-donjon ! https://www.planet-casio.com/Fr/forums/topic16878--.html Bienvenue au concours de rentrée 2021 organisé par TI-Planet et Planète Casio ! :D concours-rentree-2021-front.png Dans l'article introductif de l'événement, nous racontions comment tu as trouvé dans une brocante une console étrange avec deux cartouches. La deuxième de ces cartouches contient un jeu qui s'appelle Synchro-donjon. » Tableau des scores « Le but de Synchro-donjon est de conquérir le plus rapidement possible le donjon du Cirque des Monts Pleureurs, un donjon situé au Nord-Ouest du royaume d'Alrys et que tu peux voir de l'extérieur en jouant à La geste d'Alrys, l'autre jeu de ce concours. Dans ce jeu, il y a quatre joueurs qui commencent dans les coins : Jaune, Rouge, Bleu et Vert. Le but est de traverser le donjon aux joueurs pour les faire sortir par leurs sorties respectives (sur le côté opposé du plateau). ;) concours-rentree-2021-synchrod-principe.png Il y a de nombreux étages au donjon, et chacun est différent et imprévisible - c'est pour ça que le donjon est difficile à conquérir. Pour permettre au héros de continuer son aventure dans le monde d'Alrys, tu devras donc user d'ingéniosité et programmer ta calculatrice pour décider des actions à effectuer à chaque étage. En somme, ta tâche est d'écrire une IA pour Synchro-donjon ! :bounce: Dans cet article je vais te présenter les règles du jeu. Mais je peux déjà te dire ce qui rend ce jeu est intéressant : comme tu n'as qu'une calculatrice branchée, la console pense que tu veux contrôler les 4 joueurs d'un coup, et donc toutes tes actions s'appliquent à tous les joueurs en même temps ! Coordonner tout ce beau monde est la difficulté de ce donjon. Bien sûr, tu ne seras pas tout seul dans cette tâche, et plusieurs IAs te seront présentées pour t'aider à prendre en main le jeu ainsi que le code Python nécessaire pour écrire ton IA. Tu peux aussi joueur au jeu directement sur ta calculatrice pour te familiariser. ^^ Lis l'article explicatif de `ia2_path.py` : IA Synchro-don​jon #2 : Recherche de chemin Lis l'article explicatif de `ia3greed.py` : IA Synchro-donjon #3: Optimisations locales Règles du jeu Le donjon est un plateau de 8 lignes et 16 colonnes. Les bords sont constitués de murs et des sorties. Les 4 joueurs commencent dans les coins et chacun doit atteindre sa sortie. Sur leur chemin, on trouve : Des pics, qui font des dégâts si un des joueurs marche dessus. Des monstres, qui font aussi des dégâts si un joueur les croise, mais qui sont vaincus durant le combat. Il est aussi possible de les attaquer à distance et le vaincre sans prendre de dégâts. Des pièges, qui produisent des effets aléatoires et souvent imprévisibles : soit ils infligent des dégâts, soit ils font apparaître d'autres pics/pièges ailleurs dans le donjon. Les pics, monstres, et pièges violets affectent tous les joueurs. Ceux qui sont jaunes, rouges, bleus ou verts n'affectent pas le joueur correspondant (donc ils affectent tout le monde sauf le joueur qui partage leur couleur). À chaque tour, tu disposes de 5 actions possibles : Les 4 actions `ALLER_GAUCHE`, `ALLER_DROITE`, `ALLER_HAUT` et `ALLER_BAS` indiquent aux joueurs de se déplacer. Tout le monde effectue le même mouvement. Un joueur qui est bloqué par un mur ne se déplace pas. Si un joueur marche sur des pics, il prend des degâts ; s'il marche sur un monstre, il tue le monstre mais prend des dégâts ; s'il marche sur un piège, le piège est activé. L'action `ATTAQUER` indique aux joueurs d'attaquer les objets autour d'eux sans se déplacer. Tous les monstres à côté des joueurs sont détruits, et le joueurs ne prennent pas de dégâts. Cependant, tous les pièges à côté des joueurs sont également activés ! Au début du jeu, tu as 150 points. À chaque tour tu perds 1 point, et à chaque fois qu'un joueur prend des dégâts tu perds 10 points. S'il te reste des points quand tous les joueurs sont sortis alors ces points sont ajoutés à ton score. Dans Synchro-donjon, ton IA jouera sur un grand nombre de plateaux et le score de tous les plateaux s'ajoutent pour former ton score final. ;) Installation et utilisation du programme Synchro-donjon peut être installé sur les modèles suivants et sur PC. Le jeu est compatible avec un nombre impressionnant de modèles, allant jusqu'à la TI-82 Advanced Édition Python ! Ce résultat est possible grâce à la bibliothèque `polycal4.py` ainsi que des heures de compression investies par Critor. Les fichiers `polycal4.py` et `polyfont.py` sont identiques à ceux de La geste d'Alrys, l'autre jeu du concours. Tu n'as besoin de les transférer qu'une fois pour les deux problèmes. ;) Tu peux jouer toi-même interactivement en lançant `synchrod.py`. Quand tu auras une IA (un modèle est donné plus bas dans cet article), tu pourras faire jouer l'IA en lançant ton fichier Python. ^^ Trois IAs sont fournies avec le programme : `ia1_ask.py` qui est le squelette présenté plus bas, mais aussi `ia2_path.py` et `ia3greed.py` qui sont deux IAs plus évolées qui te seront présentées en détail plus tard durant le concours pour t'aider. :D Graph 35+E II et Graph 90+E : Télécharger les scripts Transfère `synchrod.py`, `polycal4.py` et `polyfont.py` dans la mémoire de stockage. Dans le mode interactif, tu dois appuyer sur AC/ON pour saisir tes actions dans la console. :here: Tutoriel de transfert de fichiers :here: Tutoriel d'overclocking :here: Émulateurs : Graph 90+E version 3.50 (Windows, Mac), Graph 35+E II version 3.40 (Windows) HP Prime : Télécharger l'application Installe directement l'application `SynchroD.hpappdir.zip`. Tu peux basculer entre la vue `Symb` pour modifier le script et la vue `Num` pour l'exécuter. :here: Logiciel HP Prime Virtual Calculator version 14592 (Windows 64 bits, Windows 32 bits) :here: Logiciel de transfert (Windows 64 bits, Windows 32 bits, Mac) :here: Tutoriel de transfert https://thumbs.gfycat.com/DelectableSilverAsiantrumpetfish-mobile.mp4 TI-Nspire CX et TI-Nspire CX II : Télécharger le classeur CX II ou les scripts pour KhiCAS Pour le classeur (CX II uniquement), transfère le fichier dans un dossier de ton choix, sélectionne-le avec `Ctrl →` et lance le avec `Ctrl R`. Fais de même pour le script de ton IA. La vidéo ci-dessous à gauche te détaille la procédure de lancement. Pour les scripts KhiCAS, transfère-les dans le dossier `/Xcas/` créé au premier lancement de KhiCAS, puis exécute soit `synchrod.py` soit ton IA en mode MicroPython. La vidéo ci-dessous à droite te détaille la procédure de lancement. :here: Pour le support Python via KhiCAS : Ndless et KhiCAS :here: Overclocking : Nover (Ti-Nspire CX), NoverII (TI-Nspire CX II) :here: Simulateurs : TI-Nspire CX CAS et TI-Nspire CX version 5.3.2 (Windows, Mac) :here: Logiciel de transfert : TiLP-II version 1.18 (Windows, Mac, Linux) https://thumbs.gfycat.com/FluffyPossibleJohndory-mobile.mp4 https://thumbs.gfycat.com/SillyHoarseLarva-mobile.mp4 TI-82 Advanced Edition Python : Télécharger les scripts Il te suffit de transférer le fichier `synchrod.py` (ainsi que les IAs de ton choix) puis de les lancer dans l'application Python. https://thumbs.gfycat.com/TightKlutzyAegeancat-mobile.mp4 TI-83 Premium CE et TI-84 Plus CE : Édition Python ou Adaptateur TI-Python Transfère `synchrod.py` accompagné de `SynchroD.b83` (TI-83 Premium CE) ou `SynchroD.b84` (TI-84 Plus CE). Transfère auss ton IA. Ensuite lance l'application Python et lance le script `synchrod.py` ou ton IA. Les vidéo ci-dessous te montrent la démarche pour lancer le programme. Celle de gauche concerne les anciennes TI-83 Premium CE et TI-84 Plus CE(-T) avec leur adaptateur TI-Python. Celle de droite concerne les TI-83 Premium CE Édition Python ainsi que les TI-84 Plus CE-T Édition Python et TI-84 Python. https://thumbs.gfycat.com/AccurateNarrowIchthyostega-mobile.mp4 https://thumbs.gfycat.com/ExcitableQuaintGlowworm-mobile.mp4 Numworks : Télécharger le script ou IDE en ligne Oméga Il te suffit de transférer et lancer `synchrod.py`. En raisons des limites de mémoire sur ce modèle, l'IA est incluses dedans, et tu peux la modifier et la soumettre sous cette forme. La mémoire limitée à 32 ko sur ce modèle risque de te freiner dans tes essais d'IA. Pour éviter ça, nous te conseillons d'installer un firmware tiers comme Oméga ou Khi pour disposer de 100 ko de mémoire. Le simulateur en ligne est tout aussi limité en plus d'être lent. Nous te conseillons plutôt le simulateur Oméga. :here: Transfert direct de fichiers avec WebUSB :here: Version dans le workshop Numworks (attention, peut geler le navigateur ; utilise plutôt l'IDE en ligne Oméga !) https://thumbs.gfycat.com/MediocreGrimDormouse-mobile.mp4 Ordinateur : Télécharger les scripts Si tu n'as pas de modèle compatible, tu peux aussi tester le programme sur ordinateur. C'est le programme original accompagné de `polycalc_sdl2.py`, une extension de `polycal4.py` qui permet de jouer sur un ordinateur. Tu auras besoin du module PySDL2 pour l'utiliser. Fonctionnement du plateau de jeu Le plateau de jeu contient 8 lignes et 16 colonnes, et est codé dans une liste Python de 8×16 = 128 entiers. Chaque élément de la liste indique l'état d'une case du plateau, et ils sont arrangés dans cet ordre : concours-rentree-2021-synchrod-board.png Si tu préfères numéroter les cases en lignes/colonnes, tu peux utiliser la méthode suivante. ;) Les lignes sont numérotées de `Y=0` (ligne du haut) à `Y=7` (ligne du bas). Les colonnes sont numérotées de `X=0` (colonne de gauche) à `X=15` (colonne de droite). La case sur la ligne `Y` et la colonne `X` a pour valeur `V`=`16*``Y``+``X`. La case de valeur `V` est sur la ligne `Y``=V//16` et sur la colonne `X``=V%16`. Chaque élément de la liste est une des valeurs suivantes : `VIDE`, `MUR`, `PICS`, `MONSTRE`, `PIEGE` ou `SORTIE`. En plus de ça, il peut y avoir une couleur : `JAUNE`, `ROUGE`, `BLEU`, `VERT` ou `TOUS` (violet). Le tableau ci-dessous résume les combinaisons : concours-rentree-2021-synchrod-tiles.png Sur les calculatrices monochromes, les couleurs sont remplacées par les symboles ci-dessous : concours-rentree-2021-synchrod-joueursmono.png Sur la TI-82 Advanced Édition Python, le jeu est entièrement en mode texte, et les caractères suivants sont utilisés : Les joueurs sont les symboles `¶` Les pics sont les trois-points `…` Les monstres sont les symboles `¥` Les pièges sont les symboles `Ø` Fonctionnement de l'IA L'IA de ton programme doit être un fichier Python avec une fonction pour décider ce qui doit se passer à chaque tour (ou, sur Numworks, une fonction Python intégrée à `synchrod.py`). Le squelette de base est le fichier `ia1_ask.py` : from polycal4 import get_infos from synchrod import * def tour(plateau, joueurs, evenements): # Demander une action avec input() return demander_action() play_game(tour) Les deux premières lignes importent les fonctions de Synchro-donjon. Évidemment, il est interdit d'accéder aux variables internes du script ou de modifier les valeurs identifiant les éléments de la map. :p La fonction `tour()` est ton IA. Elle est appelée à chaque tour du jeu avec trois paramètres et doit renvoyer une action à accomplir. `plateau` est la liste de 128 cases représentant le plateau de jeu (que tu ne dois pas modifier évidemment). `joueurs` est une liste de 4 éléments indiquant la position des 4 joueurs sur le plateau. Tu peux utiliser soit le style `joueurs` soit le style `joueurs[1]` selon tes préférences. Pour les joueurs qui sont encore sur le plateau, la position est un entier entre 0 et 127. Pour ceux qui sont déjà sortis, la valeur spéciale `-1` est utilisée. `evenements` est une liste d'événements qui se sont produits depuis le tour précédent. Les événements sont utiles dans des scénarios un peu rares. Chaque élément de la liste peut être égal à : `(-1,-1,NOUVELLE_PARTIE,-1)` si une nouvelle partie vient de commencer. `(<x>,<y>,PIEGE_APPARU,<joueur>)` si `<joueur>` a activé un piège qui a fait apparaître un nouveau piège à la ligne `<y>`, colonne `<x>`. `(<x>,<y>,PICS_APPARU,<joueur>)` si `<joueur>` a activé un piège qui a fait apparaître des pics à la ligne `<y>`, colonne `<x>`. La fonction `tour()` doit choisir et renvoyer une action parmi `ALLER_GAUCHE`, `ALLER_DROITE`, `ALLER_HAUT`, `ALLER_BAS` et `ATTAQUER`. Lorsque l'IA remporte la partie, une nouvelle partie commence automatiquement. Outils pour écrire ton IA `synchrod.py` fournit plusieurs outils pour t'aider à écrire ton IA, spécifiquement 4 fonctions. La fonction `demander_action()` donne la main au clavier de la calculatrice pour choisir la prochaine action. Sur les modèles où l'on peut saisir au clavier, les touches directionnelles, entrée et retour sont utilisées. Sur les autres (notamment CASIO), il faut appuyer sur AC/ON pour revenir à la console() et taper un chiffre. La fonction `est_un()` permet d'identifier les pics, monstres, et pièges indépendamment de leur couleur. Par exemple un piège vert est un piège mais pas un monstre, donc `est_un(PIEGE+VERT, PIEGE)` vaut `True` mais `est_un(PIEGE+VERT, MONSTRE)` vaut `False`. De façon similaire, la fonction `affecte()` permet de déterminer si des pics, monstres ou pièges affectent un joueur. Par exemple, les pics violets affectent Jaune mais pas les pics jaunes, donc `affecte(PICS+TOUS, JAUNE)` vaut `True` mais `affecte(PICS+JAUNE, JAUNE)` vaut `False`. Enfin, il y a une fonction `calculer_chemin(<plateau>, <début>, <fin>)` qui calcule en chemin entre la case `<début>` et la case `<fin>` et renvoie une liste de directions (`ALLER_*`). C'est un outil très utile et assez puissant, qui sera expliqué plus en détail avec une des IAs d'exemple. ^^ Utilisation de `play_game()` La fonction `play_game()` appelée à la fin du programme lance la simulation du jeu. Elle a plusieurs paramètres que tu peux modifier à loisir pour améliorer ton IA : `blind=True` peut être ajouté pour désactiver l'affichage du plateau de jeu et ne laisser que la console (ce qui va en général beaucoup plus vite). `seed=<nombre>` peut être ajouté pour tester un plateau particulier. La valeur indiquée permet en effet de contrôler le générateur aléatoire. `maxgames=<nombre>` permet de choisir le nombre de parties (par défaut 100). À chaque fois que tu gagnes une partie, `play_game()` affiche deux lignes sur la console : #0: 12648430 Bravo! 39T 50D -> 61 `#0` est le numéro de la partie (ça va jusqu'à `maxgames`). Le nombre à droite, `12648430`, est la graine aléatoire. Si tu demandes `seed=12648430` tu retomberas exactement sur ce plateau (ce qui est utile si ton programme a une erreur que tu veux retester). Sur la ligne du bas, le nombre devant `T` est le nombre de tours passés sur la plateau, le nombre devant `D` est la quantité de dégâts que tu as subis, et le résultat est ton score (`150-T-D`). Si ton score est négatif il compte pour 0. À la fin de la partie, `play_game()` affiche le nombre de parties jouées et ton score final. Par exemple : Games solved: 100 Score: 2171 Pour participer au concours Pour participer à l'épreuve de Synchro-donjon, envoie ton fichier .py d'IA (ou ton script `synchrod.py` modifié sur Numworks) par courriel à `contact@planet-casio.com` avant le Dimanche 7 Novembre à 23:59 avec : Pour sujet, Synchro-donjon ; Un moyen de te contacter rapidement en cas de gain ou de question (adresse courriel, téléphone, compte social, compte discord, etc.) ; Ton pseudonyme sur TI-Planet ou Planète Casio (optionnel) ; Pour pouvoir recevoir ton lot, ton adresse postale avec nom et prénom, et un numéro de téléphone personnel valide. (Tu peux les communiquer plus tard si tu souhaites.) Les informations personnelles transmises pendant ce concours ne seront évidemment utilisée que pour le bon fonctionnement de l'événement et sur sa durée. N'hésite pas à envoyer plusieurs participations, nous ne retiendrons que la meilleure. Lots Les lots pour cette épreuve sont les suivants. Les 5 participants ayant les meilleurs scores pourront choisir, par ordre de classement, un lot de leur choix. ;) 1 lot Graph 90+E : 1 calculatrice Graph 90+E + 1 sac et stylo CASIO + 1 pack de goodies TI-Planète Casio 1 lot Graph 35+E II : 1 calculatrice Graph 35+E II + 1 sac et stylo CASIO + 1 pack de goodies TI-Planète Casio 1 lot Goodies n°1 : 1 clé USB TI-83 Premium CE (4 Go) + 1 batterie externe CASIO (2200 mAh) + 1 sac et stylo CASIO + 1 pack de goodies TI-Planète Casio 1 lot Goodies n°2 : 1 recueil d'activités SNT Numworks (65 pages) + 1 clé USB simulateurs CASIO (8 Go) + 1 sac et stylo CASIO + 1 pack de goodies TI-Planète Casio 1 lot Goodies n°3 : 1 cahier «Boss des maths» Numworks (80 pages) + 1 clé USB simulateurs CASIO (8 Go) + 1 sac et syylo Casio + 1 pack de goodies TI-Planète Casio goodies-2021-1.jpg goodies-2021-2.jpg goodies-2021-4.jpg Tu peux voir l'article de TI-Planet sur les batteries externes pour plus de détails. Le fait qu'il y ait des lots moins fournis sur cette épreuve et que des calculatrices CASIO n'est pas une marque de favoritisme mais d'organisation. Ce sont les lots que j'ai (Lephe) collectés en plus de ceux que Critor a pour Alrys. J'ai demandé à Critor de procéder ainsi pour faciliter le traitement des participations et lots sur cette épreuve. ;) Et voilà pour cette épreuve ! Je compte sur toi pour tester toutes tes idées de génie et conquérir ce Synchro-donjon en temps record ! :D Sun, 12 Sep 2021 19:39:41 +0200