Seuls les membres ayant 30 points peuvent parler sur le chat.

Bienvenue sur Planète Casio !

Planète Casio est la commauté française de référence pour toutes les calculatrices Casio. Apprenez à utiliser votre machine, téléchargez et partagez des programmes, ou initiez-vous à l'informatique sur le forum. Ou bien venez développer des jeux avec nous pour passer le temps !

Événements en cours

Événements à venir

  • Du 1er au 31 Décembre : le Puzzle de l'Avent (Édition 2018)
  • Du 13 au 18 Janvier : 1k Basic Casio Gam Jam #2 (1ère édition)
  • Du 27 Janvier au 2 Février : semaine de test de programmes (1ère édition)

Actualités

Confirmation du mode examen au Bac 2020


Après plusieurs années de délais, le mode examen sera appliqué dès cette année pour les épreuves du Bac 2020 et les épreuves d'E3C du Bac 2021 de Première.

Les nouvelles directives considèrent les calculatrices graphiques en mode examen comme étant équivalentes à des calculatrices collège. Ces deux types seront les seuls autorisés aux épreuves d'après les derniers textes publiés :

La mission de pilotage des examens a écrit :

Je vous informe qu’il a été décidé à partir de la prochaine session, d’appliquer la circulaire n°2015-178 du 1 octobre 2015 relative à l’utilisation des calculatrices aux examens et concours de l’enseignement et concours de l’enseignement scolaire. Cette réglementation s’applique aux épreuves communes de contrôle continu (E3C) ainsi qu’aux épreuves ponctuelles de tous les examens visés.

Par conséquent, les sujets d’examens et du concours général des métiers à compter de la session 2020 pour lesquels la calculatrice est autorisée devront comporter sur la page de garde la mention suivante :

« L'usage de calculatrice avec mode examen actif est autorisé.
L'usage de calculatrice sans mémoire « type collège » est autorisé.».

Cette décision s’applique à toutes les épreuves (ponctuelles terminales, épreuves communes de contrôle continu, contrôle en cours de formation).

Reste à savoir quels sujets autoriseront les calculatrices et quels sujets les interdiront purement et simplement.

Pour rappel, le mode examen bloque tous les contenus ajoutés dans la calculatrices : programmes, e-acts, applications ajoutées... sur les calculatrices Casio, il vide purement et simplement la mémoire avant de démarrer l'examen.

Vous devrez donc absolument disposer d'une calculatrice avec mode examen ou d'une calculatrice collège pour passer les épreuves du Bac de cette année.

Quelques sources ou références (non exhaustif):
http://www.neoprofs.org/t113536p525-calculatrices-mode-examen-mesure-reportee-a-apres-2018#4811862
https://tiplanet.org/forum/viewtopic.php?f=49&t=23160
https://twitter.com/VPantaloni/status/1197494236905648128
https://twitter.com/LC_Paris11/status/1197495242641100801

Commentez cette news ! (15)

Publié par Lephenixnoir le

Voir toutes les news


Une bibliothèque graphique Python pour Graph 35+E II et Graph 90+E




Casio vient d'annoncer un futur module graphique Python pour Avril 2020. Ce modèle fonctionnera sur Graph 35+E II et Graph 90+E et semble orienté vers le tracé de graphes.


Ça ressemble pas mal au mode graphe du Basic avec une zone de tracé certainement en coordonnées cartésiennes (et non en coordonnées) d'écran.

On remarque quand même sur la première image que le tracé des lignes est libre, au lieu d'être limité par les formules de fonctions, ce qui devrait permettre de faire des diagrammes en tous genres et certainement du Super DrawStat sur Graph 35+E II. Sur la Graph 90+E, il faudra s'assurer d'abord que l'épaisseur des lignes s'y prête.

D'après les images promotionnelles, on doit également pouvoir tracer des flèches et des rectangles, des primitives qui n'existaient pas en Basic et qui pourraient bien nous simplifier le travail.

La couleur du texte des axes semble personnalisable, donc avec un peu de chances on pourra peut-être les retirer entièrement, et se configurer un ViewWindow permettant d'accéder à l'écran au pixel, comme en Basic.

On note enfin que le mode 8 couleurs de l'écran semble être utilisé, ce qui nous limite à ces couleurs extrêmes pas idéales pour les jeux.

On fera des tests dès que le module sera disponible, à la fois en termes de fonctionnalités et de performance, pour explorer les applications possibles.

À bientôt sur Planète Casio !

Commentez cette news ! (4)

Publié par Lephenixnoir le

Voir toutes les news


Résultat du concours de rentrée 2019 - Épreuve de Python !


Bonsoir à tous ! Ce soir on passe en revue les participations en méthodes à l'épreuve Python de notre concours de rentrée.

L'épreuve de Python consistait à construire une équipe de Pokémon avec la force de frappe maximale, capable de couvrir tous les types et toutes les techniques.


On va voir dès maintenant vos équipes ! Pour les lots, ce sera à la fin de l'article.


Le classement

Le nombre de participations a atteint un record de 183 envois pour 27 personnes, sur toutes les plateformes, avec des techniques variées qui ont semble-t-il toutes ou presque abouties au résultat optimal.

24. On commence doucement avec grandben49 qui nous présente son équipe de 10 Pokémons. Pensant qu'il faut du piquant pour avancer, il en confie la gestion à Dardagnan. Cette équipe bien échelonnée totalise 43.4213 points.


Dardagnan 15.05 % Reptincel 13.98 % Akwakwak 13.98 % Colossinge 10.75 % Chetiflor 10.75 % Sablaireau 9.68 % Salamèche 8.6 % Miaouss 7.53 % Grotadmorv 5.38 % Tentacool 4.3 %

23. Passé maître au jeu pierre-parier-ciseaux, thecamouflage a constitué une équipe similaire mais en nommant à sa tête Gravalanch et en le faisant seconder en prime par Racaillou. Ces ajouts de poids lui permettent d'atteindre 44.4569 points.


Gravalanch 18.28 % Racaillou 16.13 % Tentacruel 15.05 % Tentacool 12.9 % Empiflor 10.75 % Boustiflor 8.6 % Chetiflor 7.53 % Mackogneur 5.38 % Machopeur 3.23 % Machoc 2.15 %

22. Rémi G. procède de même mais motive son équipe en la confiant à l'infatigable Tartard. Et ça marche, avec maintenant 46.3762 points.


Tartard 18.28 % Abo 16.13 % Roucool 15.05 % Dodrio 12.9 % Parasect 10.75 % Mystherbe 8.6 % Reptincel 7.53 % Tentacool 5.38 % Florizarre 3.23 % Abra 2.15 %

21. Nous arrivons maintenant à KikooDX, présent à la fois sur TI-Planet et sur Planète Casio. Croyant en l'intelligence collective il nomme non pas un mais quatre chefs pour conduire son équipe au combat, et comme tout bon dresseur Pokémon il choisit bien évidemment des chefs de types tous différents : Florizarre, Rattatac, Abra et Tentacool. Une stratégie qui rapporte 46.6735 points.

KikooDX a écrit :
Autant que j'explique ce que j'ai fait pour obtenir mon score terrible
J'ai fait une boucle tirant 10 Pokémons aléatoires et les assignant à l'équipe.
J'ai laissé tourner le script deux semaines sur mon RPi, j'ai vu que les résultats n'étaient pas terribles (mon max. était un peu plus de 47) et j'ai arrêté.
En gros j'ai tenté la méthode facile, faire un script non optimisé avec une méthode bancale, et ça n'a pas marché
(Et heureusement.)
(message original)


Florizarre 16.13 % Rattatac 16.13 % Abra 16.13 % Tentacool 16.13 % Kokiyas 12.9 % Parasect 7.53 % Colossinge 6.45 % Tartard 4.3 % Caninos 3.23 % Rapasdepic 1.08 %

20. Ekter en ce qui le concerne croit aux vertus de l'égalité. Dans l'équipe à coloration végétale qu'il t'a constituée, aucun Pokémon n'a plus de pouvoir qu'un autre. Et effectivement ces nobles intentions lui permettent de s'inscrire au classement avec 47.1412 points.


Florizarre 10 % Reptincel 10 % Roucool 10 % Mystherbe 10 % Parasect 10 % Abra 10 % Chetiflor 10 % Empiflor 10 % Tentacool 10 % Dodrio 10 %

19. Ti64CLi++, actif sur TI-Planet et sur Planète Casio, nous sort pour sa part une équipe bicéphale avec Abra et Tentacool, bien évidemment de types différents. Il récolte ainsi 47.6148 points.


Abra 16.67 % Tentacool 16.67 % Florizarre 12.22 % Tadmorv 7.78 % Tartard 7.78 % Parasect 7.78 % Reptincel 7.78 % Chetiflor 7.78 % Dodrio 7.78 % Mystherbe 7.78 %

18. Krevo_ participant lui aussi à TI-Planet et à Planète Casio nous met également Abra à la tête de son équipe mais fortement secondé de Florizarre, là encore deux chefs de types différents. Un duo visiblement gagnant puisque cela lui permet de se hisser à 48.1623 points.


Abra 32.26 % Florizarre 29.03 % Mystherbe 7.53 % Empiflor 7.53 % Tentacool 7.53 % Reptincel 3.23 % Tartard 3.23 % Mackogneur 3.23 % Dodrio 3.23 % Tadmorv 3.23 %

17. Renaud42 donne cette fois-ci une puissance écrasante à Abra, tout en le faisant assister par Tentacool, qui commande lui-même à un trio de chefs intermédiaires Reptincel-Roucool-Chetiflor, que des types différents. Ces grandes compétences en dessage de Pokémon lui permettent ainsi de monter à 48.9534 points.


Abra 64.52 % Tentacool 12.9 % Reptincel 4.3 % Roucool 4.3 % Chetiflor 4.3 % Florizarre 2.15 % Nidorino 2.15 % Grodoudou 2.15 % Tropikeur 2.15 % Empiflor 1.08 %

16. Avec Filoji il n'y a plus que deux Pokémons supérieurs aux autres, Abra secondé par Tentacool. La disparition des échelons intermédiaires est visiblement payante avec 49.2890 points.


Abra 71.74 % Tentacool 19.57 % Florizarre 1.09 % Reptincel 1.09 % Mystherbe 1.09 % Parasect 1.09 % Tartard 1.09 % Chetiflor 1.09 % Dodrio 1.09 % Tadmorv 1.09 %

15. Captainluigi nous remet le même duo Abra-Tentacool. Parmi le reste des troufions, il nous fait évoluer Chetiflor en Empiflor tout en nous rajoutant Rattatac et Roucool. Des ajustements lui permetant d'atteindre 49.2930 points.

Captainluigi a écrit :
Voici ma technique assez simple :
1- Tout d'abord j'ai lancé des boucles pour tester toutes les possibilités possibles , et j'ai obtenu environ 46 .
2- J'ai lancée des boucles pour déterminer à partir du score des 46 la meilleure combinaison possible de caractères , et au final j'ai donc obtenu 49.29 ...
(message original)


Abra 70.97 % Tentacool 20.43 % Florizarre 1.08 % Reptincel 1.08 % Roucool 1.08 % Rattatac 1.08 % Mystherbe 1.08 % Parasect 1.08 % Tartard 1.08 % Empiflor 1.08 %

14. edgar13 nous propose sa propre version de l'équipe gagnante Abra-Tentacool. Chez les simples soldats nous avons donc cette fois-ci à la fois Chetiflor et Empiflor cette fois-ci, ainsi que le retour de Dodrio. 49.3089 points.

edgar13 a écrit :
Vous vous demandez comment j'ai fait 14. ? Tant mieux.

Tout d'abord j'ai commencé en classant les pokémons "a la main" puis ayant fait le classement je leur ai attribué les meilleurs points d’attaque possibles toujours "a la main". Ça m'a bien pris 4h.
Mais j'ai fait un premier score de 49 et quelques. Pourquoi j'ai fait tout ça à la main ? Parce que je ne savais pas trop comment faire un brute force approprié. Mais finalement mon frère qui a un Asus 7 en a fait un mais il n'a pas pu tourner longtemps car il en avais besoin.
J'ai un peu amélioré son score en faisant quelques boucles python et j'ai obtenu 49,308.
Par contre je n'ai plus le code.
(message original)


Abra 72.04 % Tentacool 19.35 % Florizarre 1.08 % Roucool 1.08 % Triopikeur 1.08 % Mystherbe 1.08 % Tartard 1.08 % Chetiflor 1.08 % Empiflor 1.08 % Dodrio 1.08 %

13. Voici maintenant venir Cyril S. qui a cherché sur HP Prime et nous propose sa déclinaison de l'équipe Abra-Tentacool, nous rajoutant Reptincel et Parasect parmi les autres. On progresse à 49.3101 points.


Abra 73.12 % Tentacool 18.28 % Florizarre 1.08 % Reptincel 1.08 % Roucool 1.08 % Mystherbe 1.08 % Parasect 1.08 % Tartard 1.08 % Empiflor 1.08 % Dodrio 1.08 %

12. Disperseur nous reprend le couple Abra-Tentacool. Mais cette fois-ci, il nous accompagne les autres d'un Dodrio. 49.3139 points.

Disperseur a écrit :
Voici donc une petite explication de la technique que j'ai employée pour obtenir mon score.

Face à la fonction pk() dont le code m'as un peu effrayé, j'ai choisi de ne pas essayer de le comprendre et de l'utiliser tel quelle. Tout d'abord j'ai créé une fonction qui prenait en entrée la liste des Pokémons déjà ajoutés et qui me donnait le Pokémon suivant pour obtenir le meilleur score. Cette fonction testait tout simplement un à un en ajoutant, enregistrant leur score puis retirant tous les Pokémons (les 94). Néanmoins cette fonction n’agissait pas sur les compétences des Pokémons et n’obtenait pas le meilleur score. J'ai ensuite créé une autre fonction pour exploiter la précédente, qui me donnait la meilleure main à partir d'un Pokémon de 'base' que je lui donnais. Par la suite j'ai retiré ce paramètre et j'ai obtenu LA meilleure main de 10 Pokémons sans modifier leurs compétences. N'obtenant ainsi qu'un score autour de 47, j'ai décidé de jouer à la main sur les compétences de chacun de mes 10 Pokémons. Donc en partant du premier, je tentais de modifier ces compétences en augmentant le paramètre concerné dans la fonction pk(). Si je voyais mon score diminuer, alors je revenais sur la meilleure valeur. Et ainsi de suite pour les 10. Ensuite j'ai tenté de remplacer les Pokémons n'ayant pas subi de modification de compétences par d'autres plus performants, en utilisant toujours ma première fonction (suppression du Pokémon à remplacer, appel de la fonction avec la liste des 9 autres Pokémons et obtention du meilleur Pokémon à mettre à la place). Ainsi j'ai obtenu, en affinant la technique et en testant plusieurs configurations, un score d'environ 49,301...

Je suis désolé, j'aurais bien voulu vous partager le code de cette fonction, mais en rédigeant ce message et en la cherchant, je me suis rendu compte que je l'avait supprimée

Là-dessus, je tiens à féliciter les premiers de ce classement et à leur dire que je suis toujours dans la course
(message original)


Abra 72.83 % Tentacool 18.48 % Florizarre 1.09 % Roucool 1.09 % Mystherbe 1.09 % Parasect 1.09 % Triopikeur 1.09 % Tartard 1.09 % Empiflor 1.09 % Dodrio 1.09 %

11. Amiga68000 nous ressort la même équipe, mais avec un Abra un peu plus puissant au détriment de son lieutenant Tentacool. Les autres sont également moins bien dotés avec 1,08% de puissance chacun. 49.3142 points.

Amiga68000 a écrit :
Bravo pour vos algos de code génétique, c'est vraiment très intéressant, va falloir que je creuse cette technique. Bravo et merci pour le concours j'ai appris beaucoup. A la fois sur python, les algos (que je tenterai de creuser à tête reposée).

Voici ma méthode, un peu plus classique ou du moins à l'ancienne. J'ai essayé plein de trucs, dans différentes voies. J'ai essayé de vous les synthétiser par étapes.

Brute force :
J'ai commencé par du bruteforce en tirant aléatoirement des lots de 10 individus et des priorités aléatoires. Score 46 pas plus !

Jauger les Pokémon :
Un peu moins bourrin, j'ai jaugé chaque Pokémon un à un. Ça m'a permis de les classer.

Comprendre l'algo :

Comprendre le code et l'algo, j'en ai fait un Excel.
Dans la colonne Y, vous rentrez votre priorité d'attaque en face du Pokémon choisi. En cellule Y2 vous récupérez le score.
/!\ le score est l'ancienne évaluation.
Pour l'excel, il a fallu que je cartographgie mes Pokémons. C'est là que j'ai compris que :
- la somme des priorités devait être inférieure à 187
- l'enregistrement d'une priorité devait se faire de la plus petite valeur vers la plus grande sinon par enchantement des individus disparaissaient de votre lot de Pokémon.

def cartographie():
  priorite=9
  global pkcarto
  pkcarto=[]
  lgn=["ID", "Points", "nb de X", "valeurs"]
  #pkcarto.append(lgn)
  for i in range(1,95):
    pk(i,priorite)
#    pkcarto.append(pkt)
    t=""
    for j in  range(len(pkt)):
      t+=str(int(pkt[j]))
      if j!=len(pkt)-1:
        t+=","
    print("signature.append(["+str(t)+"]) #"+str(i))
    pk(i,0)
  return

Classer les Pokémon, méthode 2 :
J'ai vu que 2 Pokémons 63 et 72 sortaient du lot. J'ai alors fait 100.000 tirages de 10 Pokémons avec les 63 et 72 avec priorité 1. A chaque fois je relevais le score pour l'ajouter à la moyenne de chaque Pokémon contenu dans le tirage. But : les classer.

Varier les priorités :
En prenant les Pokémons avec les meilleurs résultats, j'ai fait varier toutes les priorités. Je suis arrivé à un très bon résultat (3. je crois), malheureusement la combinaison était déjà prise, il a fallu que je réduise mes priorités pour arriver sur une combinaison et un score vierge. C'est là où j'ai eu mon classement

Combinaisons :
En prenant les meilleurs Pokémons de l'étape 4, (30 environ, je ne me souviens plus du chiffre exact), j'ai fait toutes les combinaisons possibles par récursivité. Ça n'a pas amélioré mon score. Autre chose, je ne me suis pas penché sur la cas de la correction de score routine setst pour mieux comprendre les différences de score.
Voilà mes étapes à peu près dans l'ordre, j'ai fait plein de petites routines pour celà Voici ci-dessous mon code global, n'hésitez pas à me faire vos remarques, je suis pas un pro de la prog. Bonne lecture ;-)
Si vous avez besoin de plus d'explication je suis dispo.

#cas
import time

signature=[]
signature.append([1,1,1,1,0,0,0,1,1,1,0,1,0,1,0,1,1,0,1,0,0]) #1
signature.append([1,0,0,1,1,1,0,1,1,1,0,1,1,0,1,0,0,1,0,0,0]) #2
signature.append([0,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,0,1]) #3
signature.append([1,1,0,1,0,1,1,0,1,1,0,1,1,0,0,0,0,0,0,1,0]) #4
signature.append([0,1,0,1,1,0,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1]) #5
signature.append([1,0,0,0,1,1,1,0,1,1,1,1,0,1,1,0,1,0,0,1,0]) #6
signature.append([0,0,0,1,0,0,1,1,1,1,0,0,0,1,0,1,1,1,0,0,1]) #7
signature.append([0,1,0,1,1,0,0,0,1,0,0,0,0,0,1,1,1,0,1,0,0]) #8
signature.append([0,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,0,1,0]) #9
signature.append([1,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,1,0,1,0,1]) #10
signature.append([1,1,1,0,0,0,0,0,0,1,1,0,0,1,1,1,1,0,0,0,0]) #11
signature.append([0,1,0,1,1,0,0,0,1,1,0,1,0,0,0,0,1,0,1,0,0]) #12
signature.append([0,1,1,0,1,0,0,0,1,1,0,0,1,0,0,0,0,0,1,1,1]) #13
signature.append([1,0,0,0,0,1,1,0,1,0,1,0,0,1,1,1,0,0,0,1,0]) #14
signature.append([1,0,1,1,1,1,0,1,1,0,0,0,1,0,0,0,1,1,0,1,0]) #15
signature.append([1,1,0,0,0,1,1,1,1,0,1,1,1,0,1,0,1,0,0,1,1]) #16
signature.append([1,1,0,1,0,0,1,1,0,0,1,1,0,1,0,1,0,1,0,0,0]) #17
signature.append([1,0,0,0,0,0,0,0,1,1,1,0,1,0,0,0,0,1,1,1,1]) #18
signature.append([0,1,0,1,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1]) #19
signature.append([1,1,1,0,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,0]) #20
signature.append([0,1,1,0,0,1,1,1,0,0,0,0,1,0,0,0,1,1,1,0,1]) #21
signature.append([0,1,0,1,1,1,1,0,1,1,0,0,0,1,0,1,0,1,1,0,1]) #22
signature.append([0,1,0,1,1,1,1,1,0,1,1,1,0,0,1,1,0,1,1,0,0]) #23
signature.append([1,1,0,0,1,0,0,1,0,1,0,0,0,0,1,0,0,1,1,1,1]) #24
signature.append([1,0,0,1,0,0,1,0,0,0,1,0,0,1,1,1,0,0,1,0,0]) #25
signature.append([1,0,0,0,1,0,0,1,1,1,0,1,1,1,0,0,1,1,1,0,0]) #26
signature.append([0,0,0,1,1,1,0,0,1,0,1,0,0,1,1,1,1,1,1,0,1]) #27
signature.append([0,1,0,0,0,1,1,0,0,0,1,1,1,0,0,1,1,0,0,1,0]) #28
signature.append([0,0,1,0,0,0,1,0,1,1,0,0,0,0,1,1,1,0,0,1,1]) #29
signature.append([1,0,0,0,0,0,1,0,1,0,0,0,0,0,0,1,0,1,0,0,0]) #30
signature.append([1,0,1,0,1,0,0,0,0,0,0,0,0,1,0,1,1,1,0,0,1]) #31
signature.append([0,0,1,1,1,0,1,1,1,0,0,0,0,0,0,1,0,1,0,0,1]) #32
signature.append([1,1,1,1,1,0,1,0,0,1,0,0,1,0,1,0,1,1,0,1,0]) #33
signature.append([0,1,0,0,1,1,0,0,0,0,1,1,1,0,0,0,1,0,1,1,0]) #34
signature.append([1,1,1,0,1,1,0,1,0,1,0,0,1,0,1,0,0,1,1,0,1]) #35
signature.append([0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,0,0,1]) #36
signature.append([1,0,0,0,0,0,1,0,0,0,0,1,1,1,1,0,0,1,1,0,1]) #37
signature.append([1,1,1,0,0,1,1,1,1,0,1,0,0,1,0,0,1,0,0,0,1]) #38
signature.append([0,1,0,0,0,1,0,1,1,0,0,1,0,0,0,1,1,1,1,1,0]) #39
signature.append([1,0,0,0,0,1,0,1,1,1,1,1,1,1,0,1,0,0,1,0,1]) #40
signature.append([0,1,0,1,0,0,0,0,0,1,0,1,1,1,0,1,0,0,0,0,1]) #41
signature.append([1,0,0,1,0,1,1,0,0,1,1,0,1,1,0,1,1,0,1,0,0]) #42
signature.append([1,1,1,1,0,1,1,1,0,0,1,1,1,1,1,0,0,1,0,1,0]) #43
signature.append([0,1,1,1,1,1,1,1,0,0,0,1,1,0,1,0,0,0,0,0,1]) #44
signature.append([0,1,1,1,0,1,1,1,1,0,0,0,0,1,1,0,0,1,0,0,0]) #45
signature.append([0,1,0,0,1,0,0,0,0,1,0,0,1,0,0,0,1,1,0,1,0]) #46
signature.append([0,0,1,0,1,1,1,0,0,1,1,1,1,1,1,0,1,1,1,1,0]) #47
signature.append([0,0,0,0,0,1,1,0,0,1,0,1,1,1,0,1,0,1,1,0,1]) #48
signature.append([1,0,1,0,0,0,1,1,0,0,0,0,1,0,1,1,1,0,1,0,0]) #49
signature.append([1,1,0,1,1,1,1,0,1,0,0,1,0,0,0,0,1,0,1,1,0]) #50
signature.append([1,1,1,1,1,1,0,0,1,0,1,0,1,1,0,0,1,0,0,1,0]) #51
signature.append([1,0,0,0,1,1,0,1,1,0,1,1,1,1,1,0,0,1,1,0,0]) #52
signature.append([1,1,0,1,1,1,0,0,0,0,0,0,1,1,0,0,0,1,1,0,0]) #53
signature.append([0,0,0,1,1,0,1,0,1,0,1,0,1,0,0,1,0,0,0,1,0]) #54
signature.append([0,1,0,1,1,0,0,1,0,0,0,1,0,0,0,1,0,0,1,0,0]) #55
signature.append([1,0,1,1,0,1,0,1,1,1,1,0,1,1,1,0,0,0,1,0,0]) #56
signature.append([1,0,1,1,0,1,0,1,1,0,0,1,1,0,1,1,0,0,1,1,0]) #57
signature.append([1,1,0,1,0,1,1,1,0,1,0,1,1,0,0,0,1,1,1,0,0]) #58
signature.append([0,0,0,1,0,1,1,1,0,0,1,0,0,0,0,0,0,0,0,1,1]) #59
signature.append([1,0,0,1,0,0,0,0,1,1,1,1,1,1,0,0,0,1,0,1,0]) #60
signature.append([0,1,0,1,1,1,0,0,1,0,0,1,0,1,0,1,0,0,0,0,1]) #61
signature.append([1,1,1,0,0,1,0,1,1,0,0,1,0,1,1,1,1,0,1,0,1]) #62
signature.append([0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1]) #63
signature.append([0,0,1,0,0,1,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1]) #64
signature.append([0,1,1,0,0,1,1,0,0,0,0,0,0,1,1,0,0,1,1,1,1]) #65
signature.append([0,1,1,0,1,0,0,1,1,0,0,1,1,1,1,1,0,1,0,1,0]) #66
signature.append([1,1,0,0,0,1,1,1,0,0,0,0,1,1,0,1,1,1,1,0,0]) #67
signature.append([1,1,1,1,0,0,1,0,0,0,1,1,1,1,0,0,0,1,1,1,0]) #68
signature.append([0,1,1,0,1,1,1,0,1,1,0,1,1,0,0,1,1,0,0,1,1]) #69
signature.append([0,1,0,1,1,1,0,1,0,0,1,0,0,1,0,0,1,0,1,1,0]) #70
signature.append([1,1,0,0,0,1,0,1,1,1,1,1,0,1,1,1,1,0,1,0,0]) #71
signature.append([1,0,0,1,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1]) #72
signature.append([1,0,0,1,0,0,1,1,0,0,1,1,1,1,0,1,0,1,1,1,0]) #73
signature.append([1,0,0,0,1,1,1,0,1,1,1,0,0,0,0,0,0,0,1,1,0]) #74
signature.append([1,1,1,1,0,1,1,0,0,1,0,1,1,0,1,0,0,0,1,1,1]) #75
signature.append([1,0,1,1,0,1,0,1,0,1,1,1,0,0,1,0,1,0,1,0,1]) #76
signature.append([1,1,0,0,1,0,0,0,0,1,0,0,0,1,1,0,0,0,0,0,0]) #77
signature.append([1,0,0,1,0,0,0,1,0,1,0,0,1,0,0,1,0,1,1,0,0]) #78
signature.append([1,1,0,0,1,1,1,1,0,0,0,0,0,1,0,1,0,1,1,1,1]) #79
signature.append([0,0,0,0,0,0,1,1,0,1,1,0,0,0,0,1,0,0,0,1,1]) #80
signature.append([0,1,0,0,1,1,0,1,1,0,0,1,1,0,1,1,0,1,1,0,1]) #81
signature.append([0,1,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0,1,1,1,0]) #82
signature.append([0,1,1,1,0,1,0,0,1,0,1,1,1,1,0,1,0,1,0,0,0]) #83
signature.append([1,1,1,0,1,0,0,0,1,1,0,0,1,0,1,0,0,1,0,0,1]) #84
signature.append([1,0,0,1,1,1,1,1,1,1,1,0,0,1,1,1,0,0,1,1,0]) #85
signature.append([0,0,0,1,1,1,0,1,1,1,1,0,0,1,1,0,1,0,0,0,1]) #86
signature.append([1,1,1,0,0,0,0,1,1,0,1,1,1,0,0,1,0,0,0,0,1]) #87
signature.append([1,1,1,0,1,0,0,0,1,1,1,0,0,1,1,1,1,0,1,0,1]) #88
signature.append([0,1,0,1,0,1,0,0,1,1,1,0,1,0,1,1,0,1,1,0,1]) #89
signature.append([1,0,0,0,0,0,1,1,1,0,0,1,1,0,1,1,1,1,1,0,0]) #90
signature.append([0,1,0,1,0,0,0,0,0,1,0,0,0,0,1,0,1,0,0,1,0]) #91
signature.append([0,0,0,1,1,0,1,0,1,1,1,0,1,0,1,1,0,1,1,1,0]) #92
signature.append([1,0,0,1,0,1,0,0,1,1,0,0,0,0,0,0,0,0,1,1,1]) #93
signature.append([0,0,0,1,1,0,1,0,1,0,1,1,1,0,0,1,1,1,0,0,1]) #94

"""
Tente d'être le meilleur le meilleur de tous les dresseurs
en relevant notre défi.

Ton but est simple, tu dois te constituer la main Pokémon
la plus puissante possible sachant que bien évidemment les Pokémons
ont des compétences différentes, et ce sous les seules règles suivantes :

    seuls les Pokémon
    n°1 à 94 sont autorisés
    ta main ne peut contenir qu'un maximum de 10 Pokémons
    tous les Pokémons
    dans ta main doivent être différents


Pour cela, un script Python va offrir à ta calculatrice
la fonction pk(n,p) pour ajouter un Pokémon à ta main, avec :

    n, le numéro de Pokémon
    de 1 à 94
    p, la priorité d'attaque que tu souhaites donner au Pokémon
    en question (1 par défaut)

Cas particuliers; si le Pokémon est déjà dans ta main sa priorité d'attaque sera mise à jour;
et p=0 retire le Pokémon de ta main.
"""
from math import *

def mmod(a,b):
    #modulo a b
  return a%b
#0 Nspire MicroPython
#1 NumWorks Python
#2 G90/35+E2 Python
#3 G75/85/95 CasioPython
#4 83PCE Python/PyAdapt
#5 HP Prime CAS
#6 G90/35+E2 KhiCAS

def getplatform():
  k=-1
  try:
    if chr(256)==chr(0):
      k=[6,5][("HP" in version())>0]
  except:
    pass
  if k>=0:
    return k
  try:
    import sys
    try:
      if sys.platform=="nspire":
        k=0
      elif sys.platform.startswith("TI-Python"):
        k=4
    except:
      k=3
  except:
    try:
      import kandinsky
      k=1
    except:
      k=2
  return k

def getlinechars(o=False):
#  c,k=2**31-1,getplatform()
  c=2**31-1
  k=getplatform() #=-1 sur PC

  if k>=0:
    c=[53,o and 99 or 29,o and 509 or 21,31,32,c,c][k]
  return c

lnm=["Bulbizarre","Herbizarre","Florizarre","Salameche","Reptincel","Dracaufeu","Carapuce","Carabaffe","Tortank","Chenipan","Chrysacier","Papilusion","Aspicot","Coconfort","Dardargnan","Roucool","Roucoups","Roucarnage","Rattata","Rattatac","Piafabec"]
lnm.extend(["Rapasdepic","Abo","Arbok","Pikachu","Raichu","Sabelette","Sablaireau","Nidoran F","Nidorina","Nidoqueen","Nidoran M","Nidorino","Nidoking","Melofee","Melodelfe","Goupix","Feunard","Rondoudou","Grodoudou","Nosferapti","Nosferalto"])
lnm.extend(["Mystherbe","Ortide","Rafflesia","Paras","Parasect","Mimitoss","Aeromite","Taupiqueur","Triopikeur","Miaouss","Persian","Psykokwak","Akwakwak","Ferosinge","Colossinge","Caninos","Arcanin","Ptitard","Tetarte","Tartard","Abra","Kadabra"])
lnm.extend(["Alakazam","Machoc","Machopeur","Mackogneur","Chetiflor","Boustiflor","Empiflor","Tentacool","Tentacruel","Racaillou","Gravalanch","Grolem","Ponyta","Galopa","Ramoloss","Flagadoss","Magneti","Magneton","Canarticho","Doduo","Dodrio","Otaria"])
lnm.extend(["Lamantine","Tadmorv","Grotadmorv","Kokiyas","Crustabri","Fantominus","Spectrum","Ectoplasma"])




#na,pkl=21,[]
na=21
pkl=[]
#mrandmax,mrand,mfmax,nn,mp=2**31-1,0,93,getlinechars(True)-na,na//2
mrandmax=2**31-1
mrand=0
mfmax=93
nn=getlinechars(True)-na
mp=na//2 #quotien de la division entière, 21//2 = 10

def mround(f):
  #renvoie l'entier le plus proche
  # 0.5 -->  1
  # 0.4 -->  0
  #-0.4 -->  0
  #-1.4 --> -1
  #-1.5 --> -2
  #-1.6 --> -2
  d=mmod(abs(f),1) #resultat = 0.xxxxx
  return (mfloor(abs(f))+(d>=.5))*(1-2*(f<0))

def mfloor(f):
  #Arrondi -mfloor(-5.2)=-5
  return round(f)-(round(f)>f)

def mceil(f):
  #arrondi SUP
  return round(f)+(round(f)<f)

def mseed(s):
  global mrand
  mrand=mmod(s,mrandmax)

def mrandom():
  mseed(mrand*16807)
  return float(mrand/mrandmax)

def muniform(mini,maxi):
  return mrandom()*(maxi-mini)+mini

def mrandint(mini,maxi):
  return mround(muniform(mceil(mini),mfloor(maxi)))


def mf2f(n):
  return float(n/mfmax) #mfmax=93

def mbit(a,b):
  return mmod((a//(2**b)),2)


def getattack(p,pts):
  #p=numéro de l'individu
  #pts=l[2]/somme(l[2])
  global pkt
#  mseed(42) #mrand=42
#  print(str(pts))
#  for k in range(p+1):
#    mrandom() #génère p+1 fois mrand
#  a,pka=mrandint(1,mrandmax),""
#  a=mrandint(1,mrandmax)
  pka=""
  npka=0
#  print("p="+str(p))
#  print(signature[p])
  for j in range(na): #na=21
#    if mbit(a,j)!=0:
    if signature[p][j]==1:
      pka+="X"
      npka+=1
      pkt[j]+=pts
    else:
      pka+=" -"[getplatform()>=5]

#  print("pka="+pka)

  return pka


def i2c(k):
  return chr(k+33)
def c2i(c):
  return ord(c)-33



def f2mf(f):
  return mround(float(f*mfmax)) #mfmax=93

def clean():

  #recalcule tous les l[2] des individus
  global pkl #données des individus
#  t,s=0,0
  s=0
  t=0

  for l in pkl:
    #t=somme(priorités)
    t+=l[1] #t=t+l[1]
#  print("t="+str(t))

  for l in pkl:
    l[2]=f2mf(l[1]/(t or 1)) #t or 1 pour eviter la division par 0

#    l[2]=mround(float(l[1]/(t or 1)*93)) #mround = entier le plus proche


    s+=l[2] #s=s+l[2] --> s= sommes des l[2]
    if(l[2]<=0):
#      print("-----")
#      print("t="+str(t))
#      print("remove "+str(l))
      pkl.remove(l) #on enlève l'individu
      return clean() #on reitère
  return s #on renvoie


def pk_ORIGINE(n,p=1,d=2):
  global pkt, pkl
  n-=1
  if n>=0 and n<len(lnm):
    new=True
    for k in range(len(pkl)):
      if pkl[k][0]==n:
        new,pkl[k][1]=False,max(p,0)
    if new and len(pkl)<mp:
      pkl.append([n,max(p,0),0])
  ptt,pkt,t,st=clean(),[0 for k in range(na)],0,""
  for l in pkl:
    s=getattack(l[0],l[2]/ptt)
    if d:
      sn=" "+lnm[l[0]]
      if len(sn)>nn:
        sn=sn[:nn]
      print(s+sn+" #"+str(l[0]+1)+" (f="+str(l[1])+")")
    st=i2c(l[0])+st+i2c(l[2])
  for k in pkt:
    if(k):
      t+=log(e+k*len(pkl))
  if(d):
    if(d>=2):
      print("Bon score ? Si oui envoie code suivant a info@tiplanet.org :")
    print(""+st)
  return float(t)



def pk(n,p=1,d=2):
  global pkt,pkl
  global sign

  #on décrémente de 1, la liste commence à 0
  n-=1
  if n>=0 and n<len(lnm):
    #le n° correspond à un individu
    new=True

    for k in range(len(pkl)):
      if pkl[k][0]==n:
        #individu existant, on remplace sa priorité
        new=False
        pkl[k][1]=max(p,0) #nouvelle priorité

    if new and len(pkl)<mp:
      #nouvel individu et poignée de 10 non pleine
      pkl.append([n,max(p,0),0]) #ajout de l'individu


  #calcul des attaques

  #  ptt,pkt,t,st=clean(),[0 for k in range(na)],0,""
  ptt=clean() #recalcule les l[2] et renvoie la somme des l[2]
  pkt=[0 for k in range(na)] # [0 0 ...  0 0 0]
  t=0
  st=""


  for l in pkl:
    s=getattack(l[0],l[2]/ptt) #maximiser l[2]/ppt
    if d:
      sn=" "+lnm[l[0]]
      if len(sn)>nn:
        sn=sn[:nn]

    st=i2c(l[0])+st+i2c(l[2])

  for k in pkt:
    if(k): #k<>0

      t+=log(e+k*len(pkl))  #LN log neperien
#      print(t,e,k,len(pkl))
#  if(d):
#    print(""+st)

  sign=""+st

  return float(t)





def setst(st):
  s,pkl[:],n=0,[],len(st)//2
  for k in range(n):
    s=pk_ORIGINE(c2i(st[n-1-k])+1,c2i(st[n+k+len(st)%2]),k+1>=n)
  return s


#print("pk(n,p) pour rajouter le Pokemon n a ta main avec p points d'attaque.")



#      print(s+sn+" #"+str(l[0]+1)+" (f="+str(l[1])+")")



#
#
#
# ICI CODE PERSO
#
#
#





import csv
from random import randint


"""
        if len(pkl)>9:
            numPkARetirer=pkl[randint(0,len(pkl)-1)]][0]
            pk(numPkARetirer,0)
"""

#ALGO de recherche
def affListe(listepkl):
    for k in listepkl:
        print(lnm[k[0]]+" #"+str(k[0]+1)+" (f="+str(k[1])+")" )



def brutforce():
    global pkl
    global pklMAX
    global scoreMax
    global score

    #construction d'une liste de 10
    for i in range(20):
        numPk=randint(1,94)
        force=randint(1,10)
        score=pk(numPk,force)
    scoreMax=score
    print("===== Liste depart")
    pkl=[[25, 1, 0], [81,1, 0], [46,1, 0], [19, 1, 0], [49, 1, 0], [50, 1, 0], [66, 1, 0], [34, 1, 0], [71, 35, 0], [62, 143, 0]]

    pklMAX=list(pkl)
    affListe(pklMAX)

    #bouclage pour trouver meilleur score
    for i in range(20000):

#        print("\n************** Iterration="+str(i))
        if i%1000==0:print(i)

#        n=len(pkl)-1
#        print(n)
#        if n==9:

        n=7 #onnenleve pas 72 ni 63
        numPkARetirer=pkl[randint(0,n)][0]+1

        #        print("----- supprimer "+str(numPkARetirer))
        pk(numPkARetirer,0)
#        affListe(pkl)

        while len(pkl)<10:
            numPk=72
            while numPk==72 or numPk==63:
              numPk=randint(1,94)
#            force=randint(1,10)
            force=1
#            print("+++++ Ajouter "+str(numPk))
            score=pk(numPk,force)
#            print("SCORE="+str(score))
#            affListe(pkl)

        if score>scoreMax:
            scoreMax=score
            pklMAX=list(pkl)
            print("\nMAX --------------------------------")
            print("score ="+str(scoreMax))
            affListe(pklMAX)
        else:
            pkl=list(pklMAX)

    return





def ScanStatPKi(numPkFixe):
    global pkl
    #on fixe 72 et 63
    #pour chaque PKi de 1 à 93
    #   on tire n combinaisons aléatoires,
    #   on note le score pour le PKi
    #à la fin on classe les PKi selon leur score

    print(numPkFixe)

    score=0
    scoreMax=0
    ctr=0

    #on remplace l'élément
    pkl[7][0]=numPkFixe-1

    #teste si numPkFixe est dans la plage pkl de 0 à 6
    for i in range(0,7):
      if pkl[i][0]+1==numPkFixe:
        boucler=True
        while boucler:
          n=randint(1,94)
          if n!=numPkFixe and n!=72 and n!=63:
            pkl[i][0]=n
            boucler=False

    boucle=2000

    #bouclage pour trouver meilleur score
    for i in range(boucle):
      #if i%1000==0:print(i)

      n=6 #onnenleve pas 72 ni 63, ni numPkFixe
      del pkl[0]


      boucler=True

      while boucler: #len(pkl)<10:
        numPk=randint(1,94)
        boucler=False
        for k in pkl:
          if k[0]+1==numPk:
            #il y a déjà un num
            boucler=True
      #on a un numéro
      pkunit=[]
      pkunit.append(numPk-1)
      pkunit.append(1)
      pkunit.append(1)
      pkl.insert(6,pkunit)

      score=pk(pkl[0][0]+1,1)
      scoreMax+=score

    score=scoreMax/boucle

    data=[]
    data.append(numPkFixe)
    data.append(score) #Score

    return data





def scanstat():
  global pkl
  start_time=time.time()
  pkl=[[25,1,0],[81,1,0],[46,1,0],[19,1,0],[49,1,0],[50,1,0],[66,1,0],[34,1,0],[71,35,0],[62,143,0]]

  d=[]
  for i in range(1,95): #range(1,95) --> 1 à 94
    if i!=72 and i!=63:
        d.append(ScanStatPKi(i))
  print("Temps d execution : "+str( (time.time() - start_time)))
  sauve(d)

  return d





#scanstat()







def init():

  pk(3)
  pk(43)
  pk(85)
  pk(75)
  pk(71)
  pk(62)
  pk(16)
  pk(6)


  pk(72,35)
  pk(63,143)

  return









def scoreprio(pk1,pk2):
  #max 186
  data=[]
  data.append(0)
  data.append(pk1)
  data.append(0)
  data.append(pk2)
  data.append(0)


  smax=0
  for p1 in range(1,177): #K186-8-1
    for p2 in range(1,178-p1):
      if p1<p2:
        pk(pk1,p1)
        s=pk(pk2,p2)
      else:
        pk(pk2,p2)
        s=pk(pk1,p1)
      if s>smax:
        smax=s
        data[0]=smax
        data[2]=p1
        data[4]=p2

#      pkl=[]
      pk(pk1,0)
      pk(pk2,0)

  return data


def duelprio():
  start_time=time.time()
  d=[]
  for i in range(1,94):
    for j in range(i,95):
      d.append(scoreprio(i,j))
      print("pk "+str(i)+" vs pk "+str(j))
      print("Temps d execution : "+str( (time.time() - start_time)))

  sauve(d)

# Affichage du temps d execution

  return d





def duel(numpk,r):
  #crée une ligne se scores du numpk vs chaque element dans r
  priorite=1
  pkduel=[]
  pk(numpk,priorite)
  for i in r:
      if numpk!=i:
          pkduel.append(pk(i,priorite))
          pk(i,0)
      else:
          pkduel.append(0)
  pk(numpk,0)
  return pkduel


def matriceduel():
    p=[]
    r=range(1,95)
    r=[16,23,62,69,71,75,88]
    r=range(1,4)
    r=range(1,95)

    for i in r:
        p.append(duel(i,r))
    return p


def cartographie():
  priorite=9
  global pkcarto
  pkcarto=[]
  lgn=["ID","Points","nb de X","valeurs"]
  #pkcarto.append(lgn)

  for i in range(1,95):
    pk(i,priorite)
#    pkcarto.append(pkt)
    t=""
    for j in  range(len(pkt)):
      t+=str(int(pkt[j]))
      if j!=len(pkt)-1:
        t+=","
    print("signature.append(["+str(t)+"]) #"+str(i))
    pk(i,0)

  return



def sauve(p):
  #sauvegarde une matrice p en csv
  #with open("L:/_Datas/11 - Arnaud/Python - DEFI/table.csv", "w") as f_write:
  with open("d:/table.csv", "w") as f_write:
      writer = csv.writer(f_write,delimiter=";")
      writer.writerows(p)
  return



def seek(id):

  smax=0

  for i in range(1,130):
    s=pk(id,i)

    if s>smax:
      smax=s
      priorite=i
  score=pk(id,priorite)
  print("pk("+str(id)+","+str(priorite)+")=" +str(score) )
  return score



def valeur(priorite=1):
  #renoie une liste de chaque score ID seul
  l=[]

  for i in range(1,95):
    s=pk(i,priorite)
    l.append(s)
    pk(i,0)
    print(s)

  return


def estdanspkl(ID):
  r=False
  for p in pkl:
    if p[0]+1==ID:
      r=True
      break
  return r



def meilleurID(IDaexclure=0):
  #renvoie le meilleur ID
  priorite=1
  IDmax=0
  smax=0

  if len(pkl)==10:
    IDmax=0
  else:

    for ID in range(1,95):
      if ID!=IDaexclure:
        if not(estdanspkl(ID)):
          #l'ID n'est pas dans la liste pkl
          s=pk(ID,priorite)
          if s>smax:
            #score meilleur
            smax=s
            IDmax=ID
          pk(ID,0)
  return IDmax




def creermeilleurID():
  ID=meilleurID()
  if ID!=0:
    pk(ID)
    seekall()
  return


def seekall():
  for p in pkl:
      score=seek(p[0]+1)
  return score



def scan():

  #max 186
  #186-8 = 178

  smax=0
  f63=94
  f72=0
  f03=0
  pk(63,f63)

  for i in range(1,178-1):
    for j in range(1,178-i):
#      for k in range(1,178-i-j):
      pk(3,i)
      s=pk(72,j)


      st=setst(""+sign)
      if st>smax:
        smax=st
#        f63=i
        f72=i
        f03=j
        print("MAX setst="+str(smax))
        print("S="+str(s))
#         print("Signature="+sign+" "+str(st))
        print(" P72="+str(i)+" P03="+str(j))

  pk(63,f63)
  pk(72,f72)
  pk(3,f03)

  return






def combi(level,levelmax,pkpossibles,smax=0,pkdeb=0):

  #on incrémente le niveau d'arbo
  l=level+1
#  print("l="+str(l))

  if l>levelmax:
    #on est arrivé en bas de l'arbo souhaitée
    #on peut faire les calculs
    s=seekall()
    print("s="+str(s))
    if s>smax:
        smax=s
        print("smax=",str(smax))
  else:

#    for i in pkpossibles:
    for ii in range(pkdeb,len(pkpossibles)):
      i=pkpossibles[ii]
#☺      if not(estdanspkl(i)):
      #l'ID n'est pas déjà dans la liste
#      print("id="+str(i))

      #on ajoute l'individu
      pk(i)

      #on descend en arbo
      smax=combi(l,levelmax,pkpossibles,smax,ii+1)

      pk(i,0) #on eneleve l'individu

  return smax


def trouvecombi():
  pkpossibles=[16,62,71,23,69,75,88]
  pkpossibles=[16,62,71,23,69]

  smax=combi(0,3,pkpossibles)
  return smax





#
#
# RESULTATS
#
#




def initamiga():
  #amiga68000
  #record à battre = 49,31730

  #49.31975298152274

  pk(3,1)
  pk(62,1)
  pk(71,1)
  pk(16,1)
  pk(43,1)
  pk(85,1)
  pk(47,1)
  pk(51,1)
  pk(72,32)
  pk(63,128)

  #la somme des priorités <=186
  return

"""
transmis le 14/10/19 via amiga68000

XXXXX XXXXXXXXX  X Florizarre
XXX  X XX  X XXXX X X Tartard
XX   X XXXXX XXXX X   Empiflor
XX   XXXX XXX X X  XX Roucool
XXXX XXX  XXXXX  X X  Mystherbe
X  XXXXXXXX  XXX  XX  Dodrio
  X XXX  XXXXXX XXXX  Parasect
XXXXXX  X X XX  X  X  Triopikeur
X  XXXX X XXXXX XXX X Tentacool
XXXX XXXXXXXXXX XXXX Abra
Bon score ? Si oui
envoie code suivant
a info@tiplanet.org :
_hSOuK0g^#""""""""3h
49.31975298152274
"""



def initk():
  #record à battre = 49,31730



  #49.32078546995182
  pk(3,1)

  pk(62,1)
  pk(71,1)
  pk(16,1)
  pk(43,1)

  pk(85,1)
  pk(47,1)
  pk(51,1)
  pk(72,35)
  pk(63,143)

  #la somme des priorités <=186

  return
"""

   XXXXX XXXXXXXXX  X Florizarre
XXX  X XX  X XXXX X X Tartard
XX   X XXXXX XXXX X   Empiflor
XX   XXXX XXX X X  XX Roucool
XXXX XXX  XXXXX  X X  Mystherbe
X  XXXXXXXX  XXX  XX  Dodrio
  X XXX  XXXXXX XXXX  Parasect
XXXXXX  X X XX  X  X  Triopikeur
X  XXXX X XXXXX XXX X Tentacool
XXXX XXXXXXXXXX XXXX Abra
Bon score ? Si oui
envoie code suivant
a info@tiplanet.org :
_hSOuK0g^#""""""""3i
49.32078546995182
"""



def init5():
  #record à battre = 49,31730

  #49.28269871690558
  pk(16,1)
  pk(51,1)
  pk(58,1)
  pk(62,1)
  pk(71,1)
  pk(76,1)
  pk(5,1)
  pk(6,1)
  pk(72,35)
  pk(63,143)

  return

def init4():
  #record à battre = 49,31730

  #49.138894711933105
  pk(85,1)
  pk(89,1)
  pk(69,1)
  pk(73,1)
  pk(90,1)
  pk(86,1)
  pk(88,1)
  pk(87,1)
  pk(72,35)
  pk(63,143)
  return


def init3():
  #record à battre = 49,31730

  #
  pk(63,64)

  pk(3,1)
  pk(72,16)

  pk(62,1)
  pk(71,1)
  pk(16,1)
  pk(43,1)

  #13 X
  pk(23,1)
  pk(16,1)
  pk(75,1)

  return

def init21():
  #record à battre = 49,31730

  #49.274636982498805
  pk(63,61) #56

  pk(3,1)
  pk(72,16)

  pk(5,1)
  pk(43,1)
  pk(47,1)
  pk(85,1)

  #17.0724019377368
  pk(16,1)
#  pk(62,1)
#  pk(71,1)
  pk(23,1)
#  pk(69,1)
#  pk(75,1)
  pk(88,1)


#  seek(63)
#  seek(72)

  return




def init1():
  #record à battre = 49,31730


  #49.28984977976379
  pk(63,61) #56

  pk(3,1)
  pk(72,16)

  pk(5,1)
  pk(43,1)
  pk(47,1)
  pk(85,1)

  #17.0724019377368

#  pk(16,1)
#  pk(62,1)
  pk(71,1)
#  pk(23,1)
  pk(69,1)
  pk(75,1)
#  pk(88,1)


#  seek(63)
#  seek(72)

  return









def init2():
  #record à battre = 49,31730

  #49.31571202586076

  pk(3,1)

  pk(5,1)
  pk(43,1)
  pk(47,1)
  pk(85,1)

  #17.0724019377368
  pk(16,1)
  pk(62,1)
  pk(71,1)
#  pk(23,1)
#  pk(69,1)
#  pk(75,1)
#  pk(88,1)

  pk(72,35)
  pk(63,143) #56

  return










#algo()
"""
print("\nMAX --------------------------------")
print(scoreMax)
affListe(pklMAX)
"""
print("--------------------------------")

print("pk(n,p) pour rajouter\nle Pokemon n a ta main\navec p points d'attaque.")
#end
(message original)


Abra 74.19 % Tentacool 17.2 % Florizarre 1.08 % Roucool 1.08 % Mystherbe 1.08 % Parasect 1.08 % Triopikeur 1.08 % Tartard 1.08 % Empiflor 1.08 % Dodrio 1.08 %

10. Encephalogramme nous sort lui aussi la même équipe, avec un Abra un peu plus puissant. Le reste c'est le commun des mortels avec plus que 1.05% chacun. Score 49.3155 points.

Encephalogramme a écrit :
Le but était de faire une sorte de force brute 'réfléchie', j'ai donc commencé par classer les Pokémons par score dans un tableau. J'ai repéré quelques Pokémons particulièrement forts en terme de points, et je les ai choisis comme base. Par la suite, j'ai fait tourner pendant quelques heures du random sur 6 ou 7 Pokémons, avec le reste pris dans les meilleurs Pokémons du tableau, et une fois la meilleure combinaison de Pokémons trouvée, j'ai refait tourner du random au niveau des points d'attaques, tout en modifiant la plage de nombre random pour gagner en points à chaque fois. Bon j'ai fini 10., mais je me suis arrêté de chercher quand j'ai vu que tout le monde bloquait en dessous de 49,32 :3


Abra 71.58 % Tentacool 20 % Florizarre 1.05 % Mystherbe 1.05 % Dodrio 1.05 % Triopikeur 1.05 % Tartard 1.05 % Parasect 1.05 % Roucool 1.05 % Empiflor 1.05 %

9. Même équipe chez Afyu, avec un Tentacool un peu moins effacé. Et surtout, plus que 1,04% chacun pour le reste qui n'est plus que de la chair à canon. Score 49.3159 points.


Abra 75 % Tentacool 16.67 % Florizarre 1.04 % Roucool 1.04 % Mystherbe 1.04 % Parasect 1.04 % Triopikeur 1.04 % Tartard 1.04 % Empiflor 1.04 % Dodrio 1.04 %

8. cent20 repart sur l'équipe gagnante Abra-Tentacool mais nous en fait une version poids-lourd en nous remontant les autres à 1,05% et leur ajoutant un Grolem. Tout ça pour 49.3169 points.

cent20 et Golden man a écrit :

PREMIERS TESTS "À LA MAIN"

Comme beaucoup de joueurs, nous avons commencé par générer des mains au petit bonheur la chance, gratifié d’un score maximum de 44,2 nous sommes vite passé à une autre méthode. Nous aurions bien voulu commencer les recherches sur la NumWorks, mais les problèmes de mémoire dont elle souffre rendent ces recherches impossibles. Ajouter quelques lignes de codes au script de 3.7 Ko aurait fait planter la calculatrice. Nous sommes donc passé sur Thonny et y avons exécuté nos scripts Python.

ATTAQUE N°1 : 10^N TIRAGES ALÉATOIRES

Après avoir neutralisé les fonctions print, les affichages des scripts du concours, et rajouté quelques variables globales, une boucle de tirage aléatoire fut codée.

Le résultat n’est pas optimal, on ne tire aléatoirement que les Pokémons en pensant naïvement que les forces sont forcement des entiers entre 1 et 10. Mais on arrive à fabriquer des scores aux alentours de 46,2. En une nuit, on arrive péniblement à réaliser entre 4 et 7 millions de tirages. A ce stade de la recherche, compte tenu de nos hypothèses, on cherche une solution optimale parmi 3 x 10^19 possibilité. Toute force brute est impossible.

import random

score, scoremax = 0.0, 0.0
code, codemax = 0.0, 0.0
tentative = 0

def tiragemain():
  for i in range(1,11,1):
    pokemonaleatoire = random.randint(1,94)
    score=pk(pokemonaleatoire,i)
  return score,code

while score<49.3:
  # Les trois lignes ci-dessous réinitialisent le script, qui tourne sans s'arrêter
  na,pkl=21,[]
  lnm =["Bulbizarre","Herbizarre","Florizarre","Salameche","Reptincel","Dracaufeu",
        "Carapuce","Carabaffe","Tortank","Chenipan","Chrysacier","Papilusion","Aspicot",
        "Coconfort","Dardargnan","Roucool","Roucoups","Roucarnage","Rattata","Rattatac",
        "Piafabec","Rapasdepic","Abo","Arbok","Pikachu","Raichu","Sabelette","Sablaireau",
        "Nidoran F","Nidorina","Nidoqueen","Nidoran M","Nidorino","Nidoking","Melofee",
        "Melodelfe","Goupix","Feunard","Rondoudou","Grodoudou","Nosferapti","Nosferalto",
        "Mystherbe","Ortide","Rafflesia","Paras","Parasect","Mimitoss","Aeromite","Taupiqueur",
        "Triopikeur","Miaouss","Persian","Psykokwak","Akwakwak","Ferosinge","Colossinge","Caninos",
        "Arcanin","Ptitard","Tetarte","Tartard","Abra","Kadabra","Alakazam","Machoc","Machopeur",
        "Mackogneur","Chetiflor","Boustiflor","Empiflor","Tentacool","Tentacruel","Racaillou",
        "Gravalanch","Grolem","Ponyta","Galopa","Ramoloss","Flagadoss","Magneti","Magneton",
        "Canarticho","Doduo","Dodrio","Otaria","Lamantine","Tadmorv","Grotadmorv","Kokiyas",
        "Crustabri","Fantominus","Spectrum","Ectoplasma"]
  mrandmax,mrand,mfmax,nn,mp=2**31-1,0,93,getlinechars(True)-na,na//2
  tentative = tentative+1
  score,code = tiragemain()
  if score>scoremax:
    scoremax = score
    codemax = code
    print("################# tirage n°",tentative,"score =", scoremax,"avec le code", codemax,"#################", round(score,8))


ATTAQUE N°2 : RECHERCHE DES POKÉMON FORTS !

On décide de faire tourner le script précédent et de mémoriser les compositions des mains supérieures à 46. On va donc réaliser quelques millions de tirages, et dénombrer les Pokémons qui ont permis de faire une main supérieure à 46.

Le lendemain, nous avons un histogramme qui nous donne des Pokémons performants :

[0, 54, 25, 143, 11, 99, 39, 23, 5, 10, 6, 11, 9, 17, 10, 31, 70, 13, 12, 10, 48, 15, 38, 51, 18, 6, 21, 33, 13, 19, 5, 8, 13, 48, 13, 33, 35, 5, 31, 24, 31, 9, 33, 94, 28, 13, 5, 106, 16, 8, 34, 51, 27, 6, 13, 3, 36, 33, 42, 4, 17, 9, 72, 311, 3, 16, 30, 25, 32, 74, 13, 60, 172, 40, 12, 62, 44, 1, 8, 38, 6, 32, 15, 22, 21, 101, 25, 24, 73, 19, 26, 5, 33, 4, 18]



Le Pokémon 63 (Abra) est sorti 311 fois dans la nuit dans des mains valant plus de 46 points. Le 64 lui était très mauvais, et il n’était que dans 3 mains valant plus de 46 points.

if score>46:
    for i in listeobtenu:
      benchmark46(i,score)


ATTAQUE N°3 : TIRAGES ALÉATOIRES SUR LISTE OPTIMALE

Le deuxième jour, nous avons poursuivi les tirages aléatoires mais sur des listes optimales générées à l’aide de l’histogramme de la veille.

• Liste large : [ 3,5,16,33,43,47,51,58,62,63,69,71,72,73,75,76,85,88 ]
• Liste short : [ 3,5,16,47,62,63,69,72,75,85,88]

Au lieu de tirer au hasard un Pokémon parmi 94, on le tirait dans une liste prédéfinie à diverses positions (nous pensions que la force était la position, donc un entier entre 1 et 11).

5 000 000 de tirages plus tard, pas de grandes améliorations, 47.6 est notre meilleur score, mais c’est déjà un joli résultat.

def tiragemain():
  listeobtenu =[]
  top = [ 3 , 5 , 16 , 47, 62, 63, 69, 72, 75, 85, 88]
  random.shuffle(top)
  for i in range(1,11,1):
    pokemonaleatoire = top[i-1]
    listeobtenu.append(pokemonaleatoire)
    score=pk(pokemonaleatoire,i)
  for i in listeobtenu:
    benchmark(i,score)
  if score>47:
    for i in listeobtenu:
      benchmark47(i,score)
  return score,code,listeobtenu


ATTAQUE N°4 : VALEUR MOYENNE DES MAINS

Toutes les tentatives pour optimiser la valeur moyenne des mains ont échouées. Le calcul lui même de cette moyenne n’étant pas concluant.

ATTAQUE N°5 : RECHERCHE DES POKÉMON FORTS SUR ℝ

En lisant le forum associée à ce défi sur Planète Casio, on croit comprendre qu’il n’y a pas un nombre fini de combinaisons, donc si on tire n dans les entiers entre 1 et 94, p lui serait un réel. On relance les scripts précédents et miracle on passe au dessus de 47.8.

def tiragemain():
  listeobtenu =[]
  for i in range(1,11,1):
    pokemonaleatoire = random.randint(1,94)
    listeobtenu.append(pokemonaleatoire)
    score=pk(pokemonaleatoire,uniform(0,2**31-1))
  if score>46:
    for i in listeobtenu:
      benchmark47(i,score)
  return score,code,listeobtenu

Après avoir affiné la liste des Pokémons optimaux, on relance les autres scripts qui mélangent, permutent, tirent d’après la liste optimale, et on obtient nos premiers score à 48.

0^uxOeh%_##>(6#))*&#
48.12835164090643

^heO0xku#_D#’’#%$*.0
48.14694065075124

ATTAQUE N°6 : ÉLIMINATION DES PLUS FAIBLES

N’étant pas certains d’avoir la main optimale, on essaye de remplacer un Pokémon par tous les autres pour voir si le score s’améliore. Cette méthode ne permet pas de progresser.

ATTAQUE N°7 : TENTATIVE DE SPÉCIFICATIONS DES FONCTIONS

On décide alors de documenter le code, de le décrypter, d’essayer de voir si on ne peut pas faire le problème à l’envers, c’est une attaque par spécification du code.

def mmod(a, b):
    # retourne la partie décimale de a a vérifier
    # si a est un entier, retourne 0
    # ?? intérêt , a % b économise de la mémoire
    return a % b


def getplatform():
    # retourne la valeur 1
    # ?? intérêt ?
    return 1


def getlinechars(o=False):
    # Cette fonction est une bague. Elle est appelée une unique fois avec true
    # et alors getlinechars(True) retourne 99
    c = 2 ** 31 - 1
    k = getplatform()
    # ?? k = 1 ;-)
    if k >= 0:
        # k = 1 donc est exécuté dans 100% des cas ...
        c = [53, o and 99 or 29, o and 509 or 21, 31, 32, c, c][k]
    return c  # c= 99  ... sauf astuce et codage plus bas ^^
    # pas défaut, en l'absence de True getlinechars() retourne 29

Les premières fonctions sont faciles à spécifier. Les variables sont rigolotes.

na = 21
# 42/2 ? :-) Utilisé 2 fois, jamais modifié
mrandmax = 2 ** 31 - 1
# valeur max d'un entier positif signé codé en 32 bits... spé NSI inside
mrand = 0
# rien d'aléatoire ici, sera modifié par la fonction mseed()
mfmax = 93
# 94-1
nn = getlinechars(True) - na
# nn = 99-21 = 78 (sans calculatrice !)
mp = na // 2
# mp = 10, jamais modifié, utilisé une seule fois f° pk

Mais nous sommes restés coincés sur les fonctions getattack(), clean() et surtout pk(). Par contre la fonction setst() nous a passionnés !

Ci-contre le script original à peine modifié, commenté et codé en pep8.

# cas
import math
# pas utilisé ?

"""Ajouts"""
# sera utilisé dans nos scripts
code = 0.0
"""Fin des ajouts"""


def mmod(a, b):
    # retourne la partie décimale de a a vérifier
    # si a est un entier, retourne 0
    # ?? intérêt , a % b économise de la mémoire
    return a % b


def getplatform():
    # retourne la valeur 1
    # ?? intérêt ?
    """ modifié, 1 avant 2 maintenant"""
    return 2


def getlinechars(o=False):
    # Cette fonction est une bague. Elle est appelée une unique fois avec true
    # et alors getlinechars(True) retourne 99
    c = 2 ** 31 - 1
    k = getplatform()
    # ?? k = 1 ;-)
    if k >= 0:
        # k = 1 donc est éxécuté dans 100% des cas ...
        c = [53, o and 99 or 29, o and 509 or 21, 31, 32, c, c][k]
    return c  # c= 99  ... sauf astuce et codage plus bas ^^
    # pas défaut, en l'absence de True getlinechars() retourne 29


na = 21
# 42/2 ? :-) Utilisé 2 fois, jamais modifié
pkl = []
# une liste
lnm = ["Bulbizarre", "Herbizarre", "Florizarre", "Salameche", "Reptincel", "Dracaufeu", "Carapuce",
                        "Carabaffe", "Tortank", "Chenipan", "Chrysacier", "Papilusion", "Aspicot", "Coconfort",
                        "Dardargnan", "Roucool", "Roucoups", "Roucarnage", "Rattata", "Rattatac", "Piafabec",
                        "Rapasdepic", "Abo", "Arbok", "Pikachu", "Raichu", "Sabelette", "Sablaireau", "Nidoran F",
                        "Nidorina", "Nidoqueen", "Nidoran M", "Nidorino", "Nidoking", "Melofee", "Melodelfe", "Goupix",
                        "Feunard", "Rondoudou", "Grodoudou", "Nosferapti", "Nosferalto", "Mystherbe", "Ortide",
                        "Rafflesia", "Paras", "Parasect", "Mimitoss", "Aeromite", "Taupiqueur", "Triopikeur", "Miaouss",
                        "Persian", "Psykokwak", "Akwakwak", "Ferosinge", "Colossinge", "Caninos", "Arcanin", "Ptitard",
                        "Tetarte", "Tartard", "Abra", "Kadabra", "Alakazam", "Machoc", "Machopeur", "Mackogneur",
                        "Chetiflor", "Boustiflor", "Empiflor", "Tentacool", "Tentacruel", "Racaillou", "Gravalanch",
                        "Grolem", "Ponyta", "Galopa", "Ramoloss", "Flagadoss", "Magneti", "Magneton", "Canarticho",
                        "Doduo", "Dodrio", "Otaria", "Lamantine", "Tadmorv", "Grotadmorv", "Kokiyas", "Crustabri",
                        "Fantominus", "Spectrum", "Ectoplasma"]
# la liste des pokemons
mrandmax = 2 ** 31 - 1
# valeur max d'un entier positif signé codé en 32 bits... spé NSI inside
mrand = 0
# rien d'aléatoire ici, sera modifié par la fonction mseed()
mfmax = 93
# 94-1
nn = getlinechars(True) - na
# nn = 99-21 = 78 (sans calculatrice !) si k =1
# nn = 509-21 = 488 (sans calculatrice !) si k =2
mp = na // 2
# mp = 10, jamais modifié, utilisé une seule fois f° pk (mp = p maximum je pense)


def mround(f):
    # arrondi f à l'entier le plus proche
    d = mmod(abs(f), 1)
    return (mfloor(abs(f)) + (d >= .5)) * (1 - 2 * (f < 0))


def mfloor(f):
    # arrondi f à l'entier naturel inférieur
    return round(f) - (round(f) > f)


def mceil(f):
    # arrondi f à l'entier naturel supérieur
    return round(f) + (round(f) < f)


def mseed(s):
    global mrand
    # modifie une variable globale sans retourner aucune valeur
    # mrand est le reste dans la division euclidienne de s par mrandmax
    # suprenant car mrandmax est l'entier maximum, filouterie ?
    # Si s=mrandmax alors elle réaffecte 0 à mrand,
   # Si s!=mrandmax elle affecte s à mrand
    mrand = mmod(s, mrandmax)


def mrandom():
    # un générateur aléatoire sans fonction random ...
    # je dois creuser - à tester en profondeur
    mseed(mrand * 16807)
    return float(mrand / mrandmax)


def muniform(mini, maxi):
    # à coup sur une loi uniforme sur un intervalle
    # je dois creuser - à tester en profondeur
    return mrandom() * (maxi - mini) + mini


def mrandint(mini, maxi):
    # à coup sur un tirage d'entier naturel
    # je dois creuser - à tester en profondeur
    return mround(muniform(mceil(mini), mfloor(maxi)))


def f2mf(f):
    # Multiple f par 93 car c'est le dernier pokemon en commençant à 0
    # en retourne l'arrondi de ce nombre
    # ?? a quoi ça sert ??
    return mround(float(f * mfmax))


def mf2f(n):
    # retourne un réel obtenu en divisant n par 93
    return float(n / mfmax)


def mbit(a, b):
    # a tester
    # renvoie le reste de la division euclidienne de a // 2**b et 2
    # autrement dit, permet de savoir si le quotient de la division euclidienne
    # de a par 2**b est impair (retourne 1) ou pair (retourne 0)
    return mmod((a // (2 ** b)), 2)


def getattack(p, pts):

    # Permet d'obtenir l'attaque du pokemon en fonction de son indice n (ici p)
    # Et d'un parametre (l[2] dans le code) qui change avec le clean()

    global pkt
    mseed(42)
    for k in range(p + 1):
        mrandom()

    a = mrandint(1, mrandmax)
    pka = ""

    for j in range(na):

        if mbit(a, j) != 0:
            # Si a / 2^j est impair, la condition est valide et on gagne des points
            pka += "X"
            pkt[j] += pts
        else:
            # Else parfaitement inutile
            pka += " -"[getplatform() >= 5]

    return pka


def i2c(k):
    # Transforme un nombre décimal en chaine de caractère
    return chr(k + 33)


def c2i(c):
    # transforme une chaine de caractère ayant un élèment en valeur décimale
    # cette valeur décimale sera comprise entre 32 (a) et 89 (z)
    return ord(c) - 33


def clean():
    global pkl
    t = 0
    s = 0

    for l in pkl:
        t += l[1]
    # On rajoute 1 a tout les p des pokemons de la liste

    for l in pkl:
        # Affecte l[1] / t (si t est superieur a 1) / 93 (fonction f2mf) a l[2]
        l[2] = f2mf(l[1] / (t or 1))
        # Ajoute le resultat obtenu a s
        s += l[2]
        if (l[2] <= 0):
            # Si l[2] <= 0: le pokemon est supprime et la fonction engage une recursion
            pkl.remove(l)
            return clean()
    return s


def pk(n, p=1, d=2):

    global pkt, pkl, code # @@ AJOUT code @@
    n -= 1 # Permet de selectionner le bon indice du pokemon

    if n >= 0 and n < len(lnm):
        # Verifie la validite de l'indice n
        # Ajoute un pokemon a la liste s'il est nouveau
        # Sinon, actualise la position si p >= 0 et met 0 sinon
        new = True
        for k in range(len(pkl)):
            # C'est cette boucle qui verifie si le pokemon est deja selectionne
            # RAPPEL : pkl[k][0] est l'indice du pokemon k qui sont a nous
            # PEU IMPORTE p
            if pkl[k][0] == n:
                new = False
                pkl[k][1] = max(p,0)
        # S'il est nouveau, on le dompte et il est a nous !
        if new and len(pkl) < mp:
            pkl.append([n, max(p, 0), 0])

    # Initialisation des variables
    ptt = clean() # Fonction la plus obscure, les recursions, c'est chiant
    # J'ai du mal a bien discerner son fonctionnement
    # du coup on ne sait pas combien vaut ptt embétant ça
    pkt = [0 for k in range(na)] # Une liste avec 21 zeros dedans
    t = 0
    # initialise le score à 0
    st = ""
    # initilise la chaine de caractère donnant le code

    for l in pkl:

        # Chaque l est de la forme
        # l = [n ; max(0;p) ; 0 (pour l'instant...) ]
        # Et represente un pokemon de notre main, peu importe sa position

        s = getattack(l[0], l[2] / ptt)
        # j'ai l'impression que le pokemon n affronte le n+2
        if d:
            sn = " " + lnm[l[0]]
            if len(sn) > nn:
                sn = sn[:nn]
            """" print(s + sn)""" # desactivé
        st = i2c(l[0]) + st + i2c(l[2])
        # Fabrique le code en ajoutant par la gauche le pokemon et par la droite sa force
    for k in pkt:
        if (k):
            t += math.log(math.exp(1) + k * len(pkl))
    if (d):
        """if (d >= 2):
            print("Bon score ? Si oui\nenvoie code suivant\na info@tiplanet.org :") """ # neutralisé
        """print("" + st)"""  # neutralisé
        code = ""+st # @@ AJOUT @@
    return float(t)


def setst(st):

    s = 0
    # Initialise le score à 0
    pkl[:] = []
    # vide la liste pkl de son contenu
    n = len(st) // 2
    # Mesure la longueur de la chaine de caractère (20) et divise par 2
    # utilisé pour la boucle for ci-dessous
    # la partie gauche c'est le codage des pokemon en ACSII décimal
    # la partie gauche c'est les forces en ACSII décimal
    # L'ordre des poid et des pokemons n'a aucune importance tant que le pokemon conserve sa force
    # En changeant l'ordre de 2 pokemons ou de 2 poid aucune différence (merci kevin)

    for k in range(n):
        s = pk(c2i(st[n - 1 - k]) + 1, c2i(st[n + k + len(st) % 2]), k + 1 >= n)
    return s

ATTAQUE N°8 : MANIPULATIONS AUTOUR DU CODE RÉPONSE

La liste des Pokémons est codée en dur dans le script, mais il n’en est rien de leurs qualités ni de la valeur de force optimale pour chaque Pokémon. Cette dernière est donc calculée. Or la chaîne de caractère du code réponse semble peu varier lorsque de l’on tire depuis une liste fixé de Pokémons. Nous comprenons que :
• La partie gauche code la liste des Pokémons.
• La partie droite leur force.
• Pour un code "ABCDEFGHIJ0987654321", on a 10 couples (un exemple est ici en gras) qui définissent les 10 Pokémons et leurs points d’attaque.
• On peut faire de jolies permutations sans changer le score obtenu car les couples n’influent pas les uns sur les autres.
• Il n’y a aucune clé de vérification, on peut tester des codes au hasard sans avoir la moindre idée de la main des Pokémons et de leur forces.
• Les forces sont codés par des caractères ASCII, on n’est plus du tout dans ℝ mais de retour dans ℕ.

def i2c(k):
    # Transforme un nombre décimal en chaine de caractère
    return chr(k + 33)


def c2i(c):
    # transforme une chaine de caractère ayant un élèment en valeur décimale
    # cette valeur décimale sera comprise entre 32 (a) et 89 (z)
    return ord(c) - 33

En modifiant à la main la partie droite de la chaîne de caractères, on arrive à modifier très substantiellement le score, à la hausse comme à la baisse. Notre premier 49 est obtenu en bricolant à la main la chaîne de caractère.

C’était assez jouissif il faut dire, en changeant un caractère parmi les 10 derniers, notre score pouvait plonger OU augmenter bien plus vite que tous nos algorithme de tirages aléatoires qui tournaient des nuits complètes... Ce code réponse ne contient que 20 caractères, on connaît déjà les 10 premiers (du moins on le pense) il ne nous reste plus qu’à utiliser la force brute sur les dix derniers caractères.

u^KhxO_%#l"""l"""%%%
Out[17] : 49.031613189324844


ATTAQUE N°9 : FORCE BRUTE POUR TRAITER LES CHAINES DE CARACTÈRE DU CODE RÉPONSE

Grace à notre compréhension obtenue avec l’attaque n°08, on a supposé que pour une liste de 10 pokémons, il existe une suite de forces optimales.

On a ainsi écrit un petit script permettant de trouver cette suite optimale.

lc = [None,"!","!","!","!","!","!","!","!","!","!"]
carac = '!"#$%&'+"'"+'()*+^;_,-./0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
def cons(liste):
    # Construit le code
    global cc
    cc = ""
    for j in range(len(liste)):
        cc = cc+liste[j]
def turboBoost(pokemons,vitesse=1,style=1):
    # Prend une main de pokemon et lui donne des steroides
    # la chaine finale sous forme de liste pour modifier les caracteres
    lc[0]=pokemons
    # les caracteres a tester (tout ce qui est possible)
    for l in range(vitesse+3):
        # creation du code par test (5x ou 4x pour trouver "l'etat stable" a tout les coups)
        # vitesse 1 = rapide, vitesse 2 = lent mais plus sur
        for i in range(1,11):
            # On initialise tout
            global cc
            cons(lc)
            scores = [0]

            for k in range(len(carac)):
                # On recense le score pour chaque caractere
                lc[i] = carac[k]
                cons(lc)
                score = setst(cc)
                scores.append(score)
            # On prend le gagnant, c'est notre partie de cle
            lc[i] = carac[scores.index(max(scores))-1]
            # on cree le code final
            cons(lc)
         # style pour la fonction (purement cosmetique)
        if style:
            print(int((l+1)*100/(vitesse+3)),"%")
            if vitesse == 1:
                print("====="*(l+1)*2+"....."*(8-(l+1)*2))
            if vitesse == 2:
                print("===="*(l+1)*2+"...."*(10-(l+1)*2))
    score = setst(cc)
    print(cc+" :",score,": "+code)

On remarque qu’il est nécessaire d’avoir une liste pour modifier les éléments de la chaîne de caractères un par un à une position donnée.

Rien qu’avec ce script, on a pu augmenter considérablement le score des meilleurs Pokémons issus des attaques précédentes.Avant :

u^KhxO_%#l"""l"""%%%
Out[17] : 49.031613189324844

Après :

turboBoost("u^KhxO_%#l")
25 %
==========..............................
50 %
====================....................
75 %
==============================..........
100 %
========================================

u^KhxO_%#l"""^""1""" : 49.29025926955508 : u^KhxO_%#l"""d""3"""

Cette optimisation du membre de droite nous permettait de faire la même chose pour le membre de gauche.

On a alors écrit une fonction utilisant notre fonction d’optimisation pour tester chaque caractères pour le membre de gauche en optimisant le score à chaque fois pour trouver le code parfait.

def chasseAuxPokemons(vitesse=1):
    # La vitesse 1 m'a prise 9h mais a bien fonctionnée

    lcp = ["!","!","!","!","!","!","!","!","!","!"]
    for l in range(vitesse+3):
        for i in range(10):
            # On initialise tout
            global cc
            cons(lcp)
            scores = [0]

            for k in range(len(carac)):
                # On cree la liste de Pokemons avec les caractères
                lcp[i] = carac[k]
                cons(lcp)
                # On applique le booster de performances dessus (rapide et sans les barres de %)
                turboBoost(cc,1,0)
                # On recense les scores
                score = setst(cc)
                scores.append(score)
            # On prend le gagnant, c'est notre nouveau Pokemon
            lcp[i] = carac[scores.index(max(scores))-1]

Grace à cette fonction, on a pu obtenir le TOP résultat, le fameux 49,31730.

On a donc envoyé des scores légèrement en dessous pour pouvoir nous qualifier dans les premiers.

_h#^g0KuOS""""""""7u
49.31730339247606


ATTAQUE N°10 : FORCE BRUTE OUI MAIS...

Nous avions exclu quelques caractères de cette force brute, on a donc réussi uniquement à obtenir le premier TOP résultat qui était déjà pris, le fameux 49,31730 mais pas au delà. Quand les premiers 49.319 et 49.32 ont commencé à sortir, nous avons compris que nous avions trop traîné, et qu’en intégrant d’autres caractères de la table ASCII nous aurions pu finir premier. Nous pensions que 49,31730 était le résultat optimal, nous n’avons pas testé davantage alors qu’on avait à priori la bonne méthode. Mais notre échec relatif nous à gonflé à bloc pour le défi historique, que nous avons fait en Python cela va de soit et sur PC car la mémoire de la NumWorks à la date d’octobre 2019 ... enfin vous voyez de quoi on veut parler, sinon il suffit de lire ceci : Script qui refuse de s’exécuter sur la Numworks N0100 pour comprendre de quoi il en retourne.

CONCLUSIONS

Nombres de tirages réalisés au total : entre 20 000 000 et 30 000 000 maximum. 3 scripts tournaient au maximum en même temps, sur deux ordinateurs distincts. L’année prochaine, il faudra compter sur nous ! Et cette fois-ci on commencera le défi le jour J et pas en retard. Pavel va devoir ... heu non rien du tout, Pavel est très au dessus du niveau moyen. ;-)

Nous remercions les organisateurs des sites TI-Planet et Planète Casio pour ce bon moment, cette recherche était passionnante, nous a réveillé la nuit (histoire de vérifier que les scripts tournaient bien) et maintenant les listes en Python n’ont plus de secret pour nous. Sur un autre sujet, nous supplions l’équipe de NumWorks d’augmenter la mémoire allouée aux scripts Python sur la N0100 et la N0110. Ne pas pouvoir écrire un script de plus de 4Ko est une absurdité !
(article original sur nsi.xyz)


Abra 72.63 % Tentacool 18.95 % Florizarre 1.05 % Roucool 1.05 % Mystherbe 1.05 % Parasect 1.05 % Tartard 1.05 % Empiflor 1.05 % Grolem 1.05 % Dodrio 1.05 %

7. Nous passons maintenant à Tituya, membre de TI-Planet et de Planète Casio avec là encore une équipe dirigée par le couple Abra-Tentacool. Particularité ici, les bidasses ont la compagnie de leur meilleur ami Caninos. Résultat 49.3171 points.

Tituya a écrit :
Malgré ma place relativement petite dans ce concours (tout de même 7., c'est honorable ), je vous partage ici mes différentes recherches dans ma quête pour trouver le meilleur score possible !

L'ère de la recherche :
Avant de chercher l'automatisation, j'avais rempli à la main le score renvoyé par chaque Pokémon, me permettant donc d'obtenir une base d'équipe assez complète. Malgré le fait que certains Pokémons ne soient pas terribles en équipe, j'obtenais tout de même des résultats convaincants ! (deuxième version du script). J'avais trouvé 49.936 points ! Puis je cherchais (comme beaucoup) à la main les points d'attaque qui renvoyaient le plus haut score ! J'ai très vite remarqué que seul 2 Pokémons pouvaient faire varier drastiquement le score : Abra et Tentacool !

L'ère de l'automatisation :
J'avais déjà formé une équipe me donnant un paquet de points. J'ai donc eu l'idée de lancer un premier script pour chaque Pokémon afin de tester si un Pokémon renvoyait un score que je n'avais pas vu !
(PETIT POINT : J'ai malheureusement perdu la liste de mes Pokémons à cause d'un problème de clef USB ayant été volée ou oubliée... (plus pratique sur clef quand tu bosses au lycée sur le concours pendant les cours d'SI )). Donc les scripts qui suivent ont été réécrits...

for a in range(94):
   pk(a,1)
   s=st
   print("score final =",setst(s))
   if setst(s)>49.3:
     print(f"                    OK pour a = {a}, s={setst(s)} pour {st}")
   pk(a,0)

Puis je testais la priorité d'attaque de chacun de ces Pokémons grâce à un script comme ça.

for a in range(150):
  pk(62,a)
  s=st
  print("score final =",setst(s))
  if setst(s)>49.3:
    print("OK !")
    print(a,setst(s),"pour",st)
  pk(62,0)

Grâce à ces petits scripts, j'ai tout de même réussi à trouver des scores comme 49.3158 points !

Puis à partir d'un moment je me suis demandé comment le code était créé. J'ai vite remarqué que chaque Pokémon correspondait à une valeur dans le code (genre par exemple le Pokémon numéro 63 correspond à '_' et le Pokémon 62 correspond à '^'). Enfin brefs, les dix premiers caractères du code représentent les Pokémons pris. Et cette valeur est facilement manipulable ! J'ai donc créé un script avec tous les caractères possibles (je n'ai malheureusement pas pensé à la table ASCII). Au final, j'ai pris le problème à l'envers en fait. J'y ai ajouté une vérification pour savoir si le score trouvé était déjà envoyé par un 'concurrent'. Et hop ! Plus qu'à laisser tourner !

Ce qui m'a permis de trouver sans effort (juste beaucoup de temps) des combinaisons auxquelles je n'avais pas pensé ! Puis j'ai cherché automatiquement quel Pokémon me donnait cette lettre dans le code !

J'ai pris le sujet à l'envers pour en tirer le plus possible avec ma petite échelle de lycéen lambda... J'ai surtout passé énormément de temps à chercher des choses en tout genree, essayé d'automatiser des bouts de code, je pense sincèrement que ce concours m'a pris plus d'une vingtaine d'heures ! Entre désillusions, avec des tentatives de bruteforce de plusieurs heures sans succès. Ou la joie de voir mon petit programme renvoyer soudainement un "OK pour cette valeur" ! Au final, ce concours m'a permis d'améliorer grandement ma maîtrise en Python ! Et étonnamment, réussir à obtenir une place sans comprendre une ligne du script fourni.

Comme quoi, avec le temps et la persévérance on peut réussir même sans tout comprendre !

Bien joué à tous/toutes pour ce concours ! Et particulièrement à cent20 qui m'a poussé sans le savoir à une compétition personnelle entre lui et moi !
(message original 1, message original 2)


Abra 73.68 % Tentacool 17.89 % Florizarre 1.05 % Roucool 1.05 % Mystherbe 1.05 % Parasect 1.05 % Caninos 1.05 % Tartard 1.05 % Empiflor 1.05 % Dodrio 1.05 %

6. Golden man nous remet le couvert avec la même équipe, avec juste un petit peu plus de puissance pour Tentacool. Ce qui fait toute la différence avec 49.3171 points.

Golden man a écrit :
Tout d'abord je voulais remercier les organisateurs pour ce concours génial et très instructif.
Ma méthode : On a commencé avec cent20 par analyser le programme en le commentant bloc par bloc, voire ligne par ligne, afin d'avoir une vision d'ensemble plus nette. A l'aide de la fonction setst(), j'ai pu analyser la lecture du code score (et donc sa construction) et j'ai effectué quelques tests pour voir si les couples (n,p) étaient liés en changeant leur position dans le code.

J'ai ensuite écrit un script pour tester les caractères optimaux sur le "membre de gauche" (les 10 derniers caractères du code) et j'ai pu augmenter considérablement des petits scores que j'avais.

lc = [None,"!","!","!","!","!","!","!","!","!","!"]
carac = '!"#$%&'+"'"+'()*+^;_,-./0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
def cons(liste):
    global cc
    cc = ""
    for j in range(len(liste)):
        cc = cc+liste[j]
def turboBoost(pokemons,vitesse=1,style=1):
    lc[0]=pokemons
    for l in range(vitesse+3):
        for i in range(1,11):
            global cc
            cons(lc)
            scores = [0]
            for k in range(len(carac)):
                lc[i] = carac[k]
                cons(lc)
                score = setst(cc)
                scores.append(score)
            lc[i] = carac[scores.index(max(scores))-1]
            cons(lc)
        if style:
            print(int((l+1)*100/(vitesse+3)),"%")
            if vitesse == 1:
                print("====="*(l+1)*2+"....."*(8-(l+1)*2))
            if vitesse == 2:
                print("===="*(l+1)*2+"...."*(10-(l+1)*2))
    score = setst(cc)
    print(cc+" :",score,": "+code)

Une fois ce membre optimisé, j'ai fait pareil pour le membre de droite.

def chasseAuxPokemons(vitesse=1):
    lcp = ["!","!","!","!","!","!","!","!","!","!"]
    for l in range(vitesse+3):
        for i in range(10):
            global cc
            cons(lcp)
            scores = [0]
            for k in range(len(carac)):
                lcp[i] = carac[k]
                cons(lcp)
                turboBoost(cc,1,0)
                score = setst(cc)
                scores.append(score)
            lcp[i] = carac[scores.index(max(scores))-1]

Après avoir tourné quelques heures la nuit, j'avais trouvé le 49.3173033 que je pensais être le maximum, puisque je n'avais pas de code au dessus en réponse. J'ai alors envoyé un code qui me donnait un score juste en dessous de ceux qui étaient déjà donnés.
(message original)


Abra 72.63 % Tentacool 18.95 % Florizar 1.05 % Roucool 1.05 % Mystherbe 1.05 % Parasect 1.05 % Caninos 1.05 % Tartard 1.05 % Empiflor 1.05 % Dodrio 1.05 %

5. Zocipal nous produit une énième version d'équipe dirigée par Abra-Tentacool, en nous saupoudrant leurs sous-fifres d'un Triopikeur qui lui permet bién évidemment de passer la dernière décimale du score précédent au chiffre 3 supérieur : 49.3173 points.

Zocipal a écrit :
Voici mes explications pour le concours Python. Je ne vais expliquer ici que ma dernière façon de faire (la meilleure), mais sachez que j'ai fait beaucoup de scripts plus simples avant m'ayant permis d'obtenir mon score. Celui-là permet juste de le faire plus vite.

L'idée est de bruteforce via le code et donc setst(). Voici ci-contre le code en entier avec en commentaire les explications.

Pour ce qui est dans la boucle :
Le script va améliorer le code. Il va changer lettre par lettre le code et voir si le résultat est meilleur. Puis 2 lettres par 2 lettres... 3 lettres par 3 lettres...

Ex : code 'banane' donne 5. Ça va tester 'canane' puis 'danane' puis 'bbnane'... intelligement puis imaginons il a trouvé 'donone' → 6 il va faire 'pznone' 'dpzone' 'dopzne' 'donpze' 'donopz'...

Juste en laissant tourner et avec un peu de chance on arrive à mon score facilement. On peut arriver au score maximal en changeant la longueur du code de base (le mien 20 caractères, celui du meilleur 33 caractères je crois). En 5 minutes on obtient un code supérieur à 49.09.

Merci pour votre lecture !

import os
import random
import string
import sys
import time

from tqdm import tqdm # Juste pour afficher une barre de chargement

from numworks import * # Fichier du concours converti avec Cython


def disablePrint(): # Juste pour pas que ça print plein de choses inutiles
    sys.stdout = open(os.devnull, 'w')


def enablePrint():
    sys.stdout = sys.__stdout__


def randomStringwithDigitsAndSymbols(stringLength=2): # pour générer la chaîne aléatoire
    password_characters = string.ascii_letters + string.digits + string.punctuation
    return ''.join(random.choice(password_characters) for i in range(stringLength))




disablePrint()
x = 4
code = randomStringwithDigitsAndSymbols(20) # génère le code en partant d'un fait au hasard.
ancien = setst(code)[0]
used = []
while True:
    disablePrint()
    for z in range(1,4): # ici de 1/1 lettre à 3/3 lettres
        enablePrint()
        print("[INFO] Change tester form from {} to {}".format(z-1, z))
        disablePrint()
        for i in tqdm(range(len(code) - z)):
            for michel in range(int(94**(z*0.5))):
                random.seed = random.randint(1, 100) * michel - z ** i
                oldcode = code
                while True:
                    try:
                        code = list(code)
                        code[i:i + z] = randomStringwithDigitsAndSymbols(z)
                        code = ''.join(code)
                        assert code not in used
                    except AssertionError:
                        continue
                    else:
                        a, b = setst(code)
                        used.append(code)
                        break
                if a > ancien:
                    ancien = a
                    enablePrint()
                    print("A = ", a, "B =", code, "C =", pkl)
                    disablePrint()
                else:
                    code = oldcode
(message original)


Abra 72.63 % Tentacool 18.95 % Florizarre 1.05 % Roucool 1.05 % Mystherbe 1.05 % Parasect 1.05 % Triopikeur 1.05 % Tartard 1.05 % Empiflor 1.05 % Dodrio 1.05 %

4. Ne0tuX, membre aussi bien de TI-Planet que de Planète Casio, nous exhibe la même équipe mais avec un Abra un peu plus puissant, au détriment de ses esclaves qui tombent à 1,04% de puissance chacun. Et il a visiblement raison de procéder ainsi, puisque le score monte à 49.3181 points !


Abra 73.96 % Tentacool 17.71 % Florizarre 1.04 % Roucool 1.04 % Mystherbe 1.04 % Parasect 1.04 % Triopikeur 1.04 % Tartard 1.04 % Empiflor 1.04 % Dodrio 1.04 %

Ne0tux a écrit :
Félicitations à tous les participants qui se sont intéressés au défi, ainsi qu'aux organisateurs !

Comme il est de coutume je fais un petit retour sur ma méthode. A l'instar de Pavel j'ai repris mon outil de l'an dernier : l'algorithme génétique. Dans un premier temps il me fallait 'modéliser' un individu (ici il s'agit de la main complète de 10 Pokémons). En y réfléchissant, j'ai réalisé que le code de participation constituait déjà en lui même une modélisation de l'individu ! J'ai donc créé un générateur de main qui tirait aléatoirement 20 caractères et remodelé légèrement la fonction de calcul de score pour l'accélérer. Je n'avais besoin de rien de plus pour faire tourner l'algorithme génétique, qui a très rapidement permis d'atteindre le score maximum 'honnête' (voir ci-dessous) de 49.3173. Sauf que mon générateur de main avait un petit défaut : il incluait un caractère en trop (celui après le tilde dans la table ASCII), normalement hors borne. Dans la pratique cela permettait de gratter quelques digits dans la normalisation des puissances ! Malheureusement le caractère en question n'est pas passé par mail lors de ma participation. D'ailleurs on voit dans le classement que j'en ai deux alors que c'est la même, à un problème de copier/coller près !

J'ai pu rectifier le soucis quelques jours plus tard en comprenant le problème. Par manque de temps, je n'ai pas effectué la dernière étape pourtant facile du bruteforce sur les caractères spéciaux, sachant que les caractères liés aux Pokémons devaient déjà être les bons. J'ai vu que ça n'avait pas échappé à certains qui ont su apporter cette petite finition qui a fait la différence : bravo !

Le code pour générer une population d'individus (i.e. un certain nombre de decks chacun composé de 10 Pokémons) c'est du style : Pop = [''.join(chr(rd.randint(0, 94)+33) for i in range(NB_POKEMONS)) for j in range(NB_DECKS)]

Le code pour calculer le score des individus de cette population c'est celui du concours (version Python Numworks) à quelques optimisations près. L'algorithme génétique qui utilise ces deux premiers éléments et qui permet de mixer les gènes des individus pour ne garder/croiser que les meilleurs c'est exactement celui décrit sur la page Wikipédia (voir le schéma récapitulatif). Je n'ai pas les moyens dans l'immédiat de fournir mon code complet mais les implémentations de cet algorithme en Python sont légions sur le net ! D'ailleurs l'an passé nous étions plusieurs à avoir choisi cette voie et à avoir partagé nos sources ici.

Je prends quelques minutes pour donner plus de détails, que voici plus bas. Le principe de l'algorithme génétique est beaucoup plus simple que ce que l'on pense. Il ressemble à ce que tout un chacun sait de la théorie de l'évolution : les meilleurs individus d'une population survivent et se reproduisent pour créer de nouveaux individus. Les individus les plus mauvais se reproduisent moins et leurs gènes ne sont pas perpétuées d'une génération sur l'autre. A terme les individus les plus adaptés subsistent. Pour faire tourner cet algorithme il faut définir ce qu'est un individu et expliciter ce que veut dire un 'bon' individu par opposition à un 'mauvais' individu. Dans le cadre de cette épreuve, il est clair qu'un individu est une main complète. L'avantage est que le nombre maximum de cartes dans la main est connu : 10. On sait qu'une carte associe à un numéro de Pokémon une puissance. Par conséquent un individu est modélisable par 10 couples [Numéro de Pokémon, Puissance]. Dans la pratique, il était plus simple de considérer le code de participation en tant que modélisation, puisque 20 caractères suffisent à définir intégralement les 10 cartes d'une main. Pour ce qui est de discerner les bons individus des moins bons, et bien le concours fournissait une fonction qui permettait en donnant un code de participation d'obtenir directement le score associé. L'algorithme réalise donc les étapes suivantes :

0) Générer au hasard une population d'individus. Dans notre cas cela revient à créer un certain nombre de chaînes de 20 caractères.
1) Calculer le score de chaque individu de la population et les trier du meilleur au moins bon.
2) Faire un tirage au hasard de deux individus que l'on appelle 'parents', proportionnellement à leur score (tirage par roue de la fortune). C'est à dire que plus le score d'un individu est élevé, plus il a de chance d'être choisi comme parent. Cette étape s’appelle la sélection.
3) Échanger des gènes entre deux parents pour créer un ou deux enfants. On parle d'enjambement. Concrètement ici une gêne d'un individu est un couple [Numéro de Pokémon, Puissance]. Dans le cas de la modélisation choisie, une gène est donc constituée de deux caractères de la chaîne. Un enfant c'est donc également une chaine de 20 caractères, dont la plupart sont recopiés d'un premier parent et quelques-uns sont recopiés d'un second.
4) Muter les enfants. Pour ajouter un peu d'entropie et éviter que l'algorithme ne tourne trop sur lui même (Peut-on parler de consanguinité ?), on change aléatoirement mais pas systématiquement une gène d'un enfant.
5) Générer une nouvelle population à partir de tous les nouveaux enfants en gardant quelques-uns des parents. On peut dire qu'il s'agit d'une nouvelle génération. Puis recommencer à l'étape 1).

Quelques remarques :
• Le procédé est stochastique c'est à dire qu'il repose en grande partie sur des tirages aléatoires. Il est donc possible que seuls des optimums locaux soient trouvés et que l'optimum global ne le soit jamais ! Il est donc nécessaire d'ajouter en étape 5) un contrôle de la population capable de 'resetter' une partie de la population si l'on sent que ça stagne.
• Le paramétrage est primordial. Notamment le choix de la taille de la population, le nombre de gènes croisées entre les parents pour créer un enfant, le pourcentage de chance de muter les enfants etc.
• L'algorithme est implémentable sur la quasi totalité des calculatrices du concours. Pas forcément besoin du Python d'ailleurs, il faut des tableaux et/ou des chaînes de caractère. Avec plus ou moins de vitesse d'exécution cependant. Sur mon PC perso (Intel Xeon E5-2687W v4, 12 coeurs à 3,5Ghz) le score de 49.3173 est atteint dans la minute.
• J'aurais aimé cette année faire du recuit simulé comme Pavel mais je n'ai pas eu l'occasion de m'y mettre.
Si tu as une question plus précise n'hésite pas ! Merci à ceux qui détaillent leur méthode, on constate qu'on a tous des façons de faire différentes, c'est chouette !
(message original, conversation originale)

3. Avec redgl0w nous avons les Pokémons communs assaisonnés d'un Caninos et réduits à 1,03% de puissance chacun. Résultat 49.3195 points !

redgl0w a écrit :
J'ai remarqué que la fonction setst() n'était pas utilisé, et j'ai vite compris que elle servait à tester des codes. J'ai aussi remarqué que quand on change à peine le string qu'elle prend,le résultat change très peu. Grâce à cette propriété, j'ai essayé de bruteforce cette fonction, en changeant 3 caractères à chaque fois. Si le score est meilleur que l'ancien, alors je me remet à bruteforce, mais avec le nouveau code généré.


Abra 73.2 % Tentacool 18.56 % Florizarre 1.03 % Roucool 1.03 % Mystherbe 1.03 % Parasect 1.03 % Caninos 1.03 % Tartard 1.03 % Empiflor 1.03 % Dodrio 1.03 %

2. M4x1m3 qui a cherché entre autres sur HP Prime nous remet quasiment la même équipe, avec comme simple différence un Triopikeur en queue de peloton, qui lui apporte biené videmment 3 millièmes à maintenant 49.3198 points !

M4x1m3 a écrit :
En gros, ma recherche s'est faite en 4 parties :
• Réflexion
Bruteforce (intelligent)
• Exploitation d'un 'bug'
Bruteforce (intelligent) ×2

1 - Réflexion :
J'ai commencé par essayer de comprendre le script, renommer quelques variables. Je suis arrivé à ça.

On se rend vite compte que le script utilise un générateur de nombres pseudo-aléatoires (sûrement pour pouvoir valider les résultats de façon consistante et pour éviter de stocker toutes les infos), notamment avec les fonctions mseed et mrandom. Je me suis en-suite lancé dans l'exploration du code, notamment de la fonction getattack. On remarque que celle-ci défini le seed du générateur pseudo-aléatoire, et que celui-ci n'est utilisé que dans cette fonction. J'ai donc utilisé l'interpréteur Python pour extraire la valeur de l'attaque de tous les Pokémons, qui est ici, sous forme de tableur. À partir de là, mon cerveau commence à considérer les pokémons comme des chiffres. Bizarrement, Abra est OP. À partir de ça, et d'un peu de réflexion annexe (notamment sur la fonction qui calcule le score), j'ai pu avoir le premier score que j'ai rendu, qui était de 49.31488 (OKu0^gxh#_o"6""""""").

from math import *

def mmod(a, b):
  return a % b;
def getlinechars(o=False):
  c,k=2**31-1,1
  if k>=0:
    c=[53,o and 99 or 29,o and 509 or 21,31,32,c,c][k]
  return c
na = 21;
pokemons_in_team = [];
lnm = ["Bulbizarre","Herbizarre","Florizarre","Salameche","Reptincel","Dracaufeu","Carapuce","Carabaffe","Tortank","Chenipan","Chrysacier","Papilusion","Aspicot","Coconfort","Dardargnan","Roucool","Roucoups","Roucarnage","Rattata","Rattatac","Piafabec","Rapasdepic","Abo","Arbok","Pikachu","Raichu","Sabelette","Sablaireau","Nidoran F","Nidorina","Nidoqueen","Nidoran M","Nidorino","Nidoking","Melofee","Melodelfe","Goupix","Feunard","Rondoudou","Grodoudou","Nosferapti","Nosferalto","Mystherbe","Ortide","Rafflesia","Paras","Parasect","Mimitoss","Aeromite","Taupiqueur","Triopikeur","Miaouss","Persian","Psykokwak","Akwakwak","Ferosinge","Colossinge","Caninos","Arcanin","Ptitard","Tetarte","Tartard","Abra","Kadabra","Alakazam","Machoc","Machopeur","Mackogneur","Chetiflor","Boustiflor","Empiflor","Tentacool","Tentacruel","Racaillou","Gravalanch","Grolem","Ponyta","Galopa","Ramoloss","Flagadoss","Magneti","Magneton","Canarticho","Doduo","Dodrio","Otaria","Lamantine","Tadmorv","Grotadmorv","Kokiyas","Crustabri","Fantominus","Spectrum","Ectoplasma"]
mrandmax = 2147483647;
mrand = 0;
mfmax = 93;
nn = 78;

def mround(f):
  d = mmod(abs(f), 1)
  return (mfloor(abs(f))+(d>=.5))*(1-2*(f<0))

def mfloor(f):
  return round(f)-(round(f)>f)

def mceil(f):
  return round(f)+(round(f)<f)

def mseed(s):
  global mrand
  mrand=mmod(s,mrandmax)

def mrandom():
  mseed(mrand*16807)
  return float(mrand/mrandmax)

def muniform(mini,maxi):
  return mrandom()*(maxi-mini)+mini

def mrandint(mini,maxi):
  return mround(muniform(mceil(mini),mfloor(maxi)))

def f2mf(f):
  return mround(float(f * 93))

def mf2f(n):
  return float(n / 93)

def mbit(a,b):
  return mmod((a//(2**b)),2)

def getattack(pokemon_id,pts):
  global pkt
  mseed(42)
  for k in range(pokemon_id + 1):
    mrandom()
  a = mrandint(1,mrandmax);
  for j in range(na):
    if mbit(a,j)!=0:
      pkt[j]+=pts

def i2c(k):
  return chr(k+33)

def c2i(c):
  return ord(c)-33

def clean():
  global pokemons_in_team
  sum_of_priorities = 0;
  s = 0;

  # Calcule la somme des priorités.
  for current_pokemon in pokemons_in_team:
    sum_of_priorities += current_pokemon[1];


  for current_pokemon in pokemons_in_team:
    #
    current_pokemon[2] = f2mf(current_pokemon[1]/(sum_of_priorities or 1))
    s += current_pokemon[2]

    # Check si on fait du sale.
    if(current_pokemon[2] <= 0):
      pokemons_in_team.remove(current_pokemon)
      return clean()
  return s

def pk(pokemon_id, priority = 1, d=2):
  global pkt, pokemons_in_team
  pokemon_id -= 1 # Obtenir id dans tableau (1-94 transformé en 0-93)
  if pokemon_id >= 0 and pokemon_id < len(lnm): # Check si id valide
    new = True
    for k in range(len(pokemons_in_team)):
      if pokemons_in_team[k][0] == pokemon_id: # Check si pokemon déjà rentré
        new = False;
        pokemons_in_team[k][1] = max(priority, 0);
    if new and len(pokemons_in_team) < 10: # Si nouveau et pas d'autre pkm dans l'équipe
      pokemons_in_team.append([pokemon_id,max(priority, 0),0]) # Ajout dans l'équipe


  ptt = clean();
  pkt = [0] * 21;
  total_score = 0;
  input_string = "";
  for current_pokemon in pokemons_in_team:
    getattack(current_pokemon[0], current_pokemon[2]/ptt)
    input_string = i2c(current_pokemon[0]) + input_string + i2c(current_pokemon[2])
  for k in pkt:
    if(k):
      total_score += log(e+k*len(pokemons_in_team))
  return float(total_score), input_string

def setst(input_string):
  score = 0;
  pokemons_in_team[:] = [];
  num_pokemon = len(input_string) // 2;
  for k in range(num_pokemon):
    score = pk(
        c2i(
            input_string[num_pokemon - 1 - k]
        ) + 1,
        c2i(
            input_string[num_pokemon + k + len(input_string) % 2]
        ),
        k + 1 >= num_pokemon
    )
  return score

print("pk(n,p) pour rajouter\nle Pokemon n a ta main\navec p points d'attaque.")

2 - Bruteforce intelligent :
Après avoir compris le script, j'ai commencé à bruteforce. La première étape était de comprendre comment fonctionne la fonction setst. Celle-ci prend les caractères du milieu vers l'extérieur, les caractères à gauche sont les Pokémons et ceux à droite sont la priorité de chaque. J'ai donc compilé le code du défi comme module C avec Cython, par souci d'optimisation et pour gagner du temps. J'ai ensuite fait un petit script de bruteforce qui utilise de l'aléatoire et un peu de théorie de l'évolution (à chaque itération, on effectue une modification aléatoire sur final_string; si le score de newstring est supérieur à l'ancien, on recommence, mais avec la nouvelle chaine).

Deuxième soumission, cette fois 49.31596 (0^geuOK#h_e3"""""""").

Puis, après quelques jours de recherches, à aller nulle-part, pensant que je ne pourrais plus monter... la révélation arriva.

from random import randint;
import original; # original.py est le fichier contenant le code du défi.
import importlib;
import sys, os;
def blockPrint():
    sys.stdout = open(os.devnull, 'w');
def enablePrint():
    sys.stdout = sys.__stdout__;
final_string = '""""""""""""""""""""';
old_score = 0;

while True:
    num_chars = randint(1, 5);
    newstring = list(final_string);
    for i in range(num_chars):
        pos = randint(0, 19);
        char = chr(randint(32, 127));
        newstring[pos] = char;
    newstring = "".join(newstring);
    if (len(newstring) != 20):
        continue;
    blockPrint();
    importlib.reload(original);
    newscore = original.setst(newstring);
    enablePrint();
    if (newscore > old_score):
        old_score = newscore;
        final_string = newstring;
        print(final_string, newscore);

3 - Exploitation d'un ""bug"" :
Je ne sais pas si on peut qualifier ceci de bug, je ne l'appellerais pas un bug moi-même, plutôt une manière non conventionnelle de faire les choses... Je croyais, à la base, devoir me restreindre à la table ASCII. J'ai donc tenté d'entrer le caractère spécial 'DEL' (\x1f). Et, à ma grande surprise, ça a marché. J'ai donc continué, toujours plus haut, à faire des choses bizarres, en sortant de la table ASCII. Ma 3è participation est arrivée, 49.31975298152274 (OKSgu_#0h^"A""\x9f""""").

4 - Bruteforce (intelligent) ×2
Je croyais avoir tapé le max avec le 49.31975, mais voyant le score de pavel (un beau 49.32), je me suis motivé à continuer. Je suis donc reparti sur un bruteforce, avec le même script qu'avant, sauf que je l'ai modifié pour échapper les caractères hors-ASCII et pour utiliser les caractères entre 32 et 1023. Et là, après 20 minutes de bruteforce et 2-3 ajustements, je suis arrivé à mon 49.32078546995182 (0hKS#O^_gu""\260"""""D"). J'avais égalé le premier, j'étais heureux, après tant de taf.

Ce que j'ai pensé du défi :
Franchement, c'était cool. Il était pas trop dur, mais pas trop simple, et pouvait être, à mon avis, largement compris par un élève de Seconde. La quantité de réflexion et de travail nécessaire à l'obtention de la première place me semble assez importante pour éviter de trop nombreuses égalités (je ne suis pas sûr, mais je pense que 49.32 est un maximum qui ne peut être dépassé). Vivement l'année prochaine
(message original)


Abra 73.2 % Tentacool 18.56 % Florizarre 1.03 % Roucool 1.03 % Mystherbe 1.03 % Parasect 1.03 % Triopikeur 1.03 % Tartard 1.03 % Empiflor 1.03 % Dodrio 1.03 %

1. Enfin Pavel, sévissant sur TI-Planet et sur Planète Casio, a cherché entre autres à la fois sur Casio Graph 90+E et HP Prime pour nous apporter la touche finale. Même équipé, mais en réduisant les Pokémons annexes à seulement 1,02% de puissance chacun, il donne la toute puissance à Abra, pour un zénith de 49.3208 points !

Pavel a écrit :
Merci pour l'explication de ta méthode M4x1m3 !

J'ai mis mon code Python dans un dépôt git. Ce code trouve le meilleur score en quelques minutes et converge la plupart du temps vers 49.32057 ou 49.32079. Dans la suite, je vais essayer d'expliquer le fonctionnement de ce code.

from math import *
from random import *
from time import *

def mmod(a,b):
  return a%b
def getplatform():
  return 1
def getlinechars(o=False):
  c,k=2**31-1,getplatform()
  if k>=0:
    c=[53,o and 99 or 29,o and 509 or 21,31,32,c,c][k]
  return c
na,pkl,lnm=21,[],["Bulbizarre","Herbizarre","Florizarre","Salameche","Reptincel","Dracaufeu","Carapuce","Carabaffe","Tortank","Chenipan","Chrysacier","Papilusion","Aspicot","Coconfort","Dardargnan","Roucool","Roucoups","Roucarnage","Rattata","Rattatac","Piafabec","Rapasdepic","Abo","Arbok","Pikachu","Raichu","Sabelette","Sablaireau","Nidoran F","Nidorina","Nidoqueen","Nidoran M","Nidorino","Nidoking","Melofee","Melodelfe","Goupix","Feunard","Rondoudou","Grodoudou","Nosferapti","Nosferalto","Mystherbe","Ortide","Rafflesia","Paras","Parasect","Mimitoss","Aeromite","Taupiqueur","Triopikeur","Miaouss","Persian","Psykokwak","Akwakwak","Ferosinge","Colossinge","Caninos","Arcanin","Ptitard","Tetarte","Tartard","Abra","Kadabra","Alakazam","Machoc","Machopeur","Mackogneur","Chetiflor","Boustiflor","Empiflor","Tentacool","Tentacruel","Racaillou","Gravalanch","Grolem","Ponyta","Galopa","Ramoloss","Flagadoss","Magneti","Magneton","Canarticho","Doduo","Dodrio","Otaria","Lamantine","Tadmorv","Grotadmorv","Kokiyas","Crustabri","Fantominus","Spectrum","Ectoplasma"]
mrandmax,mrand,mfmax,nn,mp=2**31-1,0,93,getlinechars(True)-na,na//2
def mround(f):
  d=mmod(abs(f),1)
  return (mfloor(abs(f))+(d>=.5))*(1-2*(f<0))
def mfloor(f):
  return round(f)-(round(f)>f)
def mceil(f):
  return round(f)+(round(f)<f)
def mseed(s):
  global mrand
  mrand=mmod(s,mrandmax)
def mrandom():
  mseed(mrand*16807)
  return float(mrand/mrandmax)
def muniform(mini,maxi):
  return mrandom()*(maxi-mini)+mini
def mrandint(mini,maxi):
  return mround(muniform(mceil(mini),mfloor(maxi)))
def f2mf(f):
  return mround(float(f*mfmax))
def mf2f(n):
  return float(n/mfmax)
def mbit(a,b):
  return mmod((a//(2**b)),2)
def getattack(p,pts):
  global pkt
  mseed(42)
  for k in range(p+1):
    mrandom()
  a,pka=mrandint(1,mrandmax),""
  for j in range(na):
    if mbit(a,j)!=0:
      pka+="X"
      pkt[j]+=pts
    else:
      pka+=" -"[getplatform()>=5]
  return pka
def i2c(k):
  return chr(k+33)
def c2i(c):
  return ord(c)-33
def clean():
  global pkl
  t,s=0,0
  for l in pkl:
    t+=l[1]
  for l in pkl:
    l[2]=f2mf(l[1]/(t or 1))
    s+=l[2]
    if(l[2]<=0):
      pkl.remove(l)
      return clean()
  return s
def pk(n,p=1,d=2):
  global pkt, pkl
  n-=1
  if n>=0 and n<len(lnm):
    new=True
    for k in range(len(pkl)):
      if pkl[k][0]==n:
        new,pkl[k][1]=False,max(p,0)
    if new and len(pkl)<mp:
      pkl.append([n,max(p,0),0])
  ptt,pkt,t,st=clean(),[0 for k in range(na)],0,""
  for l in pkl:
    s=getattack(l[0],l[2]/ptt)
    if d:
      sn=" "+lnm[l[0]]
      if len(sn)>nn:
        sn=sn[:nn]
      print(s+sn)
    st=i2c(l[0])+st+i2c(l[2])
  for k in pkt:
    if(k):
      t+=log(e+k*len(pkl))
  if(d):
    if(d>=2):
      print("Bon score ? Si oui\nenvoie code suivant\na info@tiplanet.org :")
    print(""+st)
  return float(t)
def setst(st):
  s,pkl[:],n=0,[],len(st)//2
  for k in range(n):
    s=pk(c2i(st[n-1-k])+1,c2i(st[n+k+len(st)%2]),False)
  return s

pokemons = []

for l in range(94):
  mseed(42)
  for k in range(l + 1):
    mrandom()
  pokemons.append(mrandint(1, mrandmax))

def fast_score(code):
  pkt = [0.0 for l in range(21)]
  for k in range(10):
    p = code[19 - k] / 93.0
    for l in range(21):
      if pokemons[code[k]] & (1 << l):
        pkt[l] += p
  size = 0
  for k in range(10):
    if code[19 - k] > 0:
      size += 1
  score = 0.0
  for k in pkt:
    if k:
      score += log(e + k * size)
  return score

def random_pokemon(code):
  n = randint(0, 9)
  v = randint(0, 93)
  if not v in code[:10]:
    code[n] = v

def random_attack(code):
  score_max = fast_score(code)
  for k in range(300):
    while True:
      i = randint(10, 19)
      j = randint(10, 19)
      if i != j:
        break
    d = randint(-93, 93)
    vi = code[i] + d
    vj = code[j] - d
    if vi >= 0 and vi <= 93 and vj >= 0 and vj <= 93:
      code_next = code.copy()
      code_next[i] = vi
      code_next[j] = vj
      score_next = fast_score(code_next)
      if score_max < score_next:
        code[:] = code_next
        score_max = score_next

seed(time())

code = [0 for k in range(20)]
code[19] = 93

score = fast_score(code)

code_max = code.copy()
score_max = score

# find team using simulated annealing
t = 1.0
while t > 0.0001:
  t *= 0.999
  code_next = code.copy()
  random_pokemon(code_next)
  random_attack(code_next)
  score_next = fast_score(code_next)
  if score_max < score_next:
    code_max[:] = code_next
    score_max = score_next
    print('%.5f' % score_max, ''.join([chr(code_max[k] + 33) for k in range(20)]))
  delta = score_next - score;
  if delta >= 0 or random() < exp(delta / t):
    code[:] = code_next
    score = score_next

# find attack points using brute force
code_max = ''.join([chr(code_max[k] + 33) for k in range(20)])
for i in range(ord('2'), 256):
  for j in range(ord('e'), 256):
    code = code_max.replace('2', chr(i)).replace('e', chr(j))
    score = setst(code)
    if score_max < score:
      score_max = score
      print('%.5f' % score, code, i, j)

• Quelques observations :
Le calcul du score favorise les équipes de dix pokémons. Les points d'attaque sont des nombres rationnels. La somme de tous les points d'attaque est censée être normalisée à 1. Il y a un problème d'arrondi qui probablement peut être exploité pour contourner la normalisation.

• Optimisation du calcul du score :
J'ai commencé par optimiser le calcul du score. J'ai ajouté une liste 'pokemons' qui est remplie une fois au début du programme, contrairement à la fonction 'getattack()' qui calcule les compétences des Pokémons à chaque appel de cette fonction. J'ai aussi ajouté une fonction 'fast_score()' qui utilise cette liste.

pokemons = []

for l in range(94):
  mseed(42)
  for k in range(l + 1):
    mrandom()
  pokemons.append(mrandint(1, mrandmax))

def fast_score(code):
  pkt = [0.0 for l in range(21)]
  for k in range(10):
    p = code[19 - k] / 93.0
    for l in range(21):
      if pokemons[code[k]] & (1 << l):
        pkt[l] += p
  size = 0
  for k in range(10):
    if code[19 - k] > 0:
      size += 1
  score = 0.0
  for k in pkt:
    if k:
      score += log(e + k * size)
  return score

• Initialisation de l'équipe de Pokémons :
Au début du programme, mon équipe de Pokémons est composée d'un seul Pokémon Bulbizarre avec 93 points d'attaque.

code = [0 for k in range(20)]
code[19] = 93

• Recherche de la meilleure équipe de Pokémons :
J'ai utilisé l'algorithme de recuit simulé. Pour modifier l'état de mon équipe de Pokémons à chaque iteration de l'algorithme, j'ai implémenté deux fonctions: 'random_pokemon()' et 'random_attack()'. La fonction 'random_pokemon()' remplace aléatoirement l'un des Pokémons par un autre qui n'est pas encore présent dans l'équipe. La fonction 'random_attack()' choisit au hasard deux Pokémons de l'équipe et un delta, puis incrémente les points d'attaque de l'un de ces deux Pokémons par le delta et diminue les points d'attaque de l'autre de ces deux Pokémons du même delta. De cette manière, la somme des points d'attaque de tous les Pokémons de l'équipe ne change pas et reste toujours à 93. Les nouveaux points d'attaque sont conservés s'ils donnent un score plus élevé. Cette opération est répétée plusieurs fois.

Voici le code de ces deux fonctions.

def random_pokemon(code):
  n = randint(0, 9)
  v = randint(0, 93)
  if not v in code[:10]:
    code[n] = v
def random_attack(code):
  score_max = fast_score(code)
  for k in range(300):
    while True:
      i = randint(10, 19)
      j = randint(10, 19)
      if i != j:
        break
    d = randint(-93, 93)
    vi = code[i] + d
    vj = code[j] - d
    if vi >= 0 and vi <= 93 and vj >= 0 and vj <= 93:
      code_next = code.copy()
      code_next[i] = vi
      code_next[j] = vj
      score_next = fast_score(code_next)
      if score_max < score_next:
        code[:] = code_next
        score_max = score_next

• Recherche des meilleurs points d'attaque :
Dans la meilleure équipe de Pokémons trouvée par l'algorithme de recuit simulé, il y a dix Pokémons mais il n'y a que deux Pokémons qui ont plus d'un point d'attaque. Ces deux sont Abra et Tentacool.

Pour trouver les meilleurs points d'attaque pour Abra et Tentacool, je vérifie toutes les valeurs possibles et je garde celles qui apportent le meilleur score.

for i in range(ord('2'), 256):
  for j in range(ord('e'), 256):
    code = code_max.replace('2', chr(i)).replace('e', chr(j))
    score = setst(code)
    if score_max < score:
      score_max = score
      print('%.5f' % score, code, i, j)

Qu'est-ce que du recuit simulé ? Lors du concours de l'année dernière, je cherchais un aperçu des différentes méthodes d'optimisation et j'ai trouvé ce livre. Il contient une brève description de l'algorithme génétique, du recuit simulé et de nombreuses autres méthodes.
(message original, conversation originale)


Abra 73.47 % Tentacool 18.37 % Florizarre 1.02 % Roucool 1.02 % Mystherbe 1.02 % Parasect 1.02 % Triopikeur 1.02 % Tartard 1.02 % Empiflor 1.02 % Dodrio 1.02 %


Conclusion et choix des lots

Sur ce problème, on voit très clairement se dégager une tendance, avec tout le monde qui converge vers les mêmes équipes. Bravo ! Combien d'entre vous pariraient que c'est l'optimal sur tout l'espace ?

On va passer à l'attribution des lots. Comme la dernière fois, ça se passe dans les commentaires, ici et sur TI-Planet. Pavel est le premier à partir. Quand votre tour arrive, postez votre choix sur l'un des deux forums !

À bientôt sur Planète Casio !

Article connexe sur TI-Planet : Résultat concours de rentrée 2019 - défi de Python

Commentez cette news ! (16)

Publié par Lephenixnoir le

Voir toutes les news


La Revue des Projets — 168


Rdp.py

def getArticle():
print(Article)
pseudo = "Kikoodx"
NbrArticle = 1

edition = int(2.633*64)

print(f"Bienvenue dans cette nouvelle RdP ! La fameuse édition {edition} ! Aujourd'hui non pas 2, non pas 3, non pas 4 mais bien {NbrArticle} article !")

getArticle()
#Verification de l'article

print(f"Voici notre premier article du jour ! Fait par le grand, le majestueux {pseudo} ! Il nous annonce un événement inattendu que voici de ses propres mots :")

Kikoodx a écrit :
Le CPCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC !

print("Une annonce d'une telle importance, ça ne se refuse pas ! Je vous rappelle que vous pouvez voir le sujet et ses informations ici :
Le CPC #25 - Explorer des lieux inconnus !
bonne chance aux participants !"
)

NbrArticle+=-1

if NbrArticle== 0:

print("C'est déjà la fin de cette RDP ! Riche en émotion ! On se retrouve la semaine prochaine pour encore plus de fun ! ")

print("Cette semaine 12 programmes ont été postés :
Gimp de shadow15510
Gold Runner de elsalada
gamma function de piu58
DIFFSLIT de piu58
moonhoax de piu58
KARTPRJ de piu58
TorseurTransfer de fabcvlr
DIFFPARB de piu58
SchémaLiaisons de fabcvlr
Arrow de elsalada
Snake multimode de hazlyde
Pong Locate de hashby

Lire la RdP précédente : La Revue des projets #167
Besoin d'aide ? Une idée ? Un projet ? Un article !")

Sinon on fait des RDPs normales parfois allez voir ça !

Commentez cette news ! (22)

Publié par Tituya le

Voir toutes les news


Le CPC #25 - Explorer des lieux inconnus !


Après une longue pause, le concours CPC est de retour. Programmez un jeu d'ici Samedi prochain pour remporter une Graph 90+E !

Bienvenue à tous dans cette 25ème édition du concours historique de Planète Casio !

Les règles de cette édition ont été annoncées et détaillées la semaine dernière. Lisez-les en détail et plusieurs fois, car il y a de nombreux éléments importants !

Une fois que c'est fait, à l'attaque ! Le thème de cette fois est...

« Explorer des lieux inconnus »



Le concours est ouvert à tous. Voici un résumé des règles !

• Pour participer, vous devez créer un jeu sur le thème «Explorer des lieux inconnus».
• Vous devez poster votre jeu sur Planète Casio avant Samedi 23 Novembre à 18 heures. Vous avez le droit de modifier votre participation jusqu'à la deadline, mais plus après.
• Votre jeu doit être un programme en Basic Casio fonctionnel dans PRGM. Si vous le demandez dans la description, nous testerons votre jeu dans l'interpréteur C.Basic. Ça peut vous être utile si vous voulez gagner en vitesse, principalement.
• Votre jeu doit contenir une référence à un mois ou une saison de l'année : le nom d'un personnage, une ligne de dialogue, le contexte de l'histoire... vous avez le choix des armes.

Les programmes seront testés par Shadow15510 et moi-même, et notés sur le barème suivant :

• Gameplay : 3 points
• Graphismes et interface : 3 points
• Narration et univers : 2 points
• Level design : 1 point
• Interprétations originales, les bonus : 1 point

La signification de chaque catégorie est expliquée dans l'annonce des règles.

Les résultats seront annoncés le Samedi 30 Novembre et le participant ayant obtenu le meilleur score gagnera une Graph 90+E ! Là encore plus de détails dans l'annonce des règles.

Pour ceux qui ont réussi à lire jusqu'ici tout en se retenant de commencer à coder, voici mes conseils !

Ne négligez pas l'aspect scénaristique ! C'est facile de créer un univers simple, ne passez pas à côté.
La durée de vie et la qualité du code ne sont pas des critères !
Postez une version jouable minimale de votre jeu avant Jeudi soir !

Sur ce, happy coding et tous à vos calculatrices !

Commentez cette news ! (105)

Publié par Lephenixnoir le

Voir toutes les news


Lancement du vote du Jeu du Mois d'Octobre 2019


Bonjour à tous !
On se retrouve avec les basses températures pour le lancement du vote du Jeu du Mois d'Octobre 2019 !
Au total, nous avons 12 programmes à départager…


Le but est simple la liste des jeux postés durant le mois d'octobre vous est soumise, à vous de voter pour vos jeux préférés dans les commentaires en classant vos trois préférés.

Le gagnant aura le droit de placer la coupe dorée du Jeu du Mois en insérant un code dans sa description et il bénéficiera d'un mise en avant d'un mois en page d'accueil !

Règles

On ne peut voter qu'une seule fois
Le Top 3 peut contenir des lacunes : vous pouvez ne mettre aucun programme en face des notes.
On ne peut pas voter pour soi-même (Tout vote pour soi est considéré invalide et remplacé par une lacune.)

Exemple de classement : Nous avons les jeux Sony, Mario, Starwars, Zelda, Pizza. J'aime beaucoup Pizza, j'ai bien aimé joué à Mario, sans plus et je n'ai pas aimé les autres :
1-Pizza (3pts)
2-
3-Mario (1pt)
Si j'ai bien aimé Sony mais pas les autres et que je pense que Sony aurait pût être mieux ce vote serait approprié:
1-
2-Sony (2pts)
3-

Si j'ai adoré Mario, Sony et Zelda, mais que je préfère Mario aux deux autres et que je trouve que la prestation de Zelda est bâclée alors mon vote va ressembler à ça :
1-Mario (3pts)
2-Sony (2pts)
3-Zelda (1pt)



Les programmes sont triés par ordre alphabétique.

- Boutique de TheBloodFlow et une sorte de jeu de rôle où vous devez… Je vous laisse découvrir ça…

- Capitales de TheBloodFlow est une sorte de QCM où vous devez trouver les capitales des pays demandés.

- Culture G de TheBloodFlow est un QCM pour tester votre culture générale…

- DAR de TheBloodFlow est un die and retry où le but est de trouver le bon chemin vers la sortie.

- Fusée de Mastermokemo est un programme pour la fx CP-400 qui permet de simuler un tir de fusée avec de nombreux paramètres : étages, carburant, booster,…

- Geo de TheBloodFlow est un quizz sur des capitales du monde.

- GF Simulator de TheBloodFlow est un jeu de rôle où le but est de ne pas rompre avec votre petite amie… Combien d'heures (de minutes ? ) allez vous tenir ?

- Inutile Pack de TheBloodFlow est une compilation de trois mini-jeux que je vous laisse découvrir par vous-même…

- Master Mind de Hashby est un… master mind ! Le but est de découvrir la combinaison colorée déterminée au hasard par la calculatrice.

- Memory Quest de TheBloodFlow est un jeu où il vous faudra épeler un nombre, chiffre par chiffre.

- PlatGame de KikooDX est un jeu d'arcade dans lequel le joueur créer ses propres niveaux ! Mais avant de vous lancer à corps perdu dans votre génie créateur, essayer de finir les 7 niveaux déjà existants…

- Voiture de Friphazeph est un programme où vous manipulez une voiture : vous pouvez tourner, ralentir, et accélérer.

On se retrouve dans plus ou moins 7 jours pour les résultats. Merci d'avance à tout ceux qui votent !

Commentez cette news ! (3)

Publié par Shadow15510 le

Voir toutes les news


La Revue des Projets – 167


Bonjour à tous ! Avec quelques… heures de retard la RdP sort enfin avec trois articles ! Nous aurons, sur le plateau, KikooDX qui va nous parler de son Locate en Python, mais aussi Maxipoint14 qui avance dans son Fortcalc et enfin Shadow15510 et son jeu Aérocie qui continue de grandir !

Allez, c'est partit, place à KikooDX et son Locate ! Lorsque Casio a décider de mettre un port Python sur les nouveaux modèles, le port n'était pas fait pour être puissant, mais pour satisfaire les nouvelles exigences de Ministère de l'Éduc'Nat. De ce fait, on ne pouvait pas faire grand-chose… KikooDX a alors eu l'idée d'exploiter le module Python des Casio au maximum pour pemettre l'affichage de caractères à des coordonnées précises de l'écran. Ce script a ouvert les portes à des jeux de rôles en ASCII art. Bref, Locate et devenu le seul moyen (pour l'instant) de faire des jeux en Python on calc comme on dit dans l'jargon… Et la dernière version de cet outil, vient de sortir !

KikooDX a écrit :
RDP,
RDP...
RDP.
Bonjour.


Cette semaine, j'ai repris mes projets Python en main.

Locate.py 2.4 !
J'ai ajouté une septième ligne à Locate.py 2, rétrocompatible avec les anciens scripts.
Fonctionne avec Pad nativement.
Télécharger la dernière version ici.

J'ai fait la page de wiki expliquant le format de levels.py de mon projet SokobanCMP.
La page en question.
Télécharger SokobanCMP.
SokobanCMP dépend de Locate.py 2.3 ou supérieur ! (fonctionne avec la septième ligne de Locate.py 2.4)


RDP,
RDP...
RDP.
Au revoir.

Une bonne nouvelle ! N'hésitez pas à télécharger Locate et à l'inclure dans vos jeux Python !

Passons à Maxipoint14 ! Il y a quelques années et sorti le jeu Fortnite, devenu célèbre sur smartphone, évidement, les calculatrices sont un peu en reste et Maxipoint14 décide de remédier à ce problème en lançant le 28 février 2018 la première version de son jeu nommé Fortcalc… Jeu qui n'a de cesse de s'améliorer puisque presque 10 mois plus tard, de nouvelles mise à jour continue d'arriver :

Maxipoint14 a écrit :
bonjour,
après plusieurs mois de codage je sors enfin mon fortcalc
c'est un programme lourd mais qui en vaut la peine
Dessus on joue comme dans le jeu on a les système de vie, de stuff, de rareté, d'ennemi, de collecte de munitions, etc...
les commandes sont pas trop compliqués
in game on a 5 choix :
[1]trouver une maison, [2]collecter du bois(inutile en ce moment et va peut-être être retiré), [3]chercher un ennemi, [optn] inventaire, [^]quitter
in fight on est contre un ennemi les touches sont simples
(flèches) déplacer la vue du jeu, [EXE] attaquer (si on a 0 armes fait 0 dégâts), [-](inutile) utiliser objet, (-) recharger, [optn]accéder a l'inventaire
dans l'inventaire:
[Vars] jeter l'objet sélectionné
(1.2.3.4.5) sélectionner objet
[EXE]équiper l'objet
[-]utiliser l'objet si :bandage,kit de soins, potions de bouclier(petite et grande), gourde du brave
Le jeu est en 1.4 mais il y aura des mises à jour chaque semaine (soit pour rajouter des armes, soit pour mettre un mode de jeu temporaire
Actuellement, le mode de jeu temporaire est la ruée vers l'or, donc on n'obtient que du légendaire, et un mode sangsue (si tu tue un ennemi, tu gagnes 50 vie/bouclier) qui sera bientôt retiré
Le jeu marche que pour les Casio ayant les couleurs mais un jour il pourrait être compatible sur toutes les Casio
si vous voulez tester n'hésitez pas et pour faire progresser le jeu me donner des idées ou me reporter des bugs écrivez le sur les commentaires
Sur ce, bon jeu

Pour essayer cette dernière release, c'est par ici Et au passage, oubliez pas le Rédacteur !

On termine cette Revue avec Shadow15510, notre spécialiste des jeux de gestion et son dernier jeu en date : Aérocie ! Aérocie est un jeu de gestion où le but est de faire fructifier une compagnie aérienne. Il faudra donc acheter des avions, les entretenir, les faire voler et accomplir des missions diverses pour ne pas couler… Depuis quelques temps, le jeu n'a pas connu de mise à jour, mais Shadow15510 rattrape son retard…

Shadow15510 a écrit :
Hey !
Après quelques mois de relâche, je reprend Aérocie… Au programme une petite version 1.2 béta suivie dans quelques semaines d'une version 1.3 encore plus complète !


Menu d'accueil


La version 1.2b intègre une nouvelle fonctionnalité : vous pouvez voir l'heure d'arrivée de vos avions en vol. Le prix de carburant a été revu à la hausse et la difficulté du jeu dans l'ensemble, s'est légèrement accrue. Devant le succès du jeu, petit retour sur le jeu : Aérocie est un jeu réaliste avec ses 20 appareils aux caractéristiques fidèles à la réalité, plus de 50 aéroports aux coordonnées exactes, et sa gestion du temps réel. Aérocie est de loin le jeu le plus peaufiné que j'ai fait.


Zoom sur le DC-3 (Douglas Dakota DC-3)


De plus le jeu intègre des outils puissants comme le calculs de distance. La souplesse des systèmes de stockages des avions et des aéropots permet des mise à jours simple et rapides ! Aérocie fait également partit des rares jeux à avoir un title screen animé, c'est accessoire, mais, la qualité graphique du jeu s'en ressent… Le menu principal a un design original.


Écran principal du jeu


Le jeu est doté d'un outil de recherche d'aéroport par le nom, par groupe de lettres, voire même par lettre ! Le jeu permet un réglage de l'heure sans passer par un autre programme, et permet au joueur de designer lui-même le logo de sa compagnie ainsi que le nom de celle-ci !


Ma flotte d'appareil


Pour la version 1.3, je prévoie une nette hausse du nombre d'aéroports dans le monde, avec une densification en Europe, mais aussi en Afrique, en Amérique du sud, en Asie, et autour du détroit de Béring ! Au final, le but ultime et de vous lancer des défis comme : "Faites le tour du monde avec DC-3" ! Bien sûr, vous devrez soigneusement calculer vos étapes… Dans une mise à jour encore plus lointaine, un nouveau pack de missions sera disponible et peut-être même de nouveaux avions !

Présentation des aéroports dans l'outil de recherche par nom. Et outil de recherche par nom.


Cet article clos cette magnifique RdP ! Bon courage pour ce jeu qui malgré les mises à jour ne connait qu'un succès médiocre… N'hésitez donc pas à donner des retours sur la page de téléchargement !

Cette semaine 3 programmes ont été postés :
Chiffrement Hill de hashby
SokobanCMP de kikoodx
ES. Chap 1 de htuoi50

Lire la RdP précédente : La Revue des projets – 165
Besoin d'aide ? Une idée ? Un projet ? Un article !

Commentez cette news ! (15)

Publié par Shadow15510 le

Voir toutes les news


Annonce : CPC #25 du 16 au 23 Novembre


Le Concours canonique de Planète Casio, le CPC, est de retour la semaine prochaine pour sa 25ème édition. Développez un jeu sur le thème imposé pour tenter de gagner une Graph 90+E !

Salut à tous ! Ça fait longtemps qu'on n'a pas eu de CPC, alors reprenons en beauté.

Présentation du concours de programmation

Cette 25ème édition de l'événement suivra essentiellement les règles habituelles. Il s'agit de programmer pendant un temps limité un jeu sur un thème imposé. Les jeux sont ensuite testés par un ou deux jurés et évalués sur un barème fixé à l'avance. Pour cette édition, les règles sont les suivantes :

• N'importe qui peut participer (comme d'habitude).
• Le sujet sera annoncé le Samedi 16 Novembre à 18h, vous devez poster avant le Samedi 23 à 18h.
• Vous devez programmer un jeu en Basic Casio, sur Graph monochrome ou sur Graph 90+E.
• Les résultats seront annoncés le Samedi 30 Novembre.
• Pour pimenter le sujet, vous devrez faire une petite référence à un mois ou une saison (voyez plus bas).

Le lot de cette édition est un modèle spécial de Graph 90+E dans son emballage pédagogique. La calculatrice est à jour avec l'OS 3.30 et supporte Python, les programmes en couleurs, les e-acts, les add-ins et la connexion USB.


Il se peut aussi que j'ajoute des goodies (avant le début du concours) selon mon humeur. Ouvrez l'oeil...

Il n'y aucune condition pour participer, mais essayez d'annoncer votre participation dans les commentaires si possible, ça nous aide à nous organiser.

Participants déclarés jusqu'ici : Disperseur, Kikoodx, Massena, Palpatine_78, Alexot, Youstones, Filoji, Tituya, CaptainLuigi.

Barème d'évaluation des programmes

Les programmes de cette édition seront évalués par Shadow15510 et moi-même. Le barème est le suivant :

• Gameplay : 3 points
• Graphismes et interface : 3 points
• Narration et univers : 2 points
• Level design : 1 point
• Interprétations originales, les bonus : 1 point

La catégorie Gameplay comprend tout le fond de votre jeu. On cherche à savoir si le principe est inventif, si les règles sont bien équilibrées, si la difficulté est correctement ajustée, et si les éléments utilisés sont bien exploités, par exemple.

La catégorie Graphisme et interface concerne tout l'aspect visuel du jeu, ainsi que la gestion des contrôles. C'est là que vous pouvez exploiter tous vos talents d'artistes : Picture, animations, fluidité, tout est bon pour marquer des points. La clarté des contrôles fait aussi partie de cette catégorie.

Dans Narration et univers, on s'intéresse à la partie scénaristique de votre programme. Identifier des personnages, expliquer qui ils sont et pourquoi ils sont là, placer un cadre et donner des objectifs permet d'améliorer grandement le ressenti du joueur. Les pistes sont infinies !

La catégorie Level design consiste à évaluer la façon dont les maps, énigmes, puzzles, niveaux, épreuves sont conçus. Pour gagner des points ici, il faut exploiter à fond les éléments introduits (par exemple des plateformes mouvantes dans un plateformer). Dans le rare cas où cette catégorie ne s'applique pas bien à votre jeu, on en discutera directement avec vous.

Et enfin, les Bonus sont un point supplémentaire attribué pour diverses raisons : éléments positifs ne rentrant pas dans le barème, interprétations originales ou inventives du sujet imposé, utilisation habile de la référence obligatoire (ci-dessous), etc.

J'attire votre attention sur deux points importants :

La durée n'est pas un critère. Visez des jeux amusants plutôt que des jeux longs !
La qualité du code n'est pas un critère. Allez à l'essentiel !

Référence à un mois ou une saison

Votre jeu doit contenir un petit clin d'oeil à un mois ou une saison de l'année. Quelque chose de tout simple suffit. Par exemple, un personnage peut s'appeller Autumn, ou avoir une ligne de dialogue évoquant les vacances de Février, ou l'histoire peut simplement se passer à Noël.

Le but est de vous aider à établir une ligne scénaristique à partir d'un détail, si vous n'êtes pas très inspiré(e).

Conclusion

Il n'y a pas besoin d'aller chercher le diable pour participer. Un programme en mode texte convient tout à fait et peut obtenir des gros points en graphismes s'il est bien conçu. Jouez avec nos attentes !

À Samedi prochain pour le grand lancement de ce CPC !

Commentez cette news ! (44)

Publié par Lephenixnoir le

Voir toutes les news


Résultat du concours de rentrée 2019 - Épreuve de tracé !


Salut à la communauté ! Il est l'heure de passer en revue les participations, méthodes et classement de la première épreuve de notre concours de rentrée annuel.

Le sujet de l'épreuve de tracé était de reproduire avec le code le plus court possible l'image suivante sur fx-92 Scientifique Collège+.


Comme l'année dernière, nous avons reçu pas moins de 93 participations de 18 personnes, présentant de nombreuses techniques pour court-circuiter le dessin et tracer toujours avec toujours moins.

La majorité d'entre vous a travaillé sur la fx-92 SC+ ou son émulateur (15), avec quelques participations en Scratch (1) et Python (2) qui ont été traduites semi-automatiquement vers le langage de la fx-92 SC+.

Alors voyons dès maintenant le classement et les méthodes que vous avez utilisées pour parvenir à vos fins ! Nous avons rédigé un commentaire succinct sur chaque programme avec l'animation du tracé qu'il réalise. Plusieurs d'entre vous ont déjà décrit leurs méthodes en détail. N'hésitez pas à ajouter vos techniques dans les commentaires !

(Pour le choix des lots, voyez à la fin de l'article !)


Le classement

17. On commence tranquillement avec la participation de CaptainLuigi. La façon la plus naturelle d'attaquer une série de rectangles est de tourner de 90° entre chaque trait. On verra vite que ça se chaîne assez bien malgré les irrégularités. Ici l'oubli dommage c'est le curseur, qui dessine beaucoup de pixels superflus. Quatre personnes en tout ont omis de le masquer en le déplaçant hors de l'écran...


16. Avec Leno (TI-Planet, Planète Casio) sur fx-92+ Spéciale Collège, on commence à trouver les techniques permettant de tracer rapidement les cercles en profitant du fait que la position du crayon et l'angle d'orientation de la tortue sont bien plus précis que 1 pixel ou 1 degré. On peut donc tourner de 18.43 degrés ou avancer de 3.2 pixels à son avantage pour tracer tout le cercle à l'aide d'une boucle régulière. La même technique est utilisée pour la série de Z, qui n'est malheureusement pas au bon endroit par rapport au cercle. 326 points.



15. On fait maintenant un bond dans le score, jusqu'à 1344 points points avec Ptitjoz (TI-Planet, Planète Casio). Ici on a les rectangles complets, les cercles, les Z et le texte. Ici on se permet de reproduire une image approximative pour gratter des points : c'était le but de l'épreuve. Dans cette participation, pas de rotation ou pas avec des valeurs décimales, le cercle intérieur rate donc quelques pixels. Pour les rectangles, c'était l'effet attendu : on pensait que les deux pixels en trop valaient les instructions économisées. Voyons ce que vous en avez pensé...


Ptitjoz a écrit :
Je vous explique comment je voulais procéder... Voila la méthode mais faute de temps (je n'en expliquerai pas les raisons... ) je n'ai fait que quelques tests que j'aurais essayé d'optimiser. Une de mes participations où l'on peut voir un peu de ce code est : ici. Le principe retenu est que chaque pixel dessiné vaut 1 et chaque pixel non dessiné vaut 0. Mon idée était d'encoder l'image colonne par colonne en transformant le binaire obtenu en décimal et de le stocker dans une variable. Ensuite avec une boucle pour chaque colonne je décodais la variable en binaire point par point et j'affichai le pixel si la valeur était 1 sinon ne je l'affichais pas. Le code parlera mieux que mes explications.
Voilà, point final pour cette année. Merci à tous.
(message original)


14. Juste au-dessus de ce score, Zocipal attaque justement les rectangles au pixel près. La technique est la même, sauf que les rectangles font maintenant 5 côtés pour ainsi dire. Les cercles sont cependant plus manuels, avec essentiellement des angles droits et des levées et posées fréquentes de stylo. Ça prend de la place mais les points le valent bien, puisque chaque pixel rapporte 10 points contre 1 seul point perdu par octet. 1367 points.



13. Toujours au coude-à-coude, Edgar13 prend la place suivante. On voit ici les premières attaques sérieuses sur le sprite de Link, pour l'instant en exploitant les lignes continues les plus longues dans l'image. C'est un bon moyen d'accumuler les pixels à moindre coût, sans tenter de reproduire toute l'image. On a la même stratégie pour réduire le texte en utilisant des formes simples à programmer, appliquée finement. Bien joué ! 1418 points.


Edgar13 a écrit :
Pour les rectangles j'ai fait très simple juste des petites boucles de 2:

2→M
10→F
Aller à x=M; y=F
Stylo écrit
S'orienter à 270 degrés
Répéter 2
  Avancer de 4 pixels
  Tourner de ↺ -90 degrés
  Avancer de 8 pixels
  Tourner de ↺ -90 degrés

Stylo relevé
Aller à x=4; y=8
Stylo écrit
Répéter 2
  Avancer de 7 pixels
  Tourner de ↺ -90 degrés
  Avancer de 5 pixels
  Tourner de ↺ -90 degrés

Stylo relevé
Aller à x=7; y=4
Stylo écrit
Répéter 2
  Avancer de 6 pixels
  Tourner de ↺ -90 degrés
  Avancer de 5 pixels
  Tourner de ↺ -90 degrés

Stylo relevé

Pour les Z par contre j'ai pas mal réfléchi et je les ai tracé avec X et Y, ce qui m'a donné un code assez court:

16→M
Aller à x=M; y=F
Stylo écrit
2→A
Répéter 6
  F-(A-1)→F
  Aller à x=M; y=F
  S'orienter à 0 degrés
  Avancer de A pixels
  Si A<7 Alors
    A+1→A
  Fin

Ensuite j'ai surtout essayé de faire des rectangle avec des boucles :

Avancer de -1 pixels
Aller à x=16; y=-17
Avancer de 6 pixels
Stylo relevé
Aller à x=42; y=-19
Stylo écrit
Répéter 2
  Avancer de 3 pixels
  Tourner de ↺ 90 degrés
  Avancer de 9 pixels
  Tourner de ↺ 90 degrés

Stylo relevé
Aller à x=40; y=-5
Stylo écrit
Aller à x=32; y=3
Stylo relevé
Aller à x=67; y=-15
Stylo écrit
Répéter 2
  Avancer de 2 pixels
  Tourner de ↺ 90 degrés
  Avancer de 4 pixels
  Tourner de ↺ 90 degrés

Stylo relevé
Aller à x=41; y=-5
Stylo écrit
Répéter 4
  Avancer de 3 pixels
  Tourner de ↺ 90 degrés

Stylo relevé
Aller à x=63; y=-13
Stylo écrit
Répéter 3
  Avancer de 2 pixels
  Tourner de ↺ 90 degrés

Stylo relevé

Ensuite j'ai dessiné le 2019 de façon basique et simple juste en avançant et en relevant le stylo pour passer à une autre lettre :

Aller à x=63; y=-13
Stylo écrit
Répéter 2
  Avancer de 2 pixels
  Tourner de ↺ 90 degrés

Stylo relevé
Aller à x=71; y=-15
Stylo écrit
S'orienter à 0 degrés
Avancer de 2 pixels
Avancer de -1 pixels
Tourner de ↺ 90 degrés
Avancer de 4 pixels
Stylo relevé
Aller à x=75; y=-15
S'orienter à 0 degrés
Stylo écrit
Avancer de 2 pixels
Tourner de ↺ 90 degrés
Avancer de 4 pixels
Tourner de ↺ 90 degrés
Répéter 3
  Avancer de 2 pixels
  Tourner de ↺ 90 degrés

Stylo relevé
Aller à x=38; y=3
Stylo écrit
S'orienter à 0 degrés
Répéter 2
  Avancer de 3 pixels
  Tourner de ↺ 90 degrés
  Avancer de 1 pixels
  Tourner de ↺ 90 degrés

Stylo relevé
Aller à x=35; y=0
Stylo écrit
Avancer de 9 pixels
Tourner de ↺ -90 degrés
Avancer de 6 pixels

Et pour finir j'ai fait sortir la flèche:

Stylo relevé
Avancer de 99 pixels

Mais j'ai eu un problème de temps et j'aurais pu faire mieux il me restait 200 octets.


12. LePetitMage nous propose la première participation en Scratch (lien direct t13.sb3). Une fois retranscrite sur fx-92+ Spéciale Collège, on retrouve plusieurs éléments précédents : sacrifier des pixels inutiles sur les rectangles, tailler dans le vif sur le sprite de Link, et on a même la chance d'apercevoir un brin d'herbe (tiré des premières générations de Pokémon !) au-dessus du 2019. Les techniques pour tracer les cercles avec des avancées décimales sont plus subtiles à reproduire sur Sractch, qui a des règles de rendu un peu différentes... et également un plus grand écran. On s'en sort quand même avec un score très honorable, malgré la traduction, l'écran tronqué et le curseur en plus. Bel effort ! 1610 points.


LePetitMage a écrit :
Bonjour,
je suis le dernier parmi ceux qui ont un lot et je vous présente ici ma méthode.
Merci à Lephe pour l'animation trouvable ici : https://i.imgur.com/Tx4ABSR.gif

J'ai commencé par les rectangles qui s'emboîtent en définissant un pixel qui sera l'origine d'un repère.

Stylo écrit
Aller à x=0; y=-7
Avancer de 5 pixels
Avancer de -2 pixels
Aller à x=3; y=-10
Avancer de 5 pixels
Aller à x=8; y=-4
Avancer de -5 pixels
Avancer de 2 pixels
Aller à x=5; y=0
Avancer de -5 pixels
Aller à x=0; y=-2
Avancer de 3 pixels
Aller à x=3; y=2
Avancer de -8 pixels
Aller à x=-5; y=-2
Avancer de 4 pixels

Vous avez sûrement remarqué que :
-je n'ai pas utilisé de "Tourner de ..." pour économiser des lignes. Pour se déplacer vers la droite ou vers la gauche, j'avance d'un nombre positif ou négatif de pixels. Pour monter ou descendre, j'écris les coordonnées en fonction de l'origine du repère. C'est une technique que je vais utiliser un peu partout.
-j'avance parfois d'un nombre de pixel puis je recule tout de suite après. C'est pour gratter les pixels des "cornes" entre les rectangles.

J'ai continué avec les Z, où il n'y a pas spécialement de remarque à faire.

Avancer de 1 pixels
Aller à x=17; y=2
Stylo écrit
1→A
√(2→B
Avancer de 1 pixels
Répéter 5
  A+1→A
  S'orienter à 225 degrés
  Avancer de B×(A-1) pixels
  S'orienter à 0 degrés
  Avancer de A pixels

Aller à x=17; y=-19
Avancer de 6 pixels
Aller à x=17; y=-25
Avancer de 5 pixels

Et pour les deux cercles, je ne me suis pas embêté avec les angles et j'ai laissé de côté 4 pixels.

Aller à x=0; y=-26
Répéter 4
  Stylo écrit
  Avancer de 3 pixels
  Tourner de ↺ 45 degrés
  Avancer de B pixels
  Tourner de ↺ -45 degrés
  Avancer de 1 pixels
  Tourner de ↺ 45 degrés
  Avancer de B×2 pixels
  Tourner de ↺ 45 degrés
  Avancer de1pixels
  Tourner de ↺ -45 degrés
  Avancer de B-B÷Abs(B pixels
  Stylo relevé
  Avancer de B÷Abs(B pixels
  Tourner de ↺ 45 degrés


Aller à x=0; y=-24
Répéter 4
  Stylo écrit
  Avancer de 3 pixels
  Tourner de ↺ 45 degrés
  Avancer de B×3-B÷Abs(B pixels
  Stylo relevé
  Avancer de B÷Abs(B pixels
  Tourner de ↺ 45 degrés

J'ai continué avec le link en ne dessinant que les diagonales les plus généreuses en points (vous le remarquerez facilement dans l'animation de Lephe).

Aller à x=43; y=-26
Stylo écrit
Aller à x=43; y=-13
Avancer de 2 pixels
Avancer de -4 pixels
Aller à x=33; y=-5
Aller à x=40; y=2
Avancer de 4 pixels
Aller à x=44; y=-4
Avancer de -7 pixels
Aller à x=37; y=-2
Avancer de 5 pixels
Stylo relevé
Avancer de 1 pixels
Aller à x=46; y=-26
Stylo écrit
Aller à x=46; y=-12

J'ai ensuite dessiné 2019 en sacrifiant quelques pixels (certains non dessiné et d'autres en plus pour éviter les "Stylo levé" et "Stylo écrit").

Aller à x=64; y=-19
Stylo écrit
Avancer de 2 pixels
Aller à x=66; y=-21
Avancer de -2 pixels
Aller à x=64; y=-23
Avancer de 6 pixels
Aller à x=70; y=-19
Avancer de -2 pixels
Aller à x=68; y=-23
Avancer de 5 pixels
Aller à x=73; y=-19
Aller à x=73; y=-23
Avancer de 5 pixels
Aller à x=78; y=-19
Avancer de -2 pixels
Aller à x=76; y=-21
Avancer de 1 pixels

Et pour finir, le coeur avec la même technique que les rectangles mais aussi en se déplaçant sans tourner.

Aller à x=71; y=-14
Stylo écrit
Aller à x=71; y=-11
Aller à x=73; y=-9
Avancer de 1 pixels
Aller à x=74; y=-11
Aller à x=71; y=-14
Aller à x=68; y=-11
Aller à x=68; y=-9
Avancer de 1 pixels
Aller à x=71; y=-11

J'ai participé sur Scratch, l'avantage est que je suis plus à l'aise sur Scratch et que c'est plus amusant de glisser des blocs.
Par contre, je ne savais pas que plusieurs bouts de mon dessin seraient en dehors de l'écran et que ces pixels ne sont pas compté, et que la conversion depuis Scratch implique de rajouter des lignes.
(message original)

11. Et on embraye directement sur la première participation Python par Afyu. Le code original (lien direct t14.py) trace l'image complète, mais fait 2094 octets une fois traduit. Il faut donc arrêter le script à un peu plus de la moitié. La plupart du tracé utilise des instructions simples et n'hésite pas à utiliser «Aller à» comme source primaire de déplacement, plutôt que «Avancer de». Si les changements de direction sont trop fréquents, c'est en effet bien plus court (5 octets plus la taille des coordonnées contre 6 octets plus la taille de l'angle et celle du pas), ce qui n'était pas évident en première approche. 1635 points.


Afyu a écrit :
Mon script n'est clairement pas optimisé, et j'en suis conscient. D'abord, j'ai découvert le défi seulement quelques jours avant la fin du concours. J'ai voulu effectuer quelques tests sur une fx92+ sc mais je n'en ai pas, je ne connais personne qui en a une et je n'ai pas pu essayer sur émulateur parce que mon Linux n'est pas à jour et je ne peux pas installer Wine. Ce n'est pas une excuse mais ça explique certains (nombreux) points plutôt impertinents et peu optimisés. J'ai donc écrit mon script en Python avec le module Turtle, en utilisant le support prévu pour la NumWorks proposé pour le concours.

Je cache la tortue (et j'aurais bien aimé qu'une fonction existe pour cacher la flèche sur la fx92+, dommage). Je commence avec le zigzag (éclair ?). La commande fd() correspond à "Avancer de".

  goto(27,7)
  pendown()
  i=1
  fd(1)

Pour tracer le zigzag, les déplacements horizontaux sont faits avec fd(), et les déplacements en biais sont faits avec goto(x,y). Ça économise des changements de direction (et encore une fois, sans pouvoir vérifier sur une vraie fx92+, je ne me suis pas risqué à choisir un angle ou un pas qui risquaient de ne pas convenir ou d'être interprété différemment par une fx92+).
On souhaite descendre de 1, puis de 2, puis de 3, puis de 4... Donc le décalage par rapport au début du zigzag en haut est de 1, puis de 1+2, puis de 1+2+3, puis de 1+2+3+4...
Le décalage total vertical est donc la somme des premiers entiers naturels, qui peut s'écrire sous la forme : 1+2+3+...+n=n(n+1)/2, d'où le i*(i+1)/2.
J'ai envisagé de remplacer cette fraction par un simple goto(28,y-i) mais je ne savais pas comment écrire ça, sachant que dans mon script en Python il n'y a pas de y et je ne suis pas sûr que Turtle comprenne ce genre d'instruction avec y. Ah, si seulement j'avais eu une fx92+ sous la main ! Le dernier virage est en dehors de la boucle pour éviter d'avancer de 7.

  while i<7:
    fd(i)
    goto(28,7-i*(i+1)/2)  #goto(28,y-i)
    i=i+1
  fd(6)
  goto(28,-20)
  fd(6)
  penup()

De même, pour les polygônes, les déplacements horizontaux sont faits avec fd() et les déplacements verticaux sont faits avec goto(x,y).

  goto(14,-1)
  pendown()
  goto(14,1)
  fd(5)
  goto(19,-5)
  fd(-5)
  goto(14,-2)
  penup()
  goto(16,0)
  pendown()
  goto(16,-2)
  fd(-5)
  goto(11,5)
  fd(3)
  goto(14,7)
  fd(-8)
  goto(6,3)
  fd(8)
  goto(14,5)
  fd(2)
  goto(16,1)
  penup()

Pour le 2019, j'ai tracé segment par segment, avec une boucle pour tracer le "0" en deux fois et une autre pour tracer le haut du "9" en 4 fois.

  goto(74,-14)
  pendown()
  fd(3)
  goto(77,-16)
  fd(-2)
  goto(75,-18)
  fd(2)
  penup()
  fd(2)
  pendown()
  for k in range(2): #répéter 2
    fd(2)
    lt(90)
    fd(4)
    lt(90)  #la tortue regarde de nouveau vers la droite (orientation à 0°)
  penup()
  fd(3)
  pendown()
  fd(3)
  fd(-1)
  lt(90)
  fd(4)
  goto(83,-15)
  penup()

  goto(86,-18)
  pendown()
  lt(-90)
  fd(3)
  lt(90)
  fd(2)
  for l in range(4): #répéter 4
    fd(2)
    lt(90)
  penup()

Pour la fée, j'ai enchaîné des segments. Je me pose en bas, je trace le segment vertical, puis je pars à droite, je redescends en biais, je repars à gauche en biais et je termine en revenant vers le milieu. Les déplacements verticaux sont faits avec fd() et je profite du fait que la tortue regarde vers le haut (orientation 90°) à la fin du tracé du "2019".

  goto(82,-10)
  pendown()
  fd(4)
  goto(84,-4)
  goto(85,-4)
  fd(-2)
  goto(82,-9)
  goto(79,-6)
  fd(2)
  goto(80,-4)
  goto(82,-6)
  penup()

Pour les cercles, j'ai utilisé des boucles et de trop nombreux déplacements de 1. Faute de pouvoir tester sur une vraie fx92+ ou sur émulateur, j'ai préféré m'assurer que le tracé était correct et je n'ai pas pu trouver (ni même chercher) le pas et l'angle qui auraient permis de tout tracer avec une seule boucle.
J'ai tout de même utilisé l'astuce que le grand cercle ressemble au petit mais comme si on l'avait découpé en 4, si on avait éloigné les 4 morceaux et si on avait ajouté quelque chose entre deux morceaux adjacents. D'où la partie "Si q>4" et la partie "Si q=5" qui permet de se décaler pour se mettre sur le tracé du grand cercle.

  goto(8,-12)
  setheading(0)     # on oriente la tortue à 0° (elle regarde vers la droite)
  q=1
  while q<9: # répéter 9
      if q==5:
        goto(6,-12)
      pendown()
      fd(1)
      lt(90)
      fd(1)
      lt(-90)
      if q>4:
        penup()
        fd(1)
        lt(90)
        pendown()
        fd(1)
        penup()
        fd(1)
        lt(-90)
        pendown()
        fd(1)
      fd(1)
      penup()
      lt(90)
      fd(1)
      lt(-90)
      pendown()
      fd(4)
      penup()
      fd(1)
      lt(-90)
      q=q+1

Pour Link, j'ai essayé de le tracer segment par segment (comme une ligne brisée) en relevant le stylo un minimum de fois. Les changements d'orientation très nombreux sont remplacés par des goto(x,y). Et dans l'histoire, j'ai oublié 2 pixels vers le haut à gauche.

  setheading(90)    #on oriente la tortue à 90° (donc elle regarde vers le haut)
  goto(54,-4)
  pendown()
  goto(57,-7)
  goto(53,-11)
  fd(-2)
  goto(57,-13)
  fd(-8)
  goto(56,-22)
  goto(55,-22)
  goto(54,-21)
  fd(8)
  goto(58,-13)
  fd(2)
  goto(57,-10)
  fd(1)
  goto(54,-9)
  goto(56,-7)
  fd(4)
  goto(55,-2)
  goto(56,-1)
  fd(1)
  goto(57,1)
  fd(3)
  goto(54,7)
  goto(50,7)
  goto(48,5)
  goto(47,5)
  goto(46,4)
  fd(-3)
  goto(45,1)
  goto(44,0)
  goto(52,-8)
  goto(54,-8)
  goto(51,-8)
  goto(49,-6)
  goto(47,-6)
  goto(46,-5)
  fd(1)
  goto(47,-4)
  fd(3)
  goto(49,-3)
  goto(54,-3)
  goto(53,-4)
  fd(-4)
  goto(52,-7)
  goto(54,-5)
  penup()
  goto(48,5)
  pendown()
  fd(-2)
  lt(-90)
  fd(2)
  penup()
  fd(1)
  pendown()
  fd(4)
  lt(90)
  fd(2)
  lt(90)
  fd(1)
  penup()
  goto(56,3)
  pendown()
  goto(53,0)
  fd(3)
  goto(48,2)
  penup()
  goto(50,-2)
  pendown()
  goto(50,1)
  fd(-3)
  goto(53,-1)
  penup()

  goto(45,2)
  pendown()
  goto(47,0)
  penup()
  goto(48,4)
  pendown()
  goto(50,6)
  penup()

Pour le vaisseau (ou logo, ou je sais pas trop quoi ), j'ai utilisé la symétrie centrale de la zone centrale mais en traçant la figure ligne par ligne (comme des lignes horitontales de pointillés) puis j'ai tracé les deux parenthèses et enfin les deux traits obliques manquants.

  goto(74,2)
  setheading(0)
  q=0
  while q<2:
    pendown()
    fd(1)
    penup()
    fd(6)
    if q==0:
      pendown()
    fd(1)
    penup()
    fd(6)
    pendown()
    fd(1)
    penup()
    goto(90,-3)
    lt(180)
    q=q+1
  goto(79,1)
  for r in range(2):
    for s in range(2):
      pendown()
      fd(2)
      penup()
      fd(1)
    goto(85,-1)
    lt(180)
  goto(76,0)
  for t in range(2):
    pendown()
    fd(3)
    penup()
    fd(5)
  goto(74,-1)
  for u in range(2):
    pendown()
    fd(2)
    penup()
    fd(11)
  goto(74,-3)
  for v in range(2):
    pendown()
    setheading(90)
    fd(4)
    penup()
    goto(90,-3)
  goto(82,-3)
  pendown()
  fd(1)
  penup()

Pour les herbes, je parcours 3 fois une boucle qui met à jour les coordonnées du point de départ à chaque fois.

  a=42
  b=-15
  w=0
  while w<3:
    goto(a+2,b)
    pendown()
    goto(a,b+2)
    penup()
    goto(a+4,b)
    pendown()
    goto(a+6,b+2)
    penup()
    goto(a+3,b+2)
    pendown()
    fd(2)
    penup()
    if w==0:
      a=61
      b=1
    if w==1:
      a=63
      b=-22
    w=w+1


10. Juste au-dessus, on rentre dans le top 10, avec Amiga68000 sur la fx-92+ Spéciale Collège. Et là, surprise ! Un programme composé en moitié d'une longue suite de «Aller à» explicites remporte pas moins de 1722 points. Quelques angles décimaux sont utilisés pour les cercles, mais c'est tout. Ce programme simple en apparence fait facilement tomber la moitié du sprite de Link. Difficile de savoir si la séquence de lignes a été générée automatiquement ou cherchée à la main. En tous cas c'est une piste que l'on attendait fermement et qui a servi à choisir le barème de l'épreuve. Eh oui, même à 1 contre 10, le code compliqué coûte vite cher !


Amiga68000 a écrit :
Je vous partage mon code pour faire les carrés et les cercles. Pour les carrés j'ai pas eu le temps de regarder l'utilisation des boucles. Pour les cercles, j'ai utilisé des boucles imbriquées. Les 4 pixels dans les coins du cercle ne sont pas tracés, je suis preneur d'un code plus optimum. Le gros pâté c'est le pointeur flèche ! script


Voici le code pour les ZZZ : script. J'ai utilisé les boucles avec des coordonnées (x,y) le mieux aurait été d'utiliser les (orientation, déplacement). Là encore je suis preneur d'optimisation.

Chapeau à celui qui a presque tout tracé.
(message original)


9. À la 9ème place, Éléonore D. score 1958 points en combinant la simplicité des «Aller à» avec trois boucles intelligentes. La première permet de tracer la décoration au-dessus du 2019, et la touffe d'herbe d'un coup en profitant de la symétrie. Les deux autres sont des formes super compactes pour le tracé des cercles : 36 pas de 1.12 pixel séparés de 9.9 degrés chacun, et 28 pas de 1 pixel séparés de 12.75 degrés chacun. Cela laisse amplement la place de s'attaquer à Link.


Éléonore D. a écrit :
Pour ma part,je rien fais d'extraordinaire, j'ai beaucoup utilisé de ''aller à''.


8. Une bonne centaine plus haut à 2070 points, Clément C. propose un programme quasi-identique qui se distingue en choisissant mieux les parties de Link et en profitant de l'espace libéré pour tracer plus en détail la décoration symétrique sur la droite.


Clément C. a écrit :
J'ai essayé de faire de mon mieux(donc rien de bien compliquer) pour les cercles j'ai fais comme Amiga68000.


7. On fait ensuite un nouveau bond pour atteindre la 7ème place où le premier participant à cette épreuve, Encephalogramme, atteint les 2227 points. Ici moins de souci de finesse, on factorise le dessin dans des boucles et on couvre les pixels le plus vite possible. On remarque une boucle bien compacte pour le tracé de plusieurs rectangles à la suite. Les octets économisés compensent les pixels sacrifiés. Comme quoi on peut aller loin avec des outils simples : bravo !


Encephalogramme a écrit :
Je pense que ma méthode est assez basique, et mon but était donc d'optimiser avec des boucles et en choisissant les meilleurs morceaux du dessin.

Je mets ici les parties du code de façon séparées pour mieux visualiser

Cette portion du code permet de tracer le petit et le grand cercle, avec des valeurs étranges, comme "avancer de 4.5 pixels", mais ça marche :

Répéter 4
  Avancer de 3 pixels
  Tourner de ↺ -34 degrés
  Avancer de 4,5 pixels
  Tourner de ↺ -31 degrés
  Avancer de 3 pixels
  Tourner de ↺ -26 degrés

S'orienter à 0 degrés
Stylo relevé
Aller à x=x; y=y-2
Stylo écrit
Répéter 4
  Avancer de 1 pixels
  Tourner de ↺ -14 degrés
  Avancer de 4 pixels
  Tourner de ↺ -60 degrés
  Avancer de 2,5 pixels
  Tourner de ↺ -16 degrés

Ici, ça permet de tracer les Z avec des boucles, encore une fois pour gagner de la place :

1→A
Répéter 5
  Aller à x=x+A; y=y
  Aller à x=x-A; y=y-A
  A+1→A

Répéter 2
  Aller à x=x+A; y=y
  Aller à x=x-A; y=y-A

Aller à x=x+A; y=y
Stylo relevé
Aller à x=x-28; y=y+27

Le code qui suit permet de tracer les 3 rectangles au-dessus des cercles, le but est de faire ça en peu de place, même si il faut pour cela tracer des pixels qui devaient rester blancs :

Répéter 2
  Avancer de 8 pixels
  Tourner de ↺ -90 degrés
  Avancer de 4 pixels
  Tourner de ↺ -90 degrés

Stylo relevé
Aller à x=x+5; y=y-9
Stylo écrit
7→A
Répéter 2
  Répéter 2
    Avancer de 5 pixels
    Tourner de ↺ 90 degrés
    Avancer de A pixels
    Tourner de ↺ 90 degrés
  ⤴
  A-1→A
  Stylo relevé
  Aller à x=x+3; y=y-3
  Stylo écrit

Le plus "interessant" est passé, à partir de là c'est le tracé d'une partie du link et de 2019, en utilisant principalement des "aller à", ce qui permet d'aller aussi bien en haut, qu'en bas, mais aussi a droite, à gauche ainsi qu'en diaguonale. L'avantage, c'est que je n'ai pas besoin de changer d'angle pour tracer les figures, et gagne donc facilement des octets.

J'aurais pu avoir plus de points en mettant des "aller à" avec des coordonnées précises et pas relatives à la position actuelle, car d'après les participations des autres cela consomme moins d'octets, mais je m'en suis pas trop mal sorti :3


6. À la 6ème place, une participation très dense de Astrostellar obtient 2405 points. Plein d'astuces sont utilisées ici, mais la plus unique est certainement l'exploitation de la symétrie dans la tête et l'épée de Link, sur une seule boucle ! Avec deux variables de contrôle le même code trace une large moitié du sprite en un temps record. On reconnaît en fait une astuce générale consistant à exécuter une boucle deux fois en changeant le paramètre entre les deux tours. Le niveau de régularité requis est très faible (contrairement à des boucles ayant au moins 3 tours) et ça factorise efficacement le code. Cette participation est aussi la seule, il nous semble, à utiliser des «Avancer de» pour tracer les Z.


Astrostellar a écrit :
J'ai tout d'abord essayer de tracer dans des programmes indépendants les différentes parties de l'image, à savoir les rectangles, les ronds, les Z, Link, 2019 et le petit patern symétrique avec le coeur en dessous. Malheureusement, une fois tous les bouts de programme réunis en un seul, celui-ci dépassait largement la limite des 900 octets. J'ai donc dû faire des sacrifices pour gagner des octets en perdant un minimum de points.

J'ai effectivement utilisé une boucle pour tracer le Link. En effet, j'avais remarqué la symétrie de son visage. Je fais ainsi simplement une boucle qui trace la moitié du Link avant de changer ma valeur A (qui vaut 1 au début) en -1 pour pouvoir tracer la symétrie (au lieu d'avancer de 3 pixels par exemple, j'avance ainsi de -3 pixels. Je fais ainsi l'exacte inverse ). La variable B vaut 0 lors du premier tour de boucle, puis 1 au second. Celle-ci permet de bien placer ma symétrie : en effet, l'axe de symétrie du visage se situe ENTRE 2 pixels. Si je n'utilisais pas B, la symétrie se tracerait 1 pixel plus loin, autour d'un axe de symétrie qui se situerai alors SUR une verticale de pixels. B me permet ainsi de déplacer de 1 pixel toute ma symétrie. Enfin, C est simplement une valeur qui revient souvent (2A+B) et cela me permet de gagner des octets en initialisant une fois C et la réutiliser au lieu de taper à chaque fois 2A+B. Pour finir, j'ai pivoté au tout début de mon programme de 270 degrés (c'est à dire en vertical vers le bas) pour économiser des Aller à et les remplacer simplement par des Avancer de lorsque j'avais besoin d'aller vers le bas.

Pour les rectangles, j'ai tracé 2 rectangles en une boucle Répéter car ils avaient la même largeur, puis dans une seconde boucle le dernier rectangle. J'ai sacrifié au passage 2 pixels pour ne pas perdre d'octets ;).
J'ai ensuite tracé les ronds. Je fais pivoter mon stylo avant de le faire avancer. Mais les angles de rotation obtenus par calculs, une fois mis dans le programme, ne trace pas un cercle parfait... J'ai alors utilisé un "bidouillage" pour obtenir les angles de rotation... J'ai modifié quelques valeurs d'angles (à 1 ou 2 degrés près) pour que le cercle tracé soit régulier, en essayant plusieurs solutions, d'où les 25, 22, 23 puis 20 degrés de rotation un peu bizarre obtenus grâce à plusieurs essais... Je trace ainsi un quart de cercle, que je mets dans une boucle Répéter 4 fois pour le tracer entièrement. Je passe ensuite au second cercle (celui interne) sans lever mon stylo (économie de 2 lignes Relever puis Abaisser le stylo en sacrifiant un seul pixel).

Pour les Z, j'ai remarqué que la longueur supérieure des Z augmentaient de 1 pixel à chaque niveau en descendant. J'ai donc fait une boucle Répéter 8 fois (pour les 8 Z) avec une incrémentation de 1 à A (la longueur du haut des Z) à chaque tour tant que A n'est pas supérieur à 6 (rang à partir duquel les Z ne s'agrandissent plus). Je pivote à 225 degrés vers la gauche pour me mettre en position pour tracer la diagonale du Z. Sachant que la diagonale a la même longueur que la longueur supérieure de Z, j'avance de √2A (√2 comme pour la diagonale d'un carré), puis je pivote de nouveau pour me retrouver à l'horizontale et tracer le haut de mon Z. Le B est une petite variable qui permet de bien tracer le premier Z.

Pour le 2019, je trace simplement des rectangles à la place des chiffres, sauf pour le 1 (je sacrifie pas mal de pixels, mais je n'avais plus la place de mettre un bon 2019 dans le programme).

Enfin, la dernière boucle permet de répéter le tracé des 2 diagonales de la décoration à droite (ce sont celles qui me permettent de tracer un maximum de pixels en aussi peu de lignes )


5. On entre dans le top 5 avec Cala Mar, qui fournit un programme de 2559 points avec... eh bien pas grand-chose ! Uniquement des «Aller à», des «Avancer de», et la technique de tracé de cercles d'Éléonore . Il trace 6 éléments disjoints en ne relevant le stylo que 7 fois en tout. On s'attendait à cette méthode, mais pas à ce qu'elle soit si efficace ! Et pourtant elle montre qu'il n'y a pas besoin de connaissances de gourou pour tutoyer les meilleurs participants. Félicitations


Cala Mar a écrit :
Ah moi j'ai pas fais la même chose qu'Amiga68000 pour les cercles, j'ai fait:

Aller à x=-30 ; y=-12
Stylo écrit
Répéter 36 fois
  Avancer de 1.12 pxl
  Tourner de 9.9

Stylo relevé
S'orienter à 0
Aller à x=-30; y=-10
Stylo écrit
Répéter 28 fois
  Avancer de 1 pxl
  Tourner de 12.75
(message original)


4. À partir de la participation de Extra44 qui atteint 2673 points, on ne plaisante plus sur les calculs. On commence à utiliser les fonctions de la calculatrice pour diverses optimisations, comme tracer les cercles en calculant tout simplement les sinus et cosinus pour différents angles et rayons. Tout est optimisé aux petits oignons, du choix des lignes jusqu'aux petites régularités permettant d'économiser des octets avec des boucles. Et on termine par une longue suite de «Aller à» qui trace l'essentiel de Link et de la décoration. Il n'y a quasiment plus un octet à sauver là-dedans.


Extra44 a écrit :
Bon pour moi : J'avais fait ma 1ère version sur python/ordi, et comme j'étais à l'aise (ben oui j'avais de la place... ça me paraissait optimal... c'était beau quoi...), j'avais réussi (yess ) à dessiner correctement le bitmap.

Mais comme quasiment tout le monde ici, le problème est le manque de place. Et quand j'ai vu qu'une instruction moyenne sur la fx-92+ Spéciale Collège faisait au bas mot 10 octets facile (avec les fins de ligne SVP !); je me suis dit Arghh !

J'ai eu un autre soucis : turtle sur python/ordi et turtle sur fx-92+ Spéciale Collège ont un comportement différent sur la dernière position/pixel avant levé du stylo; sur l'ordi : il n'est pas dessiné, sur fx-92+ Spéciale Collège : il l'est. Du coup une fois passé sur émulateur, je ne suis plus revenu sur le python/ordi !

J'avais attaqué dans cette version les figures par ordre : en 1er la figure à gauche : les cercles. Après quelques essais, j'en suis arrivé a faire le tracé mathématique d'un cercle par cos et sin. Restait à avoir les bons centres et rayons des 2 cercles: j'ai bien vu que le centre n'est pas placé pile sur un pixel entre les 4 pixels ! Sinon dommage pour moi mais je n'avais pas compris/comment utiliser correctement le thêta... Après quelques essais, j'avais un rayon de 6.3 pixels pour le grand cercle, 4.5 pixels pour le petit, et un pas d'angle de . Pourquoi , car c'était la 1ère valeur qui m'a donné un cercle collant au bitmap, et qu'ensuite la valeur de 5 dans C et la valeur de A mise a 135 (°) pouvait me servir pour le zigzag ou pour d'autres angles (2A=270=-90, 3A...).

Ensuite les rectangles : j'avais fait une première version avec les 2 pixels blancs : je me suis rendu vite compte que cela bouffait des octets ⇒ j'ai alors opté pour 3 rectangles pleins. Une petite optimisation ici a été de finir par le rectangle d'en haut et de finir sur le trait horizontal du haut du rectangle, et de finir dans la direction vers l'Est (0°), afin de ne faire qu'un avancer de 22 pixels pour arriver sur le début du zigzag. J'avais réussi a faire une petite optimisation sur le zigzag, mais la participation totale n'étant pas meilleure, elle est passée à la trappe. Voir la dernière participation.

Dans cette version je suis passé ensuite au nombre 2019, en essayant de limiter les nombres d'octets, en voyant que les si finsi, voire les si sinon finsi bouffait de la place ! J'ai essayé avec une boucle en tournant a droite pour la moitié haute du 2, puis autant de boucles que possible pour faire le reste du 2019 en tournant à gauche... sans oublier les saut entre chiffres que j'ai zappé exprès car moins rentables de les prendre en compte...

Pour le logo en haut du cœur : j'ai essayé de regrouper les actions de même type (éventuellement paramétré) : j'ai vu une symétrie d'axe verticale ( → variable D égale a ±1 agissant sur la position x), et une petite symétrie d'axe horizontal entre la pointe centrale haute et la pointe centrale basse du logo : variable C agissant sur y ! D'où le code.

Ben après pour le reste; l'épée et la tête : vu qu'il ne me restait plus beaucoup d'octets, j'ai tracé les plus grands traits, en essayant de lever le moins possible le crayon.

Après cela j'avais essayé de coder les mouvements, mais cela s'est révélé moins meilleur !

Voila, si vous avez des questions, demandez !
(message original)


3. Le programme de Krevo_ (TI-Planet, Planète Casio) à 2805 points nous emmène de nouveau sur le terrain du calcul. Une partie des constantes a clairement été générée, et on retrouve beaucoup de Ent(X÷10) permettant de parcourir tous les chiffres d'un nombre. Alors, une idée ? Eh oui vous ne rêvez pas, ce programme a été compressé en encodant de façon compacte les pas ou les angles à suivre dans des grosses constantes pour éviter de répéter les instructions de déplacement élémentaires ! La logique de décodage occupe une majeure partie de cette soumission qui n'hésite pas à éluder les parenthèses fermantes non nécessaires dans les caculs pour réduire la quantité de code. Tout y est décrocher pour la 3ème place de l'épreuve !


Krevo_ a écrit :
Alors pour les 2 cercles, j'ai fait :

4,5→A
Répéter 2
  0→M
  Stylo relevé
  Répéter 32
    Aller à x=6,5+Acos(M; y=-6,5+Asin(M
    Stylo écrit
   M+90÷8→M
  ⤴
  6,4→A


C'est un peu pareil que Grosged, j'ai un rayon de 4,5 pour le cercle intérieur, puis 6,4 pour le cercle extérieur. Ensuite j'ai 32 tours de la boucle interne car je fait progresser l'angle M de 90°/8 (32x90°/8=4x90°=360°). (La progression de l'angle et le rayon du cercle extérieur : tout ça c'est des réglages un peu empirique en vérifiant que ça dessinais bien les pixels voulus). Je dessine tout simplement un point aux coordonnées (centre + rayon x cos angle ; centre + rayon x sin angle). Et effectivement, j'aurais gagné des octets en utilisant θ.

Je passe sur la boucle qui dessine les Z c'est trivial.

Pour les 3 rectangles, les chiffres et surtout Link et son épée, j'ai fait une sorte de moteur de dessin vectoriel (qui existe donc 3 fois en tout, j'aurais sans doute pu coder les déplacement de stylo et optimisé mais bon c'était déjà consommateur de temps tout ça...). Il s'agit de consommer un à un les chiffres des variable A et M (je me limite à 15 chiffres suite à différents test pour voir ce qui marchais en nombre de chiffre significatif, c'est à dire sans perdre d'informations).

Stylo écrit
1343282468656→A
7833249394235→M
Répéter 3
  Si E=8 Alors
    2453212124178→A
    1821311311322→M
  Fin
  Répéter 15
    S'orienter à 45(A-FEnt(A÷Fdegrés
    Avancer de(M-FEnt(M÷F))(1+,41(2-PGCD(2;A-FEnt(A÷Fpixels
    Ent(A÷F→A
    Ent(M÷F→M
  ⤴
  7463468745678→A
  2232433151413→M
  1+E→E

(Attention ici E valait 6 car j'avais fini de dessiné les Z comme ça, ... donc E=8 est le test du 3è tour de boucle, car ici j'ai 3 fois 15 chiffres pour A et pour M).

Dans A, j'ai mis successivement les angles, l'unité est le multiple de 45°. Ainsi, avec 2453212124178→A, les orientations sont successivement de 90° (2x45°), 180° (4x45°), 225° (5 x 45°), ... Dans M je mets le nombre de pixels. Donc 2232433151413→M signifie qu'il faudra avancer de 2, 2, 3, ... pixels. A chaque fois un couple orientation/avancement en pixels. Problème : quand l'orientation est en diagonale (45°, 135°, 225 °, ...) il faut avancer non pas de n pixels mais de n√2 pixels, donc si le chiffre de l'orientation est impair, on est en diagonale et je multiplie le nombre de pixels d'avancement par 1+1x0.41, ce qui fait 1.41. Sinon, si c'est pair, je multiplie le nombre de pixels d'avancement par 1+0x0.41, ce qui fait tout simplement 1. La parité est testée à l'aide du PGCD du nombre testé et de 2 (le PGCD est 2 pour les nombres pairs, 1 pour les nombres impairs).
(message original 1, message original 2)


2. L'algorithme suivant nous vient de Grosged et défraie le classement en annonçant 400 points de décalage avec son poursuivant. La logique est décuplée par la possibilité d'écrire des tests sans «Si ... alors». On remarque en effet que Ent(cos(X)) vaut essentiellement 1 si X=0 et 0 sinon (pourvu que X soit petit). Et donc Ent(cos(X-Y)) permet de tester efficacement si deux coordonnées sont égales. Combinée avec un système de compression similaire à celui de Krevo_ mais plus compact, cette technique permet de factoriser très aggressivement le code ! Ce programme mérite amplement sa 2ème place et ses 3217 points.


Grosged a écrit :
Je vais vous détailler la meilleure de mes participations. Mais parlons d'abord de quelques astuces.

Afin d'éviter les tests du genre Si...Alors...Fin qui prennent plusieurs lignes (ou qu'on ne peut parfois pas utiliser car au sein de 3 boucles imbriquées), l'idéal aurait été de pouvoir insérer des tests directement dans les calculs, comme par exemple... A+(B=7)→C. La fx-92+ Spéciale Collège ne le permettant pas, j'ai rusé en utilisant Ent(cos(. En effet, grâce à cos(0)=1 , la valeur entière de cos(B-7) sera égale à 1 si B=7, ou à 0 si B≠7. L'exemple précédent devient donc... A+Ent(cos(B-7→C (vous remarquerez , au passage, cette mini-optimisation qui consiste à ne pas refermer les parenthèses en fin de ligne ).

Autre astuce d'optimisation : parfois on a besoin de ne modifier que la variable x ou y. Alors, en fonction de l'orientation actuelle du stylo, un simple Avancer de ... pixels suffit (prends moins d'octets qu'un "Aller à x=... ; y=..."). Et quand on est vraiment obligé d'utiliser Aller à x=... ; y=... , on peut mettre un x=x ou y=y pour la variable qui ne bouge pas.

Intéressante aussi cette variable d'orientation θ dont la valeur sera retranchée de 360 (autant de fois que nécessaire) dès qu'elle dépasse 359. θ est donc une variable modulo 360. C'est bon à savoir car, bien utilisée, ça nous évitera de la (re)paramétrer. A noter que cette variable n'est accessible qu'au moyen de la touche OPTN.

Parfois, on peut aussi optimiser au niveau des Stylo écrit / Stylo relevé : l'idéal étant, bien sûr, de tracer le plus possible sans relever.

Au sujet des boucles, Répéter jusqu'à... n'est pas toujours indispensable. Quand on sait déjà combien de fois la boucle doit tourner, un simple Répéter... suffit.

Au sujet des données, on n'a -à ma connaissance- pas d'autre choix que de stocker ça dans des variables, par exemple en base 2...10 ou autres..., et d'y réinjecter d'autres valeurs au fur-et-à-mesure, au coeur de la/des boucle(s)...


Voilà pour les quelques astuces, maintenant passons au programme. (Merci @Lephe pour l'animation ).

Ca commence par la routine traçant les 3 espèces de rectangles :

Aller à x=4; y=17
44→D
54843253→A
Stylo écrit
Répéter 24
  Tourner de ↺90 degrés
  ,1Ent(A→A
  Avancer de 10(A-Ent(A pixels
  A+50(2031Ent(cos(A))+313064Ent(cos(,1-A→A

Stylo relevé

Ne faites pas attention au 44→D, c'est pour plus tard. Là, j'ai pensé ça comme un pointeur qui va, tout au long du tracé, tourner à chaque fois, à 90° dans le sens inverse des aiguilles d'une montre. Il me restait alors à définir le meilleur point de départ, insérer les longueurs respectives de tracé dans la variable A (en base 10). Ainsi, ça démarre avec un tracé de longueur 3, puis 5... 2... 3... etc (d'où 54843253→A). Parfois le stylo fait du sur place pour, par exemple, faire un demi-tour (donc tracé de longueur 0). Et comme on n'a pas assez de place pour inclure d'un coup toutes les longueurs dans A... A+50(2031Ent(cos(A))+313064Ent(cos(,1-A→A réinjecte des données au fur et à mesure... (factorisation pour grapiller 1 ou 2 octets ).

Puis, l'affichage du bonhomme :

J'ai pensé ça en affichage successif de bandes verticales de 16 pixels, chacune codée en base 2 (en binaire, quoi). Il y a, au total, 15 bandes réelles car certaines, vers la fin, sont vierges (par souci d'optimisation, les 14 premières sont codées par groupes de 2, donc 7 valeurs de 32 bits).

Avancer de 30 pixels
655364x→A
Répéter 21
  Répéter 16
    ,5Ent(A→A
    Aller à x=x; y=52-2θ÷45-Arcsin(A-Ent(A
    Stylo écrit
    Avancer de 0 pixels
    Stylo relevé
    Tourner de ↺ 22,5 degrés
  ⤴
  Avancer de 1 pixels
  A+12Ent(cos(x-52))+3301008851Ent(cos(x-38))+4258383057Ent(cos(x-40→A
  A+2453574741Ent(cos(x-42))+1081671044Ent(cos(x-D→A
  A+797186680Ent(cos(x-34))+878062140Ent(cos(x-36→A

655364x→A pour la 1ère bande de 32 bits, laquelle est un multiple de 32 (et x est justement à 32), ainsi on gagne un octet.
Comme vous pouvez le constater, on réinjecte des données suivant la position actuelle du pointeur (bref, en fonction de l'abscisse x). Les 2 pixels flottants font partie de la toute dernière bande verticale, celle-ci apparaît en abscisse x=52 après quelques bandes vierges. Codée en binaire, elle vaut 12... d'où 12Ent(cos(x-52)). J'utilise la variable θ comme valeur offset pour l'ordonnée y et lorsqu'on n'a pas de pixel à tracer, l'affichage se fait hors-écran. Lorsque ,5Ent(A→A décode en base 2, A-Ent(A nous donne la valeur 0,5 si pixel, sinon 0. On gère le hors-écran grâce au fait qu'Arcsin(0)=0 et Arcsin(0.5)=30... Arcsin(A-Ent(A est préférable à 30(A-Ent(A.

Ensuite , l'affichage des zig-zags :

Aller à x=x; y=22
Répéter 8
  Aller à x=16; y=y+A
  A-1-Ent(10sin(A→A
  Stylo écrit
  Avancer de-Apixels

Là, j'ai focalisé sur les tracés horizontaux uniquement (les diagonales s'affichent d'elles-même puisque le tracé reste en continu). Un petit Ent(10sin... me permet, une fois arrivé à la longueur de 6, de ne pas la dépasser. J'utilise une valeur négative rien que pour ultérieurement réutiliser cette variable A=-6.

Puis, l'affichage de l'épée :

Aller à x=D; y=8
Stylo écrit
Aller à x=45; y=5
Aller à x=42; y=7
Aller à x=41; y=2
Avancer de 5 pixels
Aller à x=x; y=4
Aller à x=45; y=1
Aller à x=x; y=A
Aller à x=D; y=-7
Aller à x=42; y=A
Aller à x=x; y=1
Stylo relevé

J'ai fini par m'apercevoir qu'un affichage en tracé classique s'avérait plus économique qu'en mode sprite ! (Dans un premier temps, j'avais opté pour un affichage en mode "sprite", et de manière symétrique par souci d'économie de donnée)

Maintenant, c'est au tour des 2 cercles :

4,5→A
Répéter 2
  Répéter 45
    Tourner de ↺ 8 degrés
    Aller à x=,5+Acos(θ; y=,5+Asin(θ
    Stylo écrit
  ⤴
  Stylo relevé
  6,35→A

Ensuite, l'affichage de 2019 :

5642465600→A
Aller à x=x; y=2
Répéter 5
  Aller à x=20π; y=y-1
  Répéter 12
    ,5Ent(A→A
    Si A=Ent(A Alors
      Stylo écrit
      Avancer de 0 pixels
      Stylo relevé
    Fin
    Avancer de 4÷3 pixels
  ⤴
  A+16779094Ent(cos(A→A

L'astuce principale réside dans l'économie de données : on fait comme si les 4 caractères composant 2019 faisaient chacuns 3x5 pixels (on fait abstraction du pixel de séparation entre chaque, l'affichage s'occupera de les "détacher", d'où le pas de 4/3 ). Encore pour réduire la taille des données, cette fois-ci , on code le tout en inversion video (si pixel il y a , valeur 0).

Et pour terminer, l'affichage du vaisseau suivi de l'espèce de coeur :

81923201→A
    Répéter 12
        Aller à x=70; y=y
        Répéter 9
            ,5Ent(A→A
            Répéter2
                Aller à x=140-x; y=D-Arctan(A-Ent(A
                Stylo écrit
                Avancer de 0 pixels
                Stylo relevé
            ⤴
            Avancer de 1 pixels
        ⤴
        D-1→D
        A+33686470Ent(cos(D-41))+2364428Ent(cos(D-38))+263685Ent(cos(D-35→A

Là, j'ai opté pour un affichage symétrique (donc presque 2x moins de données ). Cette fois, j'utilise Arctan au lieu d'Arcsin, uniquement par rapport à la variable D préalablement définie.

Voili-voilà ! J'espère avoir été assez clair dans mes explications, si vous souhaitez des détails sur telle ou telle partie, n'hésitez pas à poster Et surtout... Longue vie à la fx-92+ Spéciale Collège ! (hmmmm je sais : c'est juste une question de pile, haha ).
(message original)


1. Et c'est Pavel (TI-Planet, Planète Casio) qui domine ce classement du haut de ses 3270 points. Le programme très court n'a plus grand-chose d'humain et l'animation montre une méthode de tracé très orthodoxe. Après avoir tracé rapidement les cercles et les rectangles, il attaque le sprite de Link et les décorations colonne par colonne, pixel par pixel, s'arrêtant même sur l'herbe (aussi tirée de la première génération de Pokémon) sur son passage. La méthode de chargement des données donne le vertige. J'ai cru un moment à une transformée de Fourier mais ne serait-ce pas un bitmap très bien écrit ? La méthode maître cette épreuve ne révèle pas facilement ses secrets. Une conclusion glorieuse !


Pavel a écrit :
Mon idée initiale était que la méthode la plus simple serait de convertir l'image en colonnes de pixels, d'utiliser des bits pour représenter les pixels et de les dessiner pixel par pixel. Reste à trouver comment coder le plus efficacement les bits.

Étant donné que la hauteur de l'image est de 30 pixels, que 2^30 contient 10 chiffres décimaux et que la fx-92+ Spéciale Collège fonctionne avec des valeurs entières avec 10 chiffres décimaux, les colonnes de pixels peuvent être encodées sous forme de valeurs entières. Afin de convertir les colonnes de pixels en valeurs entières, j'ai écrit un petit script Python:

from scipy import misc
image = misc.imread('LWTC5q8.png')
d = 9
for y in range(85):
  counter = 0
  value = 0
  for x in range(30):
    if image[x+1,y+5,0] == 0:
      counter += 1
      value += 2**x
  if counter > 1:
    length = len(str(abs(value)))+ len(str(abs(y - d)))
    if y - d == 0: length -= 2
    print('%2d %2d %9d %2d' % (counter, length, value, y - d))

Ce script imprime le nombre de pixels par colonne, la valeur entière, le nombre de chiffres décimaux dans la valeur entière et la position de la colonne de pixels. La valeur d=9 du déplacement horizontal de l'image est choisie pour minimiser la somme des longueurs de toutes les valeurs entières. Avec ce script, j'ai obtenu 52 valeurs entières correspondant à des colonnes de plus de 1 pixel.

Le code pour dessiner les colonnes de pixels est assez simple:

S'orienter à -90 degrés
Répéter 85
  f(x) → B
  Aller à x=x+1; y=9
  Répéter 30
    Si 1=PGCD(Ent(B÷2^(9-y)); 2) Alors
      Stylo écrit
      Avancer de 0 pixels
      Stylo relevé
    Fin
    Avancer de 1 pixels
  ⤴

Reste à trouver comment programmer f(x)→B, où f(x) est une fonction qui renvoie une valeur entière correspondant à la colonne de pixels avec la coordonnée x. En C ou en Python, cette fonction peut être programmée comme 123*(x==1)+456*(x==2)+789*(x==3)+.... La seule façon de programmer quelque chose de similaire sur la fx-92+ Spéciale Collège que j'ai pu trouver est la suivante : 123*Ent(Cos(x-1)) + 456*Ent(Cos(x-2)) + 789*Ent(Cos(x-3))+.... En utilisant cette approche, j'ai réussi à obtenir 3025 points avec ce code.

Malheureusement, même si cette approche est facile à implementer, elle n'est pas la plus efficace. J'ai compris ça quand grosged a soumis une solution avec un score plus élevé et j'ai commencé à chercher des méthodes plus optimales pour dessiner certaines parties de l'image. Voyant que je vais devoir tester beaucoup de codes différents et qu'il faudra beaucoup de temps pour les saisir manuellement, j'ai écrit un script Python pour programmer automatiquement l'émulateur fx-92+ Spéciale Collège : https://gitea.planet-casio.com/Pavel/fx92-programmer . En utilisant ce script, j'ai rapidement testé différentes approches pour dessiner les zig-zags, les cercles et les rectangles. Ensuite, j'ai combiné les meilleures parties de tous les codes que j'ai réussi à produire et j'ai obtenu une solution correspondant à 3270 points.

Après la publication des solutions de ce défi, j'ai analysé le code écrit par grosged et j'ai été impressionné par sa solution très efficace pour dessiner les rectangles. J'ai immédiatement voulu vérifier quel score pouvait être obtenu en combinant une approche similaire pour dessiner les rectangles avec d'autres parties de mon code et j'ai réussi à obtenir 3309 points avec ce code.



Conclusion et choix des lots

Encore plus que l'année dernière, ces participations révèlent l'ingéniosité avec laquelle vous avez approché le sujet. Les techniques utilisées dépassent de loin nos attente. Bravo !

Comme prévu par le réglement du concours, les 12 participants ayant obtenu les meilleurs scores vous pouvoir choisir les lots de leur choix par ordre de score. Le premier à se lancer est donc Pavel. Vous pouvez suivre le choix en parallèle sur ce fil et sur TI-Planet. Lorsque votre tour vient, postez sur l'un des forums pour annoncer votre choix.

À bientôt sur Planète Casio !

Article connexe sur TI-Planet : Résultat concours de rentrée 2019 - défi de tracé

Commentez cette news ! (13)

Publié par Lephenixnoir le

Voir toutes les news


Fin de la méga-Edition du Jeu du Mois !


Bonjour à tous ! Avec quelques… 4 mois de retard sur le planning et une jolie bousculade sur la page d'accueil, voici la troisième news de la soirée !

On se retrouve pour annoncer les résultats de la méga-Edition du vote du Jeu du Mois qui contenait, rappelons-le 30 programmes répartit sur les mois de Juillet, Août et Septembre ! Et le grand gagnant est Picross de Massena avec ses 13 points !



Bravo à Alexot et Filoji qui se sont qualifiés pour la finale !

On se retrouve très bientôt puisque le mois d'octobre nous attend déjà !
Bravo et merci à tous les autres : c'est grâce à vos programmes et projets que ce site vit…

Commentez cette news ! (4)

Publié par Shadow15510 le

Voir toutes les news


Planète Casio v42 © créé par Neuronix et Muelsaco 2004 - 2019 | Il y a 62 connectés | Nous contacter | Qui sommes-nous ? | Licences et remerciements

Planète Casio est un site communautaire non affilié à Casio. Toute reproduction de Planète Casio, même partielle, est interdite.
Les programmes et autres publications présentes sur Planète Casio restent la propriété de leurs auteurs et peuvent être soumis à des licences ou copyrights.
CASIO est une marque déposée par CASIO Computer Co., Ltd