π
<-
Chat plein-écran
[^]

News 2024
Avril (13)
Mars (7)
Janvier (20)

News 2023
Octobre (19)
Août (14)
Juillet (13)
Juin (21)
Mai (29)
Avril (24)
Mars (24)
Janvier (24)

News 2022
Octobre (23)
Août (14)
Juillet (15)
Juin (17)
Mai (31)
Avril (27)
Mars (28)
Janvier (34)

News 2021
Octobre (24)
Août (37)
Juillet (50)
Juin (32)
Mai (48)
Avril (61)
Mars (35)
Janvier (34)

News 2020
Octobre (17)
Août (43)
Juillet (43)
Juin (45)
Mai (60)
Avril (78)
Mars (36)
Janvier (39)

News 2019
Octobre (13)
Août (18)
Juillet (23)
Juin (28)
Mai (31)
Avril (26)
Mars (38)
Janvier (37)

News 2018
Octobre (13)
Août (32)
Juillet (23)
Juin (64)
Mai (63)
Avril (45)
Mars (43)
Janvier (45)

News 2017
Octobre (26)
Août (39)
Juillet (52)
Juin (88)
Mai (51)
Avril (43)
Mars (37)
Janvier (33)

News 2016
Octobre (25)
Août (42)
Juillet (34)
Juin (109)
Mai (55)
Avril (34)
Mars (37)
Janvier (24)

News 2015
Octobre (22)
Août (56)
Juillet (22)
Juin (94)
Mai (56)
Avril (32)
Mars (40)
Janvier (21)

News 2014
Octobre (26)
Août (18)
Juillet (23)
Juin (101)
Mai (57)
Avril (59)
Mars (54)
Janvier (31)

News 2013
Octobre (67)
Août (50)
Juillet (43)
Juin (193)
Mai (93)
Avril (102)
Mars (45)
Janvier (50)

News 2012
Octobre (64)
Août (63)
Juillet (53)
Juin (132)
Mai (88)
Avril (73)
Mars (57)
Janvier (58)

News 2011
Octobre (56)
Août (31)
Juillet (27)
Juin (71)
Mai (61)
Avril (32)
Mars (36)
Janvier (24)

News 2010
Octobre (11)
Août (8)
Juillet (14)
Juin (10)
Mai (3)
Avril (3)
Mars (1)

News 2009
Août (3)
Juin (2)
Mai (1)
Avril (2)
Mars (1)

Mode examen 2020+ : la position de TI-Planet, clarification

Nouveau messagede Admin » 06 Déc 2019, 11:58

Nous avons décidé de publier cet article pour rappeler (ou clarifier, selon les lecteurs) la position de TI-Planet par rapport au mode examen 2020+.
Nous faisons ainsi écho à l'article équivalent paru il y a quelques jours chez nos confrères de Planète-Casio.



En quelques mots...
Cela ne semble pas évident pour tout-le-monde alors allons-y. Comme elle l'a toujours fait, l'équipe TI-Planet respecte et continuera à respecter la réglementation en vigueur ainsi que les lois de la République à laquelle elle est profondément attachée :
  • nous respectons et le cas échéant appliquerons le mode examen
  • aucune aide ne sera apportée aux demandes visant à contourner ou altérer le bon fonctionnement du mode examen
  • nous ne développons et publions aucun programme, outil, ou tutoriel, permettant de contourner ou altérer le bon fonctionnement du mode examen
  • toute publication en ce sens par un tiers sera systématiquement supprimée et si pertinent signalée
  • toute faille du mode examen portée d'une façon ou d'une autre à notre connaissance est systématiquement signalée au constructeur concerné
  • dans le cas des seules failles déjà en circulation parmi les candidats ou dans la sphère publique et donc déjà hors de notre contrôle, nous nous réservons le droit non pas de les détailler ou aider à leur exploitation, mais d'informer de leur existence et ce de façon bienveillante, en rappelant les risques encourus et dans l'intérêt d'une meilleure anticipation et donc d'un meilleur traitement des incidents le jour J


Pour avoir plus d'informations et du contexte:
5409Le mode examen sera mis en place dès la session 2020 du BAC conformément à la circulaire n°2015-178 du 1er octobre 2015. Pour le principe, il s'agit en gros d'un mode de fonctionnement spécial qui supprime ou verrouille l'accès à tous les éléments logiciels non officiels que tu as rajoutés dans ta calculatrice, et dont le bon fonctionnement est indiqué au surveillant par une diode clignotant sur la tranche supérieure de ta calculatrice.

Nous n'y sommes pas favorables, et c'est notre liberté de penser la plus absolue. Essentiellement pour des problèmes d'égalité en pratique entre candidats :
  • Sans mode examen, chaque candidat était libre, peu importe le modèle de sa calculatrice, de télécharger des programmes lui rajoutant gratuitement des fonctionnalités de modèles supérieurs, programmes dont nous encourageons la création et autour desquels nous travaillons sans relâche depuis plus d'une décennie. On peut citer parmi les réalisations les plus remarquables entre autres des interpréteurs Python comme MicroPython pour TI-Nspire et CasioPython pour les Casio Graph 35/75/85/95, ou encore des moteurs de calcul littéral et formel comme eigenMath pour TI-Nspire, Casio Graph 35/75/85/95 et Graph 90+E et KhiCAS pour Casio Graph 35+E II, Graph 90+E, et TI-Nspire.
  • En mode examen chaque constructeur verrouille sa machine en interdisant toute contribution tierce, dont nombre d'outils pourtant parfaitement légitimes, ce qui est ciblé par la réglementation à ce jour étant les informations en mémoire et absolument pas les fonctionnalités.
Ce n'est pas la faute des constructeurs en question, ils ne font que respecter le cahier des charges de l'Institution finalisé en novembre 2014, à notre avis sans consultation suffisante des professionnels du terrain. Ces spécifications du mode examen expliquent en effet que pour "bloquer l'accès par l'utilisateur aux informations personnelles stockées au préalable", il faut supprimer toutes "les applications personnelles, les remarques et programmes de l'utilisateur, les données «scratchpad», les classeurs ou tout autre dossier personnel".

En conséquence chaque calculatrice devient un modèle complètement fermé qui n'est capable de faire que ce qu'il y a écrit sur la boîte et pas autre chose. Une aubaine en pratique pour les constructeurs : les acheteurs qui veulent plus de fonctionnalités n'auront dorénavant plus d'autre alternative que d'acheter le modèle supérieur et bien évidemment plus cher.

En prime, l'implémentation du mode examen varie d'un constructeur à un autre. Sur certains modèles, des fonctionnalités officielles bien décrites sur l'emballage, incluses à l'achat et loin d'être négligeables (convertisseur d'unités, bibliothèque de constantes physiques, grapheur 3D...) sont inaccessibles une fois passé en mode examen.

Dans un contexte où le développement de logiciels libres rencontre de plus en plus de succès dans le monde informatique et démontre tous les jours sa haute pertinence à un point tel que l'on se demande bien où l'on en serait sans lui, il est surprenant et même désolant de voir les calculatrices graphiques suivre le chemin inverse, avec une régression inédite des droits des propriétaires et ce jusqu'à présent dans l'indifférence générale.

Nous admettrons toutefois, tristement, qu'à côté des changements qui se profilent pour le BAC 2021+ avec les nouvelles modalités d'organisation des épreuves, les inégalités bien réelles introduites par l'activation du mode examen peuvent paraître bien anecdotiques désormais.

5415Depuis quelques jours les demandes ou initiatives visant à contourner le mode examen pleuvent chez Planète Casio. Plusieurs par jour, si bien que l'équipe a dû publier une clarification de sa position à ce sujet.
Il n'y a rien eu de comparable en volume chez nous, loin de là, et nous n'avions donc absolument pas ressenti la nécessité d'une publication similaire. Mais visiblement cette absence apparente de prise de position pourtant maintes fois répétée depuis 2015 génère quelque inquiétude chez des personnes qui, on le suppose, ne doivent nous observer que de loin, et être bien stressées dans le contexte actuel anxiogène de ce mode examen imminent et inédit.

Cela va donc être fait, puisqu'il le faut, même si cela ne vise donc personne d'ici présent en particulier. Notre position est compatible avec celle de l'équipe Planète Casio et n'a d'ailleurs pas varié depuis 2015.

Nous n'avions jusqu'à présent jamais jugé nécessaire de perdre du temps à nous abaisser à répondre aux rumeurs, racontars ou dénonciations malveillantes. Ceux qui nous connaissent et prennent réellement la peine de lire notre fil d'actualités sur le mode examen avec tous les tutoriels conséquents qui y sont conçus et mis en avant en haut de chacune de nos pages (certes hors version mobile pour le moment) n'auront certainement eu aucun doute là-dessus.

Nous restons profondément opposés à la réglementation du mode examen sous sa forme actuelle. Nous ne demandons pas sa suppression, mais sa (re)discussion avec une prise en compte de l'égalité entre candidats munis de différents modèles et de façon générale des droits de l'utilisateur, essentiellement le droit de rajouter des fonctionnalités non officielles (à ne pas confondre avec 'données') et ce sans avoir à sortir le porte-monnaie. Il ne faut pas confondre fonctionnalité et anti-sèche.

Toutefois nous n'appelons absolument pas à la désobéissance, ce serait irresponsable d'inviter les candidats à se mettre ainsi en danger par rapport à la loi :
  • responsables et légalistes, nous respecterons et le cas échéant appliquerons la nouvelle réglementation en vigueur
  • et nous appelons tout-le-monde à faire de même, particulièrement les candidats
Nous n'apporterons aucune assistance à des personnes demandant de l'aide pour contourner ou altérer le bon fonctionnement du mode examen.

Même si certains aiment à l'envisager et répéter sur certains sites, nous n'avons strictement aucune intention de créer et sortir de programmes permettant de faire clignoter la diode ou d'autres choses de ce genre. :#non#:
C'est bien mal nous connaître, nous ne l'avons déjà pas fait en 2018 malgré ces rumeurs déjà en circulation à l'époque alors que le mode examen était encore d'actualité, nous ne le ferons pas davantage cette année, nous n'en voyons absolument pas l'intérêt, et de toutes façons ceux qui pensent ce genre de programme possible ignorent manifestement les spécifications du mode examen ou alors ne les ont tout simplement pas comprises. Le clignotement de la diode se doit d'être régulier et permanent, aussi bien calculatrice allumée qu'éteinte, et même calculatrice occupée. Aucun programme ou application rajouté n'aura une priorité d'exécution suffisante pour permettre cela. Prétendre comme nous l'avons encore lu ces derniers jours que de tels programmes sont déjà en téléchargement chez nous, sur Planète Casio ou ailleurs n'est que pure invention, et on se demande bien dans quel but.

Toute éventuelle publication chez nous par des tiers de programmes, applications, tutoriels et plus généralement outils ayant pour but d'altérer le bon fonctionnement du mode examen sera également supprimée, et pourra de plus faire l'objet d'un signalement si son contenu le justifie.

Si des failles du mode examen viennent à nous être connues d'une façon ou d'une autre, elles seront systématiquement signalées auprès du constructeur concerné.

Si malgré cela des failles du mode examen se trouvent portées à la connaissance des candidats ou même du public, nous nous réservons le droit d'en parler, mais ce de façon bienveillante. Donc :
  • absolument pas pour expliquer et détailler comment exploiter la faille en question si tant est que ce soit possible, mais à titre de simple information :
  • pour rappeler aux candidats ce qu'ils risquent
  • et pour informer les surveillants du problème et des moyens de le détecter
Nous ne croyons en effet pas en la censure, qui ne fera qu'aider les candidats bien informés à frauder en toute tranquillité dans l'ignorance générale. Et puis ce qui ne serait pas évoqué chez nous le serait de toutes façons ailleurs. S'emparer de l'information est l'occasion de dénoncer le problème, d'anticiper pour une gestion plus apaisée le jour J, et de faire passer les points ci-dessus. L'information aura pour but essentiel de griller la faille en question, la rendant ainsi inutilisable. Parce que les surveillants seront au courant, et parce que les candidats équipés de modèles différents et ainsi non concernés ont le droit de savoir et donc de protester contre l'injustice si ils constatent quelque chose d'anormal chez leurs proches voisins le jour J.

5416Nous allons d'ailleurs commencer de suite. La fraude à un examen est un délit passible de sanctions disciplinaires et également pénales. Cher candidat, il serait dangereux et même irresponsable de risquer 5 ans d'interdiction aux examens et concours, y compris le permis de conduire donc, et ainsi grosso modo de "foutre en l'air ton avenir".

L'examen du Baccalauréat est extrêmement bienveillant, avec autour de 90% de réussites au BAC Général et Technologique 2019. Nous allons te dire un secret de Polichinelle, la notation s'adapte au niveau chaque année. Ce n'est pas la catastrophe cette année, si jamais les copies d'examen étaient globalement d'un niveau inférieur à cause du mode examen, elles seraient bien évidemment notées en conséquence. Il est donc ridicule de prendre des risques pour un examen que tu es déjà quasiment certain de réussir.

Les données (et nous insistons sur le mot, nous parlons bien de documents et pas de fonctionnalités rajoutées par des programmes et applications) que tu charges usuellement dans ta calculatrice sont complètement inutiles à l'examen final.
Autant pour un examen blanc cela peut servir, si les profs ont par exemple choisi de poser sans modification un sujet d'examen déjà tombé... Autant à l'examen final ce ne sera pas le cas. Les antisèches électroniques sont inutiles, c'était notre discours l'année dernière sous l'ancienne réglementation, et ça l'est toujours cette année sous la nouvelle.
Le BAC n'autorise la calculatrice qu'aux épreuves scientifiques. Ces épreuves, que ce soit en Mathématiques ou sciences expérimentales, ne demandent jamais de réciter bêtement du cours, des définitions ou des formules, mais de produire un raisonnement à partir des données ou documents fournis. Les formules essentielles sont d'ailleurs usuellement rappelées dans les sujets. Il est impossible de résoudre un sujet d'examen scientifique, toujours inédit, en recopiant des données préalablement saisies dans ta calculatrice. :#non#:
En recopiant de telles données tu as l'impression d'éviter la bulle mais en fait non, c'est pire, car même si tu n'as pas le recul pour t'en rendre compte il s'agit d'une part forcément d'un hors sujet normalement également noté zéro, mais d'autre part également d'un plagiat ce qui est en prime une fraude. Et comme il y aura certainement d'autres candidats qui auront trouvé, chargé et recopié le même document que toi, ce sera facile pour ton correcteur de s'en rendre compte et d'effectuer un signalement.
Les antisèches dans la calculatrice n'ont jamais eu qu'une seule utilité : évacuer le stress et te rassurer.

/!Enfin c'est pourtant une évidence que les diverses demandes semblent oublier, ce n'est pas parce qu'il y a maintenant une diode examen clignotante que les surveillants vont soudainement cesser de circuler et regarder les écrans. Si ils y constatent le listage ou l'affichage de données désormais interdites que tu n'as manifestement pas pu avoir le temps de saisir au clavier depuis le début de ton épreuve, ils vont forcément réagir en conséquence.

Quoi qu'il en soit cher candidat ou surveillant, nous te souhaitons un bon mode examen 2020, et ferons de notre côté le maximum dans le peu de temps qui nous reste pour que cela se passe pour le mieux.


L'équipe TI-Planet


Crédits images :
Lien vers le sujet sur le forum: Mode examen 2020+ : la position de TI-Planet, clarification (Commentaires: 3)

Formations mode examen TI/Casio en ligne - Décembre 2019

Nouveau messagede critor » 06 Déc 2019, 16:22

5409Cher enseignant-surveillant.

A compter de la session 2020, les examens de l'enseignement scolaire (BAC, DNB...) exigent la mise en place du mode examen des calculatrices graphiques. Et ce aussi bien pour les épreuves terminales que ponctuelles ou de contrôle continu.
C'est donc imminent avec les E3C de Mathématiques en Première technologique dès Janvier 2020, et peut-être commences-tu à stresser ou te demander comment tu vas bien pouvoir faire...

Dans cette urgence, nous t'avons ébauché un protocole qui vise à éviter le maximum de failles permettant la fraude, tout en restant sur des manipulations ou vérifications collectives non spécifiques et ainsi simples, car réalisables sans besoin d'être un expert pour chacun des nombreux modèles conformes. Tu es parfaitement libre de le suivre ou pas, le reprendre, partager, modifier ou améliorer. Nous t'en reparlerons prochainement, puisque nous sommes encore en train de travailler dessus.

Les constructeurs de calculatrices graphiques Casio et Texas Instruments sont également à tes côtés et se mettent en quatre, t'organisant dès ce mois-ci des formations en ligne au cours desquelles tu pourras prendre connaissance des bons réflexes et poser toutes les questions de ton choix ! :bj:

Et de plus les constructeurs ont le bon sens de ne pas faire ça en même temps, tu vas ainsi pouvoir maîtriser la surveillance de l'ensemble des modèles les plus répandus : :bj:
  • Casio t'invite le Mercredi 11 Décembre 2019 à 15h pour une session de 45 minutes et y traitera entre autres de ses modèles Graph 25+E, Graph 35+E II, Graph 90+E et fx-CP400+E.
  • Texas Instruments t'attend pour sa part le Jeudi 12 Décembre 2019 à 18h30 pour une session d'1h30.

Officiellement c'est le candidat qui doit activer par lui-même le mode examen et uniquement sur ton ordre. Si tu le souhaites ou le juges utile, tu peux dors et déjà prendre connaissance de la procédure d'activation détaillée que chaque candidat devra suivre selon son modèle.

Si un candidat arrive et se présente à toi avec une calculatrice qui est déjà en mode examen, tu ne dois pas l'accepter en l'état. Car cela ne veut pas dire que la mémoire est vide, juste qu'elle a été vidée au moment de l'activation du mode examen tu ignores quand, et le candidat a possiblement eu tout le temps depuis pour la reremplir. :#non#:

Heureusement Casio et Texas Instruments ont prévu la parade. Pas besoin de t'embêter à désactiver le mode examen (ce qui est souvent très contraignant et donc difficile pour ne pas dire impossible en salle d'examen), il est possible facilement de revalider directement le mode examen et ainsi vider à nouveau la mémoire. Cette procédure par contre est à effectuer de façon individuelle aux côtés de chaque candidat concerné. En effet puisque la diode clignote déjà elle ne peut donc plus te servir d'indicateur du vidage de la mémoire, c'est le clavier et l'écran qu'il te faudra bien regarder.

Liens :

Crédits images : NeOtuX
Lien vers le sujet sur le forum: Formations mode examen TI/Casio en ligne - Décembre 2019 (Commentaires: 0)

Mode examen, avis d'un enseignant-chercheur MathemaTICE n°68

Nouveau messagede critor » 06 Déc 2019, 18:40

11302Enseignant-chercheur à l'Institut Fourier de l'Université de Grenoble I, Bernard Parisse est à l'origine du développement du logiciel de Mathématiques intégré Xcas bien évidemment sous licence libre GPL.

Mais Bernard a également apporté une inestimable contribution au monde des calculatrices, puisque le moteur de calcul formel GIAC qu'il développe pour ce logiciel a également été adapté par ses soins pour nombre de modèles de calculatrices graphiques différents :
D'innombrables heures de travail bénévole pour offrir au plus grand nombre l'accès au calcul formel que les modèles actuels réservent officiellement au haut de gamme, et ainsi pour sa meilleure maîtrise par les élèves et étudiants ! :D

Nous étions donc tout heureux dans notre classement de rentrée QCC 2019 de t'annoncer entre autres la possibilité de rajouter gratuitement les fonctionnalités haut de gamme liées au calcul formel sur ta Casio Graph 90+E ou pour la première fois cette année sur Casio Graph 35+E II, modèle n°1 des ventes au lycée ! :bj:

5409La joie ne fut hélas que de courte durée. Nous avons appris depuis qu'afin de bloquer les informations en mémoire pour la session 2020, les épreuves des examens de l'enseignement scolaire (BAC, DNB...) exigeront la mise en place du mode examen des calculatrices graphiques.

Les applications KhiCAS ne sont bien évidemment pas des informations interdites mais des fonctionnalités parfaitement légitimes, puisque non bloquées et restant donc disponibles sur les modèles haut de gamme. Mais malheureusement les spécifications actuelles du mode examen ne font pas de différence et exigent leur blocage, tu en seras donc privé(e) cette année. :mj:

Peut-être connais-tu les manuels Sésamath ? Mais Sésamath c'est aussi le magazine bimestriel MathémaTICE.

Bernard est justement au menu du prochain MathématTICE de Janvier 2020.

Dans un article à paraître dans le MathématTICE n°68 au sujet de Xcas et de ses adaptations KhiCAS pour calculatrices, Bernard revient entre autres sur ce coup dur et te partage son analyse de la situation, son ressenti, ainsi que ses propositions.

Si nous divergeons sur ces dernières, le reste est dans l'ensemble compatible avec l'analyse que nous t'avions déjà partagée dans notre propre prise de position.

Liens :

Crédits images : NeOtuX
Lien vers le sujet sur le forum: Mode examen, avis d'un enseignant-chercheur MathemaTICE n°68 (Commentaires: 4)

Pétitions contre mode examen BAC 2020 #NonModeExamen

Nouveau messagede critor » 06 Déc 2019, 23:38

Depuis quelques années au BAC, c'est la mode des pétitions après les épreuves. Parce que telle épreuve a été jugée trop dure elles demandent une notation clémente, ce qui de toutes façons est toujours le cas avec autour de 90% de réussites au BAC Général et Technologique 2019.
Mais cette année pour le BAC 2020, jeuxvideo.com lance une nouvelle mode révolutionnaire, celle des pétitions avant les épreuves. :p

Une pétition #NonModeExamen y a en effet été lancée dès le 22 Novembre soit le lendemain des premières annonces et dépasse aujourd'hui les 6700 signataires. Si l'on regarde par rapport à l'ensemble des 538230 candidats du BAC Général et Technologique session 2019 et qui auraient donc été concernés cette année ce n'est pas rien, déjà au-delà des 1% ! :bj:

Toutefois cette pétition, peut-être rédigée trop rapidement, ne concerne en fait que les candidats au BAC S 2020.
D'autres pétitions ont donc été créées depuis en changeant ce détail de formulation (ciblant par exemple le BAC STI2D 2020 ou encore l'ensemble des BAC S/ES/L 2020) ou bien en remplaçant intégralement l'argumentaire, mais sont à date très loin d'obtenir le même succès.

Précisons que nous n'appelons pas à la signature de ces pétitions, nous ne les avons d'ailleurs pas signées nous-mêmes et allons t'expliquer pourquoi. Il n'empêche que cela fait partie de l'information et que nous n'avons pas de raison de la taire ou de ne pas donner leur chance aux personnes concernées.

Déjà un point essentiel qui nous dérange avec ces pétitions. Alors que le mode examen est comme nous l'avons réexpliqué récemment une très grave régression du droit des candidats à l'égalité devant un examen, ici chacun ne semble penser qu'à lui. On le voit avec le fait qu'il y a des pétitions différentes selon les séries (tant pis pour les autres), et surtout par le fait qu'elles ne demandent toutes qu'une exception pour la seule session 2020 du BAC (tant pis pour les prochains).
Or non, demander une exception pour la seule session 2020 ne nous intéresse absolument pas, le problème resterait alors le même pour nous en 2021. :#non#:

Ensuite, la plupart des arguments développés sonnent faux. Ils parlent d'un effondrement des résultats et de l'obligation de redoubler dans le nouveau système alors que la notation s'adaptera forcément au niveau des copies pour donner un taux de réussite similaire. La décision serait injustifiée alors qu'il y a cette année à la fois la problématique des banques de sujets publiques pour les E3C du BAC 2021 (autant éviter d'avoir à appliquer simultanément deux réglementations différentes), et que c'est aussi possiblement une réponse (non optimale certes selon nous) à la gravissime fuite des sujets des BAC S/ES/L 2019 avec des élèves du lycée Ozar Hatorah de Créteil qui avaient acheté les sujets de Mathématiques (S/ES/L), Physique-Chimie (S) et Histoire-Géographie (S) à leur surveillant la veille au soir pour en mettre la correction dans leur calculatrice et la recopier le jour de l'épreuve; avec des retentissements nationaux puisque ça a circulé jusqu'à Marseille. Et surtout ils réclament l'accès aux "programmes d'aide", qui sous le reste de la rédaction et des commentaires ne semblent être que de vulgaires antisèches électroniques, précisément ce que la réglementation vise à bloquer ce qui nous semblerait donc délégitimer la demande en question.
C'est passer complètement complètement à côté des véritables problèmes du mode examen, visiblement malgré notre communication régulière sur ce thème depuis 2015 nous n'avons pas réussi à élever le niveau des débats; tout-le-monde reste focalisé sur ces antisèches numériques totalement inutiles aux épreuve scientifiques autorisant la calculatrice.

Un dernier point purement technique est qu'il nous semble maladroit d'adresser le texte non pas au Ministre de l'Education Nationale, mais directement au Premier Ministre ou à la Présidence de la République. Surtout qu'il s'agit d'une circulaire et non d'une loi. C'est-à-dire que même les prédécesseurs de ces derniers du temps de la conception de cette réglementation (2012-2014) n'ont jamais ni rédigé ni fait voter le texte en question et qu'ils ne sont peut-être même pas au courant de son existence.

Mais après tu restes libre de signer, surtout quand il n'y a pas d'alternative, et que créer une nouvelle pétition rédigée différemment risquerait de disperser les signatures encore plus qu'elles ne le sont déjà.

Liens :

Source : http://www.jeuxvideo.com/forums/42-51-6 ... c-2020.htm (contenu censuré depuis)
Lien vers le sujet sur le forum: Pétitions contre mode examen BAC 2020 #NonModeExamen (Commentaires: 20)

Le Secret de l'Avent 2019 jour 7: TI-Nspire CX II-T à gagner

Nouveau messagede critor » 07 Déc 2019, 00:00

11828En assemblant les indices et morceaux de Python quotidiens, gagne une superbe TI-Nspire CX II-T, la grande nouveauté de la rentrée 2019 ! :bj:

Sois le ou la première à nous communiquer la bonne réponse à ton choix en commentaire ou par courriel à info@tiplanet.org ! :D

? a écrit:... du moins dans cette adaptation.
Code: Tout sélectionner
    ...
    t+=" "*6
    t=htab(23,t)
    t+=str(tan(r))
    ...

Tu sèches ? Regarde l'indice précédent, ou encore le récapitulatif par edgar13.

Et si toujours rien, pour patienter d'ici le prochain indice, tu peux aller faire un petit tour sur le Puzzle de l'Avent 2019 par Planète Casio pour gagner une Graph 35+E II.
Lien vers le sujet sur le forum: Le Secret de l'Avent 2019 jour 7: TI-Nspire CX II-T à gagner (Commentaires: 1)

Nouveaux blisters TI-Nspire CX II-T Comenius EduMedia 2019

Nouveau messagede critor » 07 Déc 2019, 00:30

1162311624Pour la rentrée 2019, Texas Instruments a lancé en Europe ses nouvelles calculatrices TI-Nspire CX II-T et TI-Nspire CX II-T CAS.

Nous t'apprenions cette semaine que les deux modèles en question avaient été primés au Comenius EduMedia 2019 à Berlin ! :bj:
1150511506

1182711828Et bien ça n'a pas tardé, sans attendre la rentrée 2020 Texas Instruments met à jour dès cette année ses emballages.

Pour la TI-Nspire CX II-T par exemple la référence au verso on passe de NSCX2/BC/3E14/A à NSCX2/BC/3E14/B et nous indique donc que l'on passe de la version A à la version B.

Nouveauté justement, ils arborent désormais fièrement le sceau Comenius EduMedia 2019 ! :bj:
Lien vers le sujet sur le forum: Nouveaux blisters TI-Nspire CX II-T Comenius EduMedia 2019 (Commentaires: 1)

Le Secret de l'Avent 2019 jour 8: TI-Nspire CX II-T à gagner

Nouveau messagede critor » 08 Déc 2019, 00:00

11828En assemblant les indices et morceaux de Python quotidiens, gagne une superbe TI-Nspire CX II-T, la calculatrice qui tourne à 396 MHz ! :bj:

Sois le ou la première à nous communiquer la bonne réponse à ton choix en commentaire ou par courriel à info@tiplanet.org ! :D

? a écrit:Comme tu as dû le remarquer, cette adaptation de mon code est conçue pour tourner sur TI-83 Premium CE.

Mais sautons maintenant ligne 24...
Code: Tout sélectionner
  home()
  l=[]
  ...

... et sautons à nouveau ligne 56...
Code: Tout sélectionner
  t=len(l)
  l.append('VvVmAZfHcZmXhlAHOQmgiW')
  ...

Tu sèches ? Regarde l'indice précédent, ou encore le récapitulatif par edgar13.

Et si toujours rien, pour patienter d'ici le prochain indice, tu peux aller faire un petit tour sur le Puzzle de l'Avent 2019 par Planète Casio pour gagner une Graph 35+E II.
Lien vers le sujet sur le forum: Le Secret de l'Avent 2019 jour 8: TI-Nspire CX II-T à gagner (Commentaires: 6)

Résultat concours rentrée 2019 - défi langage calculatrice

Nouveau messagede critor » 08 Déc 2019, 15:11

Voici enfin aujourd'hui la fin des résultats de notre concours de rentrée 2019, plus précisément pour le défi en langage calculatrice.

Le défi te faisait ici travailler sur un automate cellulaire, dont un des plus connus est le jeu de la vie. Afin toutefois qu'il ne suffise pas d'exploiter l'un des nombreux travaux universitaires à ce sujet et donc de ne favoriser personne, les règles en étaient très éloignées :
  • deux populations au lieu d'une seule
  • chaque cellule n'était pas binaire (morte ou vivante) mais pouvait prendre 6 états différents (de bien morte à bien vivante) et ce pour chacune des populations
  • les deux populations utilisaient des règles de naissance/survie/mort différentes basées sur les états voisins, et également différentes de celles du jeu de la vie

Nous avons reçu un total de 109 participations de la part de 23 participants différents :
  • 3 participants ont utilisé une Casio Graph 90+E ou son logiciel d'émulation
  • 3 participants ont utilisé une TI-Nspire CX ou son logiciel d'émulation
  • 4 participants ont utilisé entre autres une TI-83 Premium CE Edition Python ou son logiciel d'émulation
  • 2 participants ont utilisé une HP Prime ou son logiciel d'émulation



22ème :
thecamouflage, lycéen en Terminale S à l'aide de sa Casio Graph 90+E, réalise dès le départ pas moins de 15 interventions divines :
  • 4 fois en faveur des Muens
  • puis 11 fois en faveur des Atlantes
Ce qui lui permet d'obtenir 15460 points en l'an 42.
Précisons que dans sa simulation les Atlantes emportent la victoire sur les Muens en l'an 64 ce qui donne un score maximal de 21970 points.


21ème :
ggauny@live.fr muni de sa fidèle HP Prime, intervient pour sa part 17 fois :
  • 4 fois pour aider les Atlantes
  • puis 13 fois pour aider les Muens
Ce qui lui donne 16588 points en l'an 42.
Précisons que dans sous cette configuration les Atlantes gagnent encore sur les Muens mais après pas moins de 173 ans, pour score final de 81410 points ! :D


20ème :
C'est muni de sa TI-83 Premium CE Edition Python qu'Azerpogba, lycéen en Première Spécialité Mathématiques+PC+SVT présent à la fois sur TI-Planet et sur Planète Casio, use 8 fois de son pouvoir divin sans favoritisme :
  • 4 fois à l'avantage des Muens
  • 4 fois à l'avantage des Atlantes
Ce qui l'amène à 16647 points en l'an 42.
Dans cette réalité alternative ce sont les Muens qui éradiquent les Atlantes mais dès l'an 87, pour un score terminal de 34787 points.


19ème :
Adoptant quant à lui la TI-Nspire CX, Ti64CLi++, élève en classe préparatoire MPSI, fréquentant aussi bien TI-Planet que Planète Casio, fait appel 11 fois à ses capacités divines :
  • 4 fois pour semer une colonies Muenne
  • puis 7 fois pour semer une colonies Atlante
Ce qui lui permet d'obtenir 16647 points en l'an 42.
Avec un tel semis, les Atlantes écrasent à leur tour les Muens ici encore assez vite, dès l'an 86, pour un ultime score de 29051 points.


18ème :
La TI-83 Premium CE Edition Python est maintenant de retour avec LePetitMage, lycéen en Terminale S, qui se mêle 11 fois mais de façon alternative des affaires humaines :
  • 5 fois à l'avantage des Muens
  • 6 fois à l'avantage des Atlantes
Une stratégie qui lui octroie 16699 points en l'an 42.
Ici encore la cohabitation n'est pas bien durable, les Atlantes régnant sans partage dès l'an 71, pour un score alors figé à 28455 points.


17ème :
Toujours sur TI-83 Premium CE Edition Python, grandben49 n'apparaît aux simples mortels qu'avec parcimonie, seulement 6 fois :
  • 3 fois pour créer une colonie Muenne
  • puis 3 fois pour créer une colonie Atlante
Il atteint ainsi 17257 points en l'an 42.
Une vision à plus long terme dans son cas, les Muens n'arrivant alors à exterminer les Atlantes qu'après 134 ans, pour un score définitif de 58203 points. :D


16ème :
La valeur n'attend point le nombre des années et Leno, collégien en Quatrième traînant aussi bien sur TI-Planet que sur Planète Casio, ne se mêle lui aussi que 6 fois des affaires inférieures :
  • prenant 3 fois parti pour les Muens
  • prenant 3 fois parti pour les Atlantes
Il récupère ainsi 17922 points en l'an 42.
Une bonne durabilité là encore, les Muens ne dominant alors le monde qu'après 144 ans, pour un score s'arrêtant alors à 52750 points. :D


15ème :
Astrostellar, lycéen en Terminale S, exerce lui aussi 6 fois ses talents de créateur :
  • 3 fois au service de la cause Muenne
  • 3 fois au service de la cause Atlante
Il encaisse ainsi 17989 points en l'an 42.
Mais hélas l'équilibre n'est sans lui qu'éphémère, les Muens triomphant alors après seulement 88 ans pour 35375 points.


14ème :
Encephalogramme, lycéen plus interventioniste en Première, invoque ses pouvoirs divins pas plus de 10 fois sur les 11 premières années :
  • 3 fois au au nom des Atlantes
  • puis 7 fois au nom des Muens
Il décroche ainsi 18142 points en l'an 42. :)
Une cohabitation de ces populations qui a le mérite de durer 247 ans, avant la victoire finale des Atlantes sur les Muens pour 117607 points ! :bj:


13ème :
C'est au nom des anciens dieux Commodore Amiga qu'Amiga68000 agit quant à lui 7 fois sur les 8 premières années :
  • 3 fois pour le bien des Atlantes
  • 4 fois pour le bien des Muens
Il décroche ainsi 18425 points en l'an 42. :)
Une durabilité toutefois en retrait, les Atlantes devant les maîtres du monde après 149 ans pour 65274 points. :D
Amiga68000 a écrit:
Voici mon code, et vu mon classement vous comprendrez que ma méthode n'est pas la meilleure.
J'ai fait des tirages aléatoires en paramétrant (en en tirant aléatoirement) :
  • la taille zone de départ où mettre les habitants (variables carrex et carrey)
  • le nombre d’habitants
Voilà les 2 fonctions utilisées: atmu=run(100,False)
  1. 100 = nombre de tirages de 42 ans
  2. 0 = pas de limite
  3. True = sauvegarde de chaque tirage pour faire des statistiques
Routine qui à partir d'une composition fait varier chaque position de chaque habitant et prend la meilleure configuration : variercompo()

Et le code global ci-contre (merci Pavel pour la transpo sur PC).
Code: Tout sélectionner
from math import log10,sqrt

from random import randint
import csv




from math import log10,sqrt
from tkinter import *




def color(r, g, b):
  return '#%02x%02x%02x' % (r, g, b)

def fill_rect(x, y, w, h, color):
  y += 18
  canvas.create_rectangle(x, y, x + w, y + h, fill=color, outline='')

def draw_string(text, x, y, fg=color(0,0,0), bg=None):
  y += 18
  t = canvas.create_text(x, y, anchor=NW, text=text, fill=fg)
  if bg is not None:
    r = canvas.create_rectangle(canvas.bbox(t), fill=bg, outline='')
    canvas.tag_lower(r, t)

def clear():
  canvas.delete('all')
  canvas.create_rectangle(0, 18, 320, 240, fill=color(255, 255, 255), outline='')
  canvas.create_rectangle(0, 0, 320, 18, fill=color(255, 183, 52), outline='')

def init():
  global atmu,n,j,s,ma,mb,mc,w,fp,fm
  atmu,n,j,s,w,fp,fm=[],9,0,0,5,0,0
  ma,mb,mc=[[0]*n for k in range(n)],[[0]*n for k in range(n)],[[0]*n for k in range(n)]

def dr():
  global s,j,w
  sw=320
  d,h=min(sw//n,221//n),(color(0,0,0),color(255,255,255))
  b=sw-1-n*d
  clear()
  for i in range(0,n*d+1,d):
    fill_rect(b,i,n*d,1,h[0])
    fill_rect(b+i,0,1,n*d,h[0])
  for y in range(0,n):
    for x in range(0,n):
      t=255-(255*abs(ma[y][x])//w)
      fill_rect(b+x*d+1,y*d+1,d-1,d-1,ma[y][x]<0 and color(t,t,255) or ma[y][x]>0 and color(255,t,t) or h[1])
  draw_string(" ATLEMU ",1,1,color(255,255,0),color(127,127,127))
  draw_string("Muen\ndo(-1,c,l)",0,19,color(0,0,255),h[1])
  draw_string("Atlante\ndo(1,c,l)",0,53,color(255,0,0),h[1])
  draw_string("Passer\ndo(0)",0,87,color(255,0,255),h[1])
  draw_string("Recommencer\ninit()",0,121,color(0,0,0),h[1])
  draw_string("An: "+str(j)+"\nScore:\n"+str(s)[:10],0,n*d-49)

def do(*ar):
  global j,gp,gm,fp,fm,s
  j,k,v,(sc,sl)=j+1,ar[0],(len(ar)%2) or ar[len(ar)-1],(len(ar)>=3) and (ar[1],ar[2]) or (0,0)
  k,gp,gm=k and k//abs(k),fp,fm
  for y in range(n):mb[y]=mc[y].copy()
  for y in range(n):
    for x in range(n):
      o,ma[y][x]=ma[y][x],ma[y][x]+w*(ma[y][x]==0 and x==sc and y==sl)*((k>0)-(k<0))+(ma[y][x]<=0 and (x-sc or y-sl or k==0) and mb[y][x]//10==3)*((ma[y][x]==0)*w-ma[y][x]*(not(not(ma[y][x]))))-(ma[y][x]>=0 and (x-sc or y-sl or k==0) and mb[y][x]-10*(mb[y][x]//10)==3)*((ma[y][x]==0)*w+ma[y][x]*(not(not(ma[y][x]))))
      if o and ma[y][x]==o:
        ls=(-1,w>abs(ma[y][x]))
        ma[y][x]=ma[y][x]+(ma[y][x]>0)*ls[mb[y][x]//10==3 or mb[y][x]//10==4]-(ma[y][x]<0)*ls[mb[y][x]-10*(mb[y][x]//10)==3 or mb[y][x]-10*(mb[y][x]//10)==2]
      if ma[y][x]-o:
        fp,fm=fp+(ma[y][x]>0 and not(o))-(o>0 and not(ma[y][x])),fm+(ma[y][x]<0 and not(o))-(o<0 and not(ma[y][x]))
        if not(o) and ma[y][x] or o and not(ma[y][x]):
          for dl in range(-1,2):
            for dc in range(-1,2):
              if dl or dc:mc[y+dl+(dl<0 and y==0)*n-(dl>0 and y==n-1)*n][x+dc+(dc<0 and x==0)*n-(dc>0 and x==n-1)*n]+=(ma[y][x]<0)-(o<0 and 0==ma[y][x])+10*((ma[y][x]>0)-(o>0 and 0==ma[y][x]))
  if max(fp,gp)*max(fm,gm):s=s/(1+abs(k)*log10(sqrt(j)))+fp*fm*min(fp,gp)*min(fm,gm)/max(fp,gp)/max(fm,gm)
  atmu.append((sc*k+k,sl*k+k))
  if v:
    dr()
#    print("Bon score ? Envoie la liste\n'atmu' a info@tiplanet.org")
  return s

def st(l,v=True):
  init()
  for p in l:s=do((p[0]>0)-(p[0]<0),abs(p[0])-1,abs(p[1])-1,v)
  dr()
  return s





 
 
#  ************************************************************************************
#  **
#  ** SUB PERSO
#  **
#  ************************************************************************************

rep="D:/_Datas/_Datas PERSO/Python-atlemu"

def sauvecsv(v,nom=rep + "/sansnom.csv",m="w"):
  #sauvegarde une matrice p en csv
  #with open("L:/_Datas/11 - Arnaud/Python - DEFI/table.csv", "w") as f_write:
    with open(nom, m) as f_write:
        writer = csv.writer(f_write,delimiter=";")
        writer.writerow(v) #        writer.writerows(v) si plusieurs lignes
    return
   
def sauvetxt(v,nom=rep + "/sansnom.txt"):     
    fichier = open(nom,"w")
    fichier.write(str(v))
    fichier.close()
       
    return
 

 

def run(nbboucles,sauvechaquetirage=False):
  global atmumax
 
  smax=0
  boucle=0
  moyscore=0
 
  while boucle<nbboucles or nbboucles==0:
    boucle+=1
   
    init()
    if boucle%100==0:print("run "+str(boucle)+" Max="+str(smax))
 
    carrex= randint(2,4)
    carrey= randint(2,4)
   
    zonex=9-carrex
    zoney=9-carrey
   
    x1=randint(1,zonex)
    y1=randint(1,zoney)
    x2=randint(1,zonex)
    y2=randint(1,zoney)
   
    nbhabitants=12 #randint(3,5)
   

    for k in range(nbhabitants-1): #nombre d'habitants  par couleur
#      l=randint(0,carre)
#      m=randint(0,carre)
   
        do(1,x1+randint(0,carrex),y1+randint(0,carrey) )
        do(-1,x2+randint(0,carrex),y2+randint(0,carrey) )

#        nx1=x1+randint(0,carrex)
#        ny1=y1+randint(0,carrey)       
#        if ma[nx1-1][ny1-1]!=0:
#              s=do(0)
#        else:
#              do(1,nx1,ny1)
#               
#        nx2=x2+randint(0,carrex)
#        ny2=y2+randint(0,carrey)
#        if ma[nx2-1][ny2-1]!=0:
#              s=do(0)
#        else:
#              do(-1,nx2,ny2)

    s=do(0)
    s=do(0)
    do(1,x1+randint(0,carrex),y1+randint(0,carrey) )
    do(-1,x2+randint(0,carrex),y2+randint(0,carrey) )
       

    while j<42:
      s=do(0)
     
    moyscore+=s
       
    if s>smax:
      smax=s
      atmumax=list(atmu)
      print("---")
      print("#"+str(smax))
      print("#"+str(atmumax))
      print("---")
      print("Carre X="+str(carrex))
      print("Carre Y="+str(carrey))
      print("Nb habitants="+str(nbhabitants))
      print("---")
     
      if not(sauvechaquetirage):
             sauvertirage(smax,nbhabitants,0,carrex,carrey,atmumax) 
     

    if sauvechaquetirage:
      sauvertirage(s,nbhabitants,0,carrex,carrey,atmu) 
 
     
     
  print("#"+str(smax))
  print("#st("+str(atmumax)+",False)")
  print("#"+str(smax))
  moyscore=moyscore/nbboucles
  print("#"+str(moyscore))
 
  st(atmumax,False)
 
  return atmumax

 
def sauvertirage(score,nbhabitants,surface,carrex,carrey,compo):
    if surface==0:
        surface=carrex*carrey
    e=[]
    e.append(score)
    e.append(nbhabitants)
    e.append(surface)
    e.append(carrex)
    e.append(carrey)
    e.append(compo)
    sauvecsv(e,rep+"/stat-tirages.csv","a")
    return
 
   
def variercompo():
    compo=[(7, 2), (-4, -7), (8, 2), (-2, -7), (7, 4), (-3, -7), (0, 0), (-4, -9), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0)]

    smax=0
    atmumax=[]
    s=st(compo,False)
    smax=s
    atmumax=list(atmu)
   
    for k in range(len(compo)):
        print("k="+str(k))
       
        hab=compo[k]
        x=hab[0]
        y=hab[1]
        if x!=0:

            #on fait varier les positions
            plage=[-1,0,1]
            for deltax in plage:
                nx=x+deltax
                for deltay in plage:
                    ny=y+deltay
                   
                    #on a la nouvelle position nx,ny
                    ncompo=list(compo)
                    print(ncompo[k])
                    ncompo[k][0]=nx
                    ncompo[k][1]=ny

                    #on teste la compo
                    s=st(ncompo,False)
                   
                    #
                    if s>smax:
                        smax=s
                        atmumax=list(atmu)
                        print("---")
                        print("#"+str(smax))
                        print("#"+str(atmumax))
                        print("---")
                        print("Carre X="+str(carrex))
                        print("Carre Y="+str(carrey))
                        print("Nb habitants="+str(nbhabitants))
                        print("---")

    return
   
   
   
   
 
master = Tk()
master.resizable(0, 0)
canvas = Canvas(master, width=320, height=240)
canvas.pack()


sauvertirage("Score","nb habitants","surface","carre X","carre Y","Sequence")

init()
dr()
variercompo()
#atmu=run(100,False)
#sauvetxt(atmu,rep+"/CompoAtmu.txt")

#affichage
if __name__== "__main__":master.mainloop()


#st([(7, 2), (-4, -7), (8, 2), (-2, -7), (7, 4), (-3, -7), (0, 0), (-4, -9), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0)],False)
#18425.217793183947

#st([(7, 2), (-4, -7), (8, 2), (-2, -7), (7, 4), (-3, -7), (0, 0), (-4, -9), (0, 0), (-3, -9), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0)],False)
#18390.75048739328

#18381.309236990124
#[(7, 2), (-4, -7), (8, 2), (-2, -7), (7, 4), (-3, -7), (8, 2), (-4, -9), (7, 4), (-3, -9), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0)]
#18381.309236990124

#18168.450679791244
#[(9, 7), (-4, -8), (9, 8), (-4, -7), (7, 8), (-2, -8), (9, 8), (-4, -8), (8, 6), (-4, -9), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0)]
#18168.450679791244

#18049.830151963542
#[(9, 3), (-5, -3), (7, 3), (-5, -2), (9, 2), (-5, -4), (7, 2), (-3, -4), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0)]
#18049.830151963542

#18035.99025478949
#[(3, 3), (-8, -7), (2, 3), (-7, -6), (3, 4), (-9, -6), (4, 3), (-7, -7), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0)]
#18035.99025478949

#18003.837819596458
#[(3, 3), (-4, -8), (3, 4), (-4, -7), (5, 3), (-2, -8), (2, 2), (-5, -9), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0)]
#18003.837819596458

#17841.546235752416
#[(4, 4), (-8, -2), (4, 5), (-8, -3), (2, 5), (-6, -3), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0)]

#17781.124608967286
#[(4, 7), (-8, -6), (3, 6), (-9, -7), (5, 6), (-7, -7), (4, 7), (-8, -6), (3, 5), (-9, -8), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0)]

#17605.76772889996
#[(2, 9), (-7, -6), (3, 9), (-7, -7), (2, 8), (-5, -7), (4, 7), (-5, -7), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0)]

#17425
#[(4, 5), (-8, -3), (4, 4), (-8, -4), (4, 3), (-6, -4), (3, 3), (-6, -3), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0)]
viewtopic.php?f=49&t=23051&start=150#p248013


12ème :
Ne0tuX hantant à la fois TI-Planet et Planète Casio, met la main à la pâte 9 fois sur les 13 premières années :
  • 5 fois pour aider les Atlantes
  • 4 fois pour aider les Muens
Il est ainsi récompensé de 18467 points en l'an 42. :D
Saluons la durée exceptionnelle de cohabitation de ces deux populations, les Muens devant attendre pas moins de 263 ans pour régner en maîtres absolus, pour pas moins de 130039 points ! :bj:
Ne0tuX a écrit:Félicitations à tous les participants et aux instigateurs de l'épreuve ! J'ai trouvé ce défi particulièrement intéressant pour les raisons suivantes :
  • Contrairement au défi précédent, l'ordre des éléments a un sens ce qui complique les choses ;
  • La lois de l'automate cellulaire ne sont pas explicitement lisibles dans le code ce qui pousse à l'expérimentation on calc ;
  • L'automate n'est pas bijectif, mais surjectif (sésolé si ce ne sont pas les bons termes, qu'on me corrige s'il y a mieux). Autrement dit, même si on trouve une configuration de la 42ème année qui donne un bon score, on ne peut pas remonter le temps pour déterminer une séquence d'implantation des colonies (pas à ma connaissance du moins).
Pour ce qui est de ma méthode, j'ai pressenti que l'algorithme génétique n'était pas terrible à l'état brut (voir la première raison ci-dessus). J'ai donc rapidement implémenté en Python un recuit simulé (rien de sorcier sur la forme) mais j'ai vite compris que TOUT reposait sur le paramétrage et surtout sur la définition du mouvement élémentaire, qu'il faut définir avec beaucoup de soin et de façon intelligente. Par manque de temps et d'investissement je n'avais ni l'un ni l'autre donc j'ai coupé court... J'aurais vraiment aimé explorer ce problème, mais n'ai finalement fait que quelques essais directement sur TI-Nspire (très belle animation d'arrière plan au passage) en remarquant globalement les mêmes observations que celles postées précédemment sur ce topic.

J'ai hâte de lire toutes les méthodes employées et je n'exclus pas d'en expérimenter quelques-unes pour le plaisir !
viewtopic.php?f=49&t=23051&start=140#p247951


11ème :
Thomas F. se retrousse les manches pas plus de 10 fois sur les 12 premières années :
  • 4 fois pour aider les Atlantes
  • 6 fois pour aider les Muens
Le voici ainsi pourvu de 18835 points en l'an 42. :D
Par contre c'est bien moins solide, les Atlantes faisant disparaître les derniers Muens après seulement 86 ans pour 30546 points.
Thomas F. a écrit:J'ai placé 3 civilisations de chaque couleur. Il m'a fallu un peu de temps pour comprendre le fait que la grille était semblable à un tore. Puis un peu plus pour constater que l'ordre avait aussi son importance. Du coup j'ai lancé une recherche de la meilleure configuration de départ pour mes 2 lignes de 3 civilisations. Enfin, j'ai lancé des boucles de recherche de meilleurs scores avec des civilisations aléatoires dans les 6 tours suivant. J'ai fait le choix totalement arbitraire de ne pas explorer plus loin dans le temps l'implantation de nouvelles civilisations. Voilà, c'est pas transcendant comme démarche, mais je n'ai pas trouvé mieux en trois jours.


10ème :
edgar13, lycéen en Première Spécialité Mathématiques+PC+SVT accompagné de sa fidèle TI-83 Premium CE Edition Python présent à la fois sur TI-Planet et sur Planète Casio modère le monde 11 fois :
  • 6 fois pour la gloire Atlantes
  • 5 fois pour la gloire des Muens
L'an 42 le récompense alors de 19013 points ! :D
La durabilité est améliorée, avec les Muens qui ne signent l'arrêt de mort des Atlantes que l'an 148 avec 64383 points. :D
edgar13 a écrit:Alors moi aussi j'ai commencé sur TI-83 Premium CE mais c’était très long! :(
Avec la TI-83 Premium CE j'ai compris que 6 colonies suffisaient pour devenir autonomes et qu'il valait mieux ne rien faire pour gagner plus de points. Finalement lundi soir à 20h Zocipal m'a un peu aidé, il m'a fait remarquer que le programme existait aussi en Python. Et là avec un simple brute force j'ai fait 19013. :whistle:
A vrai dire je ne comprends pas pourquoi il existe aussi la version python alors que c'est le défi basic. :?
C'était une force brute mais je ne l'ai fait tourner que 2h. :)
Après j'ai dormi. :D
viewtopic.php?f=49&t=23051&start=140#p247946


9ème :
RdB armé de sa puissance HP Prime choisit d'éditer le monde 9 fois sur les 10 premières années :
  • 5 fois pour augmenter Atlantes
  • 4 fois pour augmenter Muens
Il arrive ainsi à 19236 points en l'an 42 ! :D
Mais les Atlantes font maintenant disparaître les Muens après 116 ans pour 46842 points.


8ème :
M4x1m3 lycéen en Terminale S altère 10 fois la réalité :
  • 3 fois en faveur des Atlantes
  • 7 fois en faveur des Muens
Il se classe ainsi à 19534 points en l'an 42 ! :D
Meilleure durabilité puisque les Atlantes ne triomphent des Muens qu'après 193 ans pour 78423 points ! :D


7ème :
C'est muni de sa TI-Nspire CX qu'Extra44 agit 10 fois :
  • 5 fois en l'honneur des Muens
  • 5 en l'honneur des Atlantes
Il obtient ainsi 19743 points en l'an 42 ! :D
Meilleure durabilité puisque les Atlantes gagnent leur dernier combat dès l'an 96 avec 36335 points.
Extra44 a écrit:Voila pour ma part mon explication de ma démarche.
NB : L'explication sera malheureusement générale, car mon PC portable qui servait pour les essais a planté (carte mère), et je n'ai plus accès à mes fichiers tns intermédiaires (je n'ai pas encore pu réinstaller le logiciel TI Nspire CAS Software).

Bon ma méthode pour avoir le score max est composé de plusieurs points :
  • quelques essais manuels pour voir comment àa marche
  • décodage du code (compressé ;) ) et voir à quoi correspondent les variables sur la version ti nspire, donc en Langage LUA
  • afficher des résultats pour arriver à décoder le code (affichage consultable dans la console de l'éditeur LUA du logiciel TI-Nspire Software)
  • Modifier le code pour n'avoir au final qu'un affichage du score dans la console (plus d'affichage intermédiaire)
  • Faire une version LUA sans affichage graphique et qui ne ressort que le résultat final en fonction d'une entrée sous forme de liste
  • On peut passer maintenant à faire des algo pour trouver un bon score...
  • J'ai essayé le score aléatoire ... mais ce n'est pas fameux ;)
  • J'ai remarqué qu'il faut au moins 3 colonies d'une population pour qu'elle puisse croître ...Donc un minimum de 2x3 = liste de 6 éléments minimum
  • J'ai remarqué que si l'ajout d'une colonie n'est pas optimal, il peut réduire fortement le score !
  • Ensuite, pour accélérer les recherches, j'ai converti le code LUA en C++ et j'ai compilé des versions successives en C++, pour plus de rapidité. J'ai ajouté parfois ...
    • une partie d'algo de recherche aléatoire (entre 6 et 20..22..40 colonies)
    • une partie d'algo génétique, mais apparemment je n'ai pas trouvé/obtenu le bon démarrage.
    • une partie d'algo d'optimisation de bon résultats,
    • Tout cela me permettait d'arriver rapidement à chaque fois aux 17000/18000/18800 points.
    • Sur un bon résultat, je l'ai modifié à la main, et réussit à obtenir mon score final de 19743 pts
    • J'ai fait tourner ma machine pendant 2/3/4 jours avant qu'elle ne plante, (le mercredi de la dernière semaine du concours)
    • Puis en changeant de machine (je passais d'un i5 à un i3 ;-( ), j'ai essayé d'autres algos, d'autres paramètres d'algo génétique sans obtenir de meilleur résultats ;-(
Bravo encore aux organisateurs pour ce joli concours, et aux participants ! ;-)
viewtopic.php?f=49&t=23051&p=249019#p249019


6ème :
Sentaro21 sévissant à la fois sur TI-Planet et sur Planète Casio fait réaliser 9 miracles à sa Casio Graph 90+E :
  • 3 en faveur des Atlantes
  • 6 en faveur des Muens
Il atteint ainsi 19907 points en l'an 42 ! :D
Et c'est du solide, les Muens ne remportant leur ultime bataille qu'en l'an 225 avec 108463 points ! :bj:
sentaro21 a écrit:Thank you very much for the contest again this year. Animation is very good. ;)
The result is clear at a glance. There is no content that I can explain in particular. I quickly found out that the first few steps were important, but I couldn't stabilize the two countries. As a result, I got results only by trial and error with the calculator just like last year. :p
In this participate, Casio's traditional language Basic was too slow. However, it was very good that it was able to work with C.Basic. :D
viewtopic.php?f=49&t=23051&start=160#p248950


5ème :
Zocipal, lycéen en Première Spécialité Maths-PC-NSI, intervient équitablement 8 fois :
  • 4 fois pour aider les Atlantes
  • 4 fois pour aider les Muens
Il franchit ainsi un cap symbolique avec pas moins de 20130 points en l'an 42 ! :bj:
C'est un peu plus fragile, les deux populations n'arrivant à cohabiter que jusqu'à l'an 142, où seuls les Atlantes subsisteront avec 62652 points. :D


4ème :
Golden Man, lycéen en Terminale S, intervient pour sa part pas moins de 12 fois :
  • 5 fois pour avantager Atlantes
  • 7 fois pour avantager les Muens
Il passe ainsi à 20311 points en l'an 42 ! :bj:
Un net mieux en terme de cohabitation, qui dure maintenant jusqu'à l'an 183, où ne resteront que les Muens avec 78167 points ! :D
Golden Man a écrit:Après le concours de rentrée 2019 - Le défi Python / Pokémon passionnant nous nous sommes attaqué au défi historique, proposé par les sites internet TI-Planet et Planète Casio et les équipes de bénévoles passionnés qui animent ces communautés.


LE CONTEXTE
Il existait autrefois au coeur du grand océan appelé Pacifique un empire, l’empire de Mu. Grâce à l’énergie du soleil qu’ils avaient réussi à maîtriser complètement les Lémuriens menaient une vie tranquille et prospère. A la même époque, une autre civilisation celle de l’Atlantide régnait au centre de l’autre océan, l’Atlantique. Les Atlantes eux aussi savaient contrôler la puissance du soleil et ils avaient construit un puissant empire.
Mais un jour, la guerre éclata entre la terre de Mu et l’Atlantide pour une raison si insignifiante que l’histoire elle-même l’a oubliée. La guerre dura longtemps, de nombreuses années, car les forces des deux puissances étaient égales. Jusqu’au jour où les hommes firent usage de l’arme solaire. C’est ainsi que ces deux grandes civilisations disparurent, englouties au fond des deux océans…

Tu n’as rien compris ? Normal, cela fait parti du challenge !
(lire l’intégralité du défi : Concours de rentrée 2019 - défi langage historique)

Il était possible de participer avec un script en Casio-Basic, TI-Basic, ou en Python. Nous avons bien évidement choisi le langage Python pour sa souplesse, et la capacité que nous avions à le faire tourner sur un PC sur divers IDE Python.

Dans la suite de l’article, le "nous" fait référence aux participants cent20 et Golden Man, car nous avons réalisé les recherches en commun.


PREMIERS TESTS
Tout commence par des premiers tests à la main, et en tout premier lieu nous avons commencé par neutraliser le traitement graphique du script, les affichages textes, pour chercher à l’aveugle par ce que sinon cela n’est pas assez difficile...
Code: Tout sélectionner
from math import log10,sqrt
def init():
    global atmu,n,j,s,ma,mb,mc,w,fp,fm
   
    atmu = []
    n = 9
    j = 0
    s = 0
    w = 5
    fp = 0
    fm = 0
    ma = [[0]*n for k in range(n)]
    mb = [[0]*n for k in range(n)]
    mc = [[0]*n for k in range(n)]

"""
A CREUSER

def dr():
    global s,j,w # sjw (je sais pas si c'est fait expres, mais c'est tres drole)
    sw=320
    d,h=min(sw//n,221//n),(color(0,0,0),color(255,255,255))
    b=sw-1-n*d
   
    for i in range(0,n*d+1,d):
        fill_rect(b,i,n*d,1,h[0])
        fill_rect(b+i,0,1,n*d,h[0])
       
    for y in range(0,n):
        for x in range(0,n):
            t=255-(255*abs(ma[y][x])//w)
            fill_rect(b+x*d+1,y*d+1,d-1,d-1,ma[y][x]<0 and (t,t,255) or ma[y][x]>0 and (255,t,t) or h[1])
           
    draw_string(" ATLEMU ",1,1,color(255,255,0),color(127,127,127))
    draw_string("Muen\ndo(1,c,l)",0,19,color(0,0,255),h[1])
    draw_string("Atlante\ndo(-1,c,l)",0,53,color(255,0,0),h[1])
    draw_string("Passer\ndo(0)",0,87,color(255,0,255),h[1])
    draw_string("An: "+str(j)+"\nScore:\n"+str(s)[:10],0,n*d-49)
   
"""

def do(*ar):
   
    global j,gp,gm,fp,fm,s
   
    j = j+1 # Indice de la liste des couples et nombre d'annees
    k = ar[0] # Notre premier argument (le camp choisi (ou passer))
    v = (len(ar)%2) or ar[len(ar)-1] # v = 1 ou 0 selon la longueur (3 ou 1)
    (sc,sl) = (len(ar)>=3) and (ar[1],ar[2]) or (0,0) # Les deux derniers
   
    # permet de recuperer les deux derniers elements de do(a,b,c)
    # a = equipe ; b = colonnes ; c = lignes
   
    k = k and k//abs(k) # Change pas k (fausse piste je pense)
   
    # Changement de nom
    gp = fp
    gm = fm
   
    for y in range(n):
        # mb possiblement une sauvegarde
        # mc devient une copie de mb
        mb[y]=mc[y].copy()
       
    for y in range(n):
        for x in range(n):
           
            o = ma[y][x]
           
            # Le gros tas
            ma[y][x] = ma[y][x]+w*(ma[y][x]==0 and x==sc and y==sl)*((k>0)-(k<0))+(ma[y][x]<=0 and (x-sc or y-sl or k==0) and mb[y][x]//10==3)*((ma[y][x]==0)*w-ma[y][x]*(not(not(ma[y][x]))))-(ma[y][x]>=0 and (x-sc or y-sl or k==0) and mb[y][x]-10*(mb[y][x]//10)==3)*((ma[y][x]==0)*w+ma[y][x]*(not(not(ma[y][x]))))
           
            if o and ma[y][x]==o:
               
                ls=(-1,w>abs(ma[y][x]))
                ma[y][x]=ma[y][x]+(ma[y][x]>0)*ls[mb[y][x]//10==3 or mb[y][x]//10==4]-(ma[y][x]<0)*ls[mb[y][x]-10*(mb[y][x]//10)==3 or mb[y][x]-10*(mb[y][x]//10)==2]
           
            if ma[y][x]-o:
               
                fp = fp+(ma[y][x]>0 and not(o))-(o>0 and not(ma[y][x]))
                fm = fm+(ma[y][x]<0 and not(o))-(o<0 and not(ma[y][x]))
               
                if not(o) and ma[y][x] or o and not(ma[y][x]):
                    for dl in range(-1,2):
                        for dc in range(-1,2):
                            if dl or dc:
                                mc[y+dl+(dl<0 and y==0)*n-(dl>0 and y==n-1)*n][x+dc+(dc<0 and x==0)*n-(dc>0 and x==n-1)*n]+=(ma[y][x]<0)-(o<0 and 0==ma[y][x])+10*((ma[y][x]>0)-(o>0 and 0==ma[y][x]))
    if max(fp,gp)*max(fm,gm):
        s=s/(1+abs(k)*log10(sqrt(j)))+fp*fm*min(fp,gp)*min(fm,gm)/max(fp,gp)/max(fm,gm)
   
    # The final code !
    # Il est ici
    # Chaque elements est de la forme (sc*k+k,sl*k+k)
   
    atmu.append((sc*k+k,sl*k+k))
   
    if v:
        # dr()
        print("Bon score ? Envoie la liste\n'atmu' a info@tiplanet.org")
    return s
def st(l,v=False):
    init()
    for p in l:
       
        # C'est ici qu'on triche !
        # On va pas utiliser une liste de couple, mais une liste de liste
        # comme ca, c'est modifiable comme on veut
       
        # J'ai mis v sur False pour pas avoir le message "Bon score..."
       
        s=do((p[0]>0)-(p[0]<0),abs(p[0])-1,abs(p[1])-1,v)
    # dr()
    return s
init()

actions = [[0,0] for k in range(42)]
rien = [0,0]
scores = []
refscores = []
def chasse():
    for k in range(100): # On va tester au max
        for i in range(42):
            scores = []
            for t in [-1,1]:
                for col in range(1,10):
                    for lig in range(1,10):
                        actions[i] = [t*(col+1),t*(lig+1)]
                        scores.append(st(actions))
                        refscores.append([t,col,lig])
            actions[i] = rien
            scores.append(st(actions))
            refscores.append(rien)
            if refscores[scores.index(max(scores))] != rien:
                actions[i] = [refscores[scores.index(max(scores))][0]*(refscores[scores.index(max(scores))][1]+1),refscores[scores.index(max(scores))][0]*(refscores[scores.index(max(scores))][2]+1)]
            else:
                actions[i] = rien
            print("Annee",i,":",max(scores))


Tout commence avec des tirages aléatoires très aléatoires sans aucune réflexion, et ayant réussi à fabriquer une liste de 5 couples avec un score acceptable (on le pense alors !), on essaye de l’améliorer, et de tirer d’autres listes de 5 couples acceptables.
Code: Tout sélectionner
import random
def aleat5():
    m = 42
    l = [(-2,-2), (2,3), (-2,-4), (2,5), (-4,-3)] # la liste de départ
    while len(l)<m:
        l.append((0,0))
    scoremax = st(l)
    print("score liste : ", scoremax)
    equipe = [1, -1]
    l = []
    tirage = 0   
    while scoremax <100000:
        tirage+=1
        l = []
        for i in range(5):       
            random.shuffle(equipe)
            l.append((equipe[0]*random.randint(1,9),equipe[0]*random.randint(1,9)))
        while len(l)<m:
            l.append((0,0))
        scorerandom = st(l)   
       
        if scorerandom > scoremax:
            print("Meilleur score", scorerandom)
            print("Liste",l[0:5])
            scoremax = scorerandom
        if tirage%1000==0:
            print("Tirages aléatoire : ",tirage)

Cette méthode est un échec, les scores générés ne dépassent pas 100 ! Nous pensions que 100 était en score acceptable car on l’a comparé naïvement au score maxi de 43.x obtenu sur le défi précédent.


ET SI ON EN TIRAIT 10 COUPLES ?
Au lieu de tirer 5 couples, on décide d’en tirer 10.

Pour rappel à ce stade nous sommes toujours aveugles, nous n’avons aucun rendu graphique à analyser pour affiner notre stratégie.
Code: Tout sélectionner
import random
def aleat10():
    m = 42
    scoremax = 100
    print("score aleat5 : ", scoremax)
    equipe = [1, -1]
    tirage = 0   
    while scoremax <100000:
        tirage+=1
        l = []
        for i in range(10):       
            random.shuffle(equipe)
            l.append((equipe[0]*random.randint(1,9),equipe[0]*random.randint(1,9)))
        while len(l)<m:
            l.append((0,0))
        scorerandom = st(l)       
        if scorerandom > scoremax:
            print("Meilleur score", scorerandom)
            print("Liste",l[0:10])
            scoremax = scorerandom
        if tirage%1000==0:
            print("Tirages aléatoire : ",tirage)

Assez rapidement, on obtient des score aux alentours de 16000-17000.

Comme au pays des aveugles les borgnes sont rois, on décide alors de continuer les tirages aléatoires de n couples et dans le même temps de développer notre propre couche graphique histoire d’y voir quelques choses et de laisser passer un peu de lumière...
Meilleur score 16685.07457023799
Liste [(-8, -3), (-4, -6), (-9, -1), (-1, -1), (4, 7), (-5, -4), (5, 9), (6, 7), (-4, -3), (-2, -5)]
Meilleur score 17304.672747006774
Liste [(7, 6), (5, 7), (7, 5), (-4, -7), (-3, -5), (-5, -5), (-3, -9), (-6, -5), (-3, -5), (-9, -8)]



TIRAGES ALÉATOIRES DE N COUPLES
Bien évidemment, on lance les fonctions aleatn(annee) avec des valeurs pour la variable annee comprise entre 1 et 42 mais tout ceci est très long, un unique script tourne sur un unique IDE Python.
Code: Tout sélectionner
def aleatn(annee):
    m = 42
    scoremax = 100
    print("score kiki : ", scoremax)
    tirage = 0   
    while scoremax <100000:
        tirage+=1
        l = []
        for i in range(annee):
            l.append(((-1)**i*random.randint(1,9),(-1)**i*random.randint(1,9)))
        while len(l)<m:
            l.append((0,0))
        scorerandom = st(l)
        if scorerandom > 15000:
            print("bon score", scorerandom)
            print("Liste",l[0:annee])
        if scorerandom > scoremax:
            print("========== Meilleur score : ", scorerandom)
            print("================== Liste = ",l[0:annee])
            scoremax = scorerandom
        if tirage%1000==0:
            print("Tirages aléatoire : ",tirage)



LA PROBLÉMATIQUE DU MULTI-THREAD
Nous n’arrivons pas à faire tourner nos scripts en multi thread sur Python en utilisant les outils adéquates, nous commençons donc par faire du multi thread manuel :
  • 2 PCs = 2 scripts qui tournent 😄
  • 3 IDE = 3 scripts qui tournent. 😅
  • 2 PCs avec 3 IDE = 6 scripts 🤣

Et puis sur pycharm nous arrivons enfin à faire tourner 10-12 scripts en parallèle.
(oui enfin, nous avions autant de fichiers que de [i]threads, cela ressemblait vraiment à un classeur d’élève de 2nde)[/i]

Maîtrisant le multi thread cela fut le début de folles nuits des tirages aléatoires
Il faut bien occuper le Ryzen 7 2700 et ses 16 threads !


La première nuit, les fonctions aleatn(annee) furent lancées avec tous les entiers possible entre 4 et 14.
Je vais me coucher. J’ai lancé les 10 scripts en parallèle on verra demain matin si on a cassé le score de Pavel.


Et le lendemain matin les résultats furent dépouillées.


DES NOUVELLES DE LA COUCHE GRAPHIQUE
En parallèle, nous nous sommes occupés de recréer l’interface graphique en l’améliorant légèrement pour pouvoir voir comment le programme fonctionnait et, accessoirement, ce que l’on obtenait avec nos tirages.

Nous avons choisit tKinter pour ce travail et fixé un cahier des charges :
  • Un espace pour voir la grille.
  • Un petit commentaire pour expliquer le fonctionnement de la GUI.
  • Une reconnaissance de l’entrée des touches pour entrer les do() plus vite.
  • Un espace pour entrer des commandes spéciales (st() par ex). La détection des touches doit être désactivée pour saisir
  • Un historique :
    • Une grille (plus visuelle).
    • Sous forme de texte.
Ainsi, il a fallu créer la fenêtre.
Code: Tout sélectionner
interface = Tk()
interface.resizable(False,False)
interface.title('Concours AT//MU')

# Utilisable
utilisable = Frame(interface,borderwidth=0)
utilisable.pack(side=LEFT)
canevas = Canvas(utilisable,width=500,height=400,bg="white")
canevas.pack(side=TOP)
saisie = StringVar()
barreSaisie = Entry(utilisable,width=60,textvariable=saisie)
barreSaisie.pack(side=RIGHT)
barreSaisie.configure(state="readonly")
label = Label(utilisable,text="'W' pour (ne plus) ecrire")
label.pack(side=LEFT)
labelScore = canevas.create_text(10,240,text="An : 0 // Score = 0",anchor=NW)
canevas.create_text(10,270,text="Appuyez sur + ou - sur le clavier numerique pour choisir votre camp",anchor=NW)
canevas.create_text(10,290,text="Puis, toujours sur le clavier numerique, selectionnez votre colonne puis votre ligne avec les",anchor=NW)
canevas.create_text(10,305,text="touches 1 a 9.",anchor=NW)
canevas.create_text(10,325,text="Attention, la case (1;1) est la case en haut a gauche !",anchor=NW)
canevas.create_text(10,345,text="Pour passer une annee, appuyez sur le point du clavier numerique.",anchor=NW)
canevas.create_text(10,365,text="Pour recommencer une partie, appuyez sur 'R'.",anchor=NW)
canevas.create_text(10,385,text="Il est possible de rentrer des commandes speciales a tout moment en appuyant sur 'W'.",anchor=NW)

# Historique
historique = Frame(interface,borderwidth=0)
historique.pack(side=RIGHT)
canevasHist = Canvas(historique,width=400,height=230,bg="white")
canevasHist.pack(side=TOP)
listeHist = ScrolledText(historique,width=50,height=11)
listeHist.pack(side=BOTTOM)

Ceci étant fait, on crée une fonction récupérant les événements claviers.

Attention : On prend bien soin de lier cette fonction à la fenêtre : interface.bind("<Key>",event)
Cette ligne envoie à la fonction event() la valeur quand une touche est pressée.
Code: Tout sélectionner
isWriting = False
commande = ["","",""]
index = 1

def event(touche):
    global isWriting,index,commande
    touche = touche.keysym
    if touche == "w":
        if isWriting:
            barreSaisie.configure(state="readonly")
            saisie.set("do("+commande[0]+","+commande[1]+","+commande[2]+")")
        else:
            barreSaisie.configure(state="normal")
            saisie.set("")
        isWriting = isWriting == False # paradoxe du menteur
    if touche == "r":
        init()
        dr(2,0,0)
    if touche == "plus" and not isWriting:
        commande[0]="1"
    if touche == "minus" and not isWriting:
        commande[0]="-1"
    if touche == "BackSpace" and not isWriting:
        commande[index-1] = ""
        if index > 1:
            index -= 1
    if touche == "1" and not isWriting and index<3:
        commande[index] = "0"
        index += 1
    if touche == "2" and not isWriting and index<3:
        commande[index] = "1"
        index += 1
    if touche == "3" and not isWriting and index<3:
        commande[index] = "2"
        index += 1
    if touche == "4" and not isWriting and index<3:
        commande[index] = "3"
        index += 1
    if touche == "5" and not isWriting and index<3:
        commande[index] = "4"
        index += 1
    if touche == "6" and not isWriting and index<3:
        commande[index] = "5"
        index += 1
    if touche == "7" and not isWriting and index<3:
        commande[index] = "6"
        index += 1
    if touche == "8" and not isWriting and index<3:
        commande[index] = "7"
        index += 1
    if touche == "9" and not isWriting and index<3:
        commande[index] = "8"
        index += 1
    if touche == "Return":
        try:
            eval(saisie.get())
            saisie.set("")
            index=1
            commande=["","",""]
        except:
            print("aie")
    if touche == "period" and not isWriting:
        do(0)
    if not isWriting:
        saisie.set("do("+commande[0]+","+commande[1]+","+commande[2]+")")

Mais, un problème de taille était toujours présent, modifier la couche graphique pré-codée avec kandinsky.

Voici donc ce qu’on a pu faire.
Code: Tout sélectionner
def dr(camp,xHist,yHist):
    global s,j,w,labelScore
    sw=320
    d=min(sw//n,221//n)
    b=sw-1-n*d
   
    for i in range(0,n*d+1,d):
        canevas.create_rectangle(b,10+i,b+n*d,i+11,fill=hexColor(0,0,0),outline="")
        canevas.create_rectangle(b+i,10,b+i+1,n*d+10,fill=hexColor(0,0,0),outline="")
        canevasHist.create_rectangle(b,10+i,b+n*d,i+11,fill=hexColor(0,0,0),outline="")
        canevasHist.create_rectangle(b+i,10,b+i+1,n*d+10,fill=hexColor(0,0,0),outline="")
       
    if camp != 0 and camp != 2:
        t=255-(255*abs(ma[yHist][xHist])//w)
        canevasHist.create_rectangle(b+xHist*d+1,yHist*d+11,b+xHist*d+d,yHist*d+10+d,fill=camp<0 and hexColor(t,t,255) or camp>0 and hexColor(255,t,t),outline="")
        listeHist.insert(END,str((xHist*camp+camp,yHist*camp+camp))+"\n")
    elif camp == 0:
        listeHist.insert(END,"(0, 0)\n")
    else:
        listeHist.delete(1.0,END)
       
    for y in range(0,n):
        for x in range(0,n):
            t=255-(255*abs(ma[y][x])//w)
            canevas.create_rectangle(b+x*d+1,y*d+11,b+x*d+d,y*d+10+d,fill=ma[y][x]<0 and hexColor(t,t,255) or ma[y][x]>0 and hexColor(255,t,t) or hexColor(255,255,255),outline="")
            if camp == 2:
                canevasHist.create_rectangle(b+x*d+1,y*d+11,b+x*d+d,y*d+10+d,fill=ma[y][x]<0 and hexColor(t,t,255) or ma[y][x]>0 and hexColor(255,t,t) or hexColor(255,255,255),outline="")
           
           
    canevas.itemconfig(labelScore,text="An: "+str(j)+" // Score: "+str(s)[:10])

On remarque que les couleurs sont générées au moyen d’un code RGB, or tKinter n’accepte que des chaines de caractères, donc (cours de NSI ;) ), on convertit les valeurs en hexadécimal et on crée un code de la forme "#rrggbb".
Code: Tout sélectionner
def hexColor(r,g,b):
    r = "0" + hex(r)[2:]
    g = "0" + hex(g)[2:]
    b = "0" + hex(b)[2:]
    return "#"+r[len(r)-2:len(r)]+g[len(g)-2:len(g)]+b[len(b)-2:len(b)]

On obtient ainsi le résultat suivant.

Bon au cours du développement de cette couche graphique, on a constaté que Pavel avait codé la sienne de son coté et qu’il l’avait rendue publique pendant le concours. Heureusement bien peu ont compris l’importance de ces simulations graphiques.


ANALYSE DES RÉSULTATS
A partir de là, nous avons commencé à faire des tirages aléatoires sans IA.

Les 30 000 000 de tirages réalisés pendant la nuit furent analysés en détails, et des grilles de sudoku furent coloriées pour identifier les positions initiales de 6 couples ayant de gros scores.

Nous avons eu confirmation que cela ressemblait au jeu de la vie et avons compris quelques règles :
  • Il faut semer 3 cases différentes mais proches d’une même colonie pour avoir un développement exponentiel.
  • Quand les colonies Atlantes et Muennes se rencontrent, elles se détruisent. Une trop forte densité d’une colonie amène aussi à son auto destruction par le centre.
  • Il existe des états stables mais nous ne les avons pas trouvé optimaux en terme de score à la fin de l’an 42.
  • Le score monte plus vite si les deux colonies se développent, donc aleatn(5) ne produira jamais un gros score, aleatn(6) lui peut faire un gros score.
Pour affiner les résultats, nous avons décidé de sauvegarder les bonnes listes et non plus uniquement les meilleures listes.


NUITS DE FOLIE : 6 À 12 SCRIPTS QUI TOURNENT EN PARALLÈLE
Quelques nuits de folies plus tard ...
Code: Tout sélectionner
listealeat = []
tirage = [0 for k in range(42)]

best_list =  []
best_scor = 0

good_list = []
good_scor = []
good_indice = 0

def sauvegarde(sauveliste,score,tirage,annee):
    global best_indice, best_scor, good_list, good_scor, good_indice, best_list
    if score > 15500: #Le chiffre de 15500 a régulièrement été augmenté
        # On sauvegarde les listes de couples donnant 15500 min
        good_list.append(sauveliste)
        good_scor.append(score)
        good_indice+=1
    if score > best_scor:
         # On sauvegarde la meilleur liste trouvée
        best_list = sauveliste[0:annee]
        best_scor = score
        print("\n======= Meilleur score ======== tirage n° ",tirage, "sur",annee, "années ======== ")
        print("Score : ",score)
        print("liste = ",best_list[0:annee])

def calcule_score(liste,tirage,annee):
    m=42
    sauveliste = liste
    # print(sauveliste)
    # input()
    while len(liste)<m:
        liste.append((0,0))
    score = st(liste)
    sauvegarde(sauveliste,score,tirage,annee)

def forcealeat(annee,nbtirage):
    global best_scor, good_indice
    for j in range(nbtirage):
        listealeat = []
        tirage[annee]+=1
        for i in range(annee):
                listealeat.append(((-1)**i*random.randint(1,9),(-1)**i*random.randint(1,9)))
                # le choix de faire un coup négatif un coup positif peut se discuter...
                random.shuffle(listealeat)
        calcule_score(listealeat,tirage[annee],annee) 
    print(30*"##")
    print("fini,",nbtirage, "tirages de",annee, "couples aléatoires")
    print("bonne liste : ",good_indice)
    print("MeilleurScore : ",best_scor)
    print("liste = ",best_list)

def forcealeatgeometrie6(annee,nbtirage):
    global best_scor, good_indice
    for j in range(nbtirage):
        listealeat = []
        tirage[annee]+=1
        col1 = random.randint(1,6)
        lig1 = random.randint(1,9)
        col2 = random.randint(1,9)
        lig2 = random.randint(1,6)
        listealeat.append((col1,lig1))
        listealeat.append((col1+1,lig1))
        listealeat.append((col1+2,lig1))
        listealeat.append((-1*col2,-1*lig2))
        listealeat.append((-1*col2,-1*(lig2+1)))
        listealeat.append((-1*col2,-1*(lig2+2)))
        random.shuffle(listealeat)
        calcule_score(listealeat,tirage[annee],annee) 
    print(30*"##")
    print("fini,",nbtirage, "tirages de",annee, "couples aléatoires")
    print("bonne liste : ",good_indice)
    print("MeilleurScore : ",best_scor)
    print("liste = ",best_list)



JEUX AVEC LE MOTEUR GRAPHIQUE
A l’aide du moteur graphique, on a pu analyser les figures donnant des états stables. C’est à dire qu’à partir d’une configuration donnée, on obtient une configuration qui n’évolue plus dans le temps.

Ainsi, on obtient les résultats suivants.

1er état stable, avant-après :

2ème état stable, avant-après :

Un 3ème, très joli :

Avec ces états, on observe un autre comportement du programme, les bords interagissent entre eux.


TIRAGES ALÉATOIRES AVEC IA
Nos résultats étaient satisfaisants et ils nous permettait d’obtenir un score supérieur à 18 000, mais beaucoup de tirage étaient gâchés car l’algorithme manquait de discernement.

Nous avons alors repris les coloriages et amélioré notre script de tirage. L’heure de l’IA avait sonné.
Oui on utilise facilement le mot IA alors que ... on a juste réfléchit et que les scripts sont eux toujours aussi stupides.

Ce script a réalisé à lui tout seul plus de 20 000 000 de tirage, déjà parce qu’il était beau, et ensuite parce que nous voulions obtenir une liste significative de tirage ayant un score supérieur à 18 000.

forcealeatIA(6,7000000) nous au ainsi donné 154 tirages certifiés supérieurs à 18 000.
Code: Tout sélectionner
def forcealeatIA(annee, nbtirage):
    global best_scor, good_indice
    for j in range(nbtirage):
        listealeat = []
        tirage[annee] += 1
        na = random.randint(1, 9)
        ma = random.randint(1, 9)
        nlist = [max(na - 1, 1), na, min(na + 1, 9)]
        mlist = [max(ma - 1, 1), ma, min(ma + 1, 9)]
        pa = random.randint(1, 9)
        qa = random.randint(1, 9)
        plist = [max(pa - 1, 1), pa, min(pa + 1, 9)]
        qlist = [max(qa - 1, 1), qa, min(qa + 1, 9)]
        for i in range(annee // 2):
            listealeat.append((random.choice(nlist), random.choice(mlist)))
            listealeat.append(((-1) * random.choice(plist), (-1) * random.choice(qlist)))
        random.shuffle(listealeat)
        goodliste(listealeat, tirage[annee], annee)
    print(30 * "##")
    print("fini,", nbtirage, "tirages de", annee, "couples aléatoires")
    print("bonne liste : ", good_indice)
    print("MeilleurScore : ", best_scor)
    print("liste = ", best_list)

Ces tirages ont alors été mélangés aléatoirement, histoire de s’assurer vérifier que un autre ordre ne nous donnerait pas un meilleur score.

La variable goodliste contenait à ce moment là une liste de listes, nos 154 listes que nous avons mélangés 100 000 fois procédant ainsi à 15 000 000 nouveaux tirages.
Code: Tout sélectionner
def improve_liste():
    global goodliste
    listetraiteeok = 0
    for listeatraiter in goodliste:
        listetraiteeok += 1
        annee = len(listeatraiter)
        for i in range(100000):
            listemelange = listeatraiter[0:annee]
            random.shuffle(listemelange)
            calcule_score(listemelange, i, annee)
        if listetraiteeok % 10 == 0:
            print("liste mélangées :", listetraiteeok, "1000 fois")

In fine, nous avons obtenu trois 4 listes ayant un score supérieur à 19 000.
Code: Tout sélectionner
[(-1, -4), (-2, -5), (8, 1), (-3, -5), (7, 1), (7, 3)]
[(2, 3), (2, 4), (-6, -7), (1, 2), (-6, -9), (-5, -7)]
[(5, 3), (7, 3), (7, 4), (-1, -7), (-3, -7), (-1, -6)]
[(5, 5), (4, 5), (4, 3), (-6, -8), (-5, -8), (-4, -8)]

MeilleurScore : 19207.913058803344
liste = [(5, 5), (4, 5), (4, 3), (-6, -8), (-5, -8), (-4, -8)]



DERNIÈRE APPROCHE GAGNANTE
La dernière approche (gagnante) fut de procéder par force brute sur des listes ayant un bon patrimoine génétique.

Nous avions à notre disposition des nombreuses listes courtes avec des scores supérieur à 18 000 voir 19 000. Et si nous cherchions à les rallonger ?

Certains résultats obtenus par forcealeatIA(9,1000000) étaient surprenant. Certaines listes de 9 couples avaient un bon score, mais si on ne prenait que la liste des 6 premiers couples le score était mauvais.

Un script sur mesure fut donc codé.

La variable goodliste contenait à ce moment là une unique liste, que l’on voulait compléter.
  • add_liste(goodliste, an, 1) quelques secondes, 163 tirages
  • add_liste(goodliste, an, 2) quelques minutes, 26 569 tirages
  • add_liste(goodliste, an, 3) quelques heures, plus de 4 000 000 de tirages
Nous n’avons pas testé add_liste(goodliste, an, 4) par manque de temps.

Par contre, sur 6,8,12 thread le script add_liste(goodliste, an, 3) a tourné non stop sur des listes sélectionnées avec amour au moyen des scripts forcealeatIA(annee, nbtirage) qui continuait à tourner, dès fois que ...
Code: Tout sélectionner
def add_liste(listeatraiter, annee, rangsup=1):
    liste = listeatraiter.copy()
    # on essaie avec (0,0)
    liste.append((0, 0))
    listescore = liste.copy()
    calcule_score(listescore, 0, annee + 1)
    if rangsup - 1 > 0:
        add_liste(liste, annee + 1, rangsup - 1)
    liste.pop(len(liste) - 1)
    # on essaie avec (+,+)
    for i in range(1, 10, 1):
        for j in range(1, 10, 1):
            liste.append((i, j))
            listescore = liste.copy()
            calcule_score(listescore, 10 * i + j, annee + 1)
            if rangsup - 1 > 0:
                add_liste(liste, annee + 1, rangsup - 1)
            liste.pop(len(liste) - 1)
    # on essaie avec (-,-)
    for i in range(-9, 0, 1):
        for j in range(-9, 0, 1):
            liste.append((i, j))
            listescore = liste.copy()
            calcule_score(listescore, 10 * i + j, annee + 1)
            if rangsup - 1 > 0:
                add_liste(liste, annee + 1, rangsup - 1)
            liste.pop(len(liste) - 1)

an = len(goodliste)
add_liste(goodliste, an, 2)
print(good_list)



CHRONOLOGIE DES SCORES OBTENUS
  1. 15/10 17:00 : 15016
    Pour l’instant on pédale dans la semoule
    global s,j,w # sjw, je ne sais pas si c’est fait exprès mais...
  2. 15/10 19:34 : 17142
    On n’a toujours aucun graphique ni aucune idée de ce qui se passe mais si ça ressemble fortement à des multiplications matricielles.
  3. 16/10 14:16 : 18157
    Score de la nuit sur 10 000 000 de tirages pas vraiment optimisés.
  4. 23/10 10:30 : 18860
    Objectif 19000 avant la fin de la journée.
  5. 23/10 11:30 : 19117
    Prochain objectif : 19430 (pour doubler un autre candidat).
  6. 24/10 10:07 : 19675
    Finalement 19430 n’était qu’une formalité.
    Maintenant pour aller jusqu’à 21700 il va falloir trouver une autre méthode, celle-ci est un peu longue, mais comme il faut chauffer un peu la maison je ne suis responsable d’aucun meurtre supplémentaire de pingouin.
  7. 24/10 21:13 : 20180
    500 points de plus ! Et c’est pas fini !
  8. 28/10 22:12 : 20475
    Il me tarde de savoir comment a fait Pavel parce que j’ai tout donné et que j’ai 7 scripts qui moulinent sur mon PC...
  9. 28/10 22:12 : 20972
    Je ne perds pas espoir de finir 1er, mais stratégiquement je me dis que j’ai peut-être intérêt à envoyer mes scores le dernier jour pour que le 1er ne puisse pas réagir...
    C’est beau de rêver ... 20972 fut notre meilleur score.


CONCLUSIONS
Une estimation basse du nombre de tirages que nous avons réalisé donne 100 000 000 de tirages. Mais comme les scripts tournaient non stop en parallèle, nous pensons qu’on s’approche plus des 200 000 000 de tirages et simulations diverses pas du tout optimales.

Ne maîtrisant pas encore les exports / imports CSV en Python nous avons été limités par la nécessité d’arrêter manuellement les scripts, de copier / coller les bons résultats et de relancer les scripts, mais pour le défi de l’année prochaine nous seront prêts.

Félicitation une nouvelle fois à Pavel qui a dominé les 3 épreuves mais semble ne pas partir avec les mêmes connaissances de base que le simple visiteur des sites TI-Planet et Planète Casio.

L’année prochaine, il est probable que l’on donnera le concours Python en devoir maison facultatif aux élèves de spé NSI de Terminale de notre lycée, histoire de voir s’ils ont fixé des connaissances et s’ils font preuve d’initiative et d’autonomie.

Se classer dans les 10 premiers : 18/20, coefficient 0,42.
Se classer devant le prof : 20/20, coefficient 0,666.
https://nsi.xyz/concours-de-rentree-201 ... -en-python


3ème :
Afyu n'interfère quant à lui que 10 fois :
  • 3 fois pour les Atlantes
  • 7 fois pour les Muens
Ce qui fait la différence avec 20453 points en l'an 42 ! :bj:
Une longévité de plus exceptionnelle, les Atlantes mettant pas moins 277 ans à achever les derniers Muens pour 136275 points ! :bj:
Afyu a écrit:Voici comment j'ai procédé pour la résolution du défi en langage historique :

J'ai effectué mes premiers essais sur la ressource NumWorks proposée pour le concours, avec des do(1,c,l) et des do(-1,c,l) qui permettent de placer des civilisations rouges ou bleues en indiquant la position en ligne et en colonne (vivement l'implémentation du getkey() pour simplifier tout ça !).

Après quelques (nombreux) essais, j'ai découvert que le score augmentait bien plus vite lorsqu'on "oubliait" de placer une colonie et qu'on laissait passer une année. J'ai donc essayé de réduire fortement le nombre de colonies à placer et un nombre de colonies autour de 10 semblait être bien.

J'ai également découvert que le score n'augmente pas tant qu'il n'y a qu'une civilisation (donc qu'une seule couleur) de placée. De plus, il faut au minimum 3 colonies d'une même civilisation pour que cette dernière se développe. Donc il faut au minimum 6 colonies (3 pour chaque civilisation) pour que les deux civilisations se développent. Dernier point : pour qu'une civilisation se développe, il faut que les 3 colonies placées soient les voisines d'une même cellule vide pour y faire apparaître une colonie (une ressemblance avec le Jeu de la vie de John Conway ? :D).

Partant de ce constat et trouvant que taper des do(+-1,c,l) est assez fastidieux, j'ai commencé à automatiser le placement de mes colonies, en utilisant la programmation en Python. J'ai repris le programme de la ressource NumWorks et je l'ai un peu modifié, mais hors ressource NumWorks, pour gagner en confort (de modification, de vitesse et de capacité de mémoire de travail).

À la fin du programme, j'ai ajouté quelques lignes pour initialiser une liste de colonies à placer, puis pour modifier aléatoirement des éléments de cette liste et pour déterminer et afficher le score obtenu avec cette liste.

On initialise la liste de colonies à placer à (0,0) pour chacune des 42 années (donc 42 colonies). Ensuite, on répète 50 000 fois l'essai suivant : on choisit un nombre entier entre 0 et 9 pour modifier une des 10 premières colonies à placer, puis on modifie le couple de coordonnées de cette colonie à placer, en essayant de placer une colonie Muenne, puis une colonie Atlante.
Code: Tout sélectionner
from random import randint
liste0=[(0,0)]*42
liste=liste0[:]
st(liste)
for k in range(50000):
    a=randint(0,9)
    liste[a]=(-randint(1,9),-randint(1,9))
    st(liste)
    liste[a]=(randint(1,9),randint(1,9))
    st(liste)


Ensuite, j'ai modifié mon programme pour n'afficher le score obtenu que s'il est meilleur que le meilleur score déjà obtenu. Il faut donc stocker le meilleur score obtenu et comparer chaque nouveau score avec ce meilleur score. On initialise donc une liste scores qui stocke les meilleurs scores obtenus et une liste gagnant qui stocke les listes correspondantes. On stocke la valeur -1 dans scores pour s'assurer que le premier test effectué (sur une liste de 42 couples à (0,0)) stocke bien un score à 0, associé à une liste de couples à (0,0) dans gagnant.
Code: Tout sélectionner
scores=[-1]
gagnant=[]

Dans le programme, j'ai remplacé la ligne qui affiche "Bon score ? Envoie la liste 'atmu' à ..." par mon test de comparaison et un éventuel stockage du nouvau score obtenu. On vérifie si on a atteint la 42ème année et si le nouveau score obtenu est meilleur que l'actuel meilleur score. Si c'est le cas, on ajoute la nouvelle meilleure liste à gagnant et le nouveau meilleur score à scores et on affiche cette nouvelle meilleure liste, puis ce nouveau meilleur score, l'année (pour vérification) et enfin la longueur de la liste (pour vérification). Le # affiché en début de sortie me permet de faire un copier-coller de cette nouvelle meilleure liste pour remplacer ma liste0, tout en gardant une trace du score associé et sans avoir à commenter ce score pour ne pas avoir d'erreur à l'exécution.
Code: Tout sélectionner
        if j==42 and s>scores[-1]:
            gagnant.append(liste[:])
            print(liste)
            scores.append(s)
            print("#",s,j,len(liste))


Le stockage de la meilleure liste n'est pas indispensable, un simple affichage suffit. Mais je la stocke pour la reprendre après un certain nombre d'essais infructueux. Je ne sais pas si c'est la meilleure stratégie, mais elle m'a semblée plutôt efficace.
J'initialise à 0 une variable nb_chgt qui stocke le nombre de changements effectués, au même moment que je crée ma liste0. Ensuite, j'ajoute à la fin de mon programme quelques lignes qui permettent d'augmenter le compteur du nombre de changements effectués, puis de récupérer la dernière meilleure liste stockée après un certain nombre de changements effectués.
Code: Tout sélectionner
   nb_chgt+=1
    if nb_chgt=20:
    nb_chgt=0
    liste=gagnant[-1]


J'aurais sûrement pu éviter de stocker dans la liste gagnant TOUS les meilleurs scores obtenus et ne garder que le dernier. Pour ça, il faut déclarer la variable gagnant comme étant globale et non pas locale, je crois, mais je ne maîtrise pas cette subtilité et je n'ai pas cherché comment faire. :D

J'ai ensuite laissé tourner ce programme durant de nombreuses heures/jours/semaines, en espérant améliorer mon score jusqu'à l'infini et au-dela !
J'ai remarqué qu'une liste qui comporte des couples de (0,0) entre des colonies assure souvent un meilleur score en les supprimant et en rapprochant du début de la liste les dernières colonies placées. :)
Par exemple, la liste [(5, 5), (5, 4), (7, 4), (-2, -6), (-2, -5), (-2, -4), (-6, -1), (-2, -1), (-3, -3), (0, 0), (-8, -9)] donne un score de 20300 tandis que la liste [(5, 5), (5, 4), (7, 4), (-2, -6), (-2, -5), (-2, -4), (-6, -1), (-2, -1), (-3, -3), (-8, -9)] donne un score de 20453, simplement en avançant la dernière colonie à la place du (0,0).

Parmi les autres essais que j'ai effectués :
Je vais appeler seed une liste assez courte de civilisations à placer, suivies de couples tous à (0,0) jusqu'à atteindre 42 années.
J'ai essayé de trouver le meilleur seed de 6 de long, puis de 7 de long, jusqu'à 10 de long. J'ai donc modifié le randint(0,9) pour que le choix des colonies à modifier ne soit plus parmi les 10 premières, mais seulement parmi les 6 premières randint(0,5), etc.

Uniquement pour la recherche du meilleur seed de 6 de long, j'ai effectué une recherche exhaustive (enfin, je crois :D) en choisissant soit de placer 3 colonies Atlantes suivies de 3 colonies Muennes, soit d'alterner les colonies. C'est lors de ces essais que j'ai constaté qu'on obtenait souvent (toujours ?) un meilleur score en plaçant d'abord les colonies Atlantes. Pour éviter de multiplier les essais, j'ai raisonné en terme de symétrie et de distance. Par symétrie, on peut placer la première colonie (liste[0]) au milieu de la grille (donc en (5,5)) et placer la 2ème colonie (liste[1]) de la même civilisation dans 1/8 de disque et à une distance de maximum 2 de la colonie placée au centre (ce qui laisse donc seulement 5 cellules à tester : (5,4);(5,3);(6;4);(6;3);(7;3) tous les autres cas pouvant être obtenus par symétrie de ces 5). De même, la 3ème colonie (liste[2]) de la même civilisation est à placer à une distance de maximum 2 de chacune des deux premières colonies placées (pour assurer l'apparition d'une 4ème colonie, etc), ce qui limite beaucoup le nombre de positions possibles.
Pour les colonies de l'autre civilisation, je les ai placées en parcourant toute la grille et en respectant une distance de maximum 2 entre les colonies placées avec
Code: Tout sélectionner
for k in range(c-2,c+2+1):
    cc=(k+9-1)%9+1
la position cc de la nouvelle colonie à placer varie entre c-2 et c+2 avec c la position de la précédente colonie placée de la même civilisation et la position cc de la nouvelle colonie à placer est modifiée si elle est inférieure à 1 ou supérieure à 9 pour être ramenée dans la grille, en considérant que cette dernière est un tore (donc 0 devient 9 et -1 devient 8 et 10 devient 1 et 11 devient 2). Ma précédente approche pour cette distance inférieure à 2 était d'utiliser for cc in range(max(1,c-2),min(c+2,9)+1): qui oublie quelques cas particuliers lorsqu'une colonie est proche d'un bord de la grille, donc à oublier.
Cette recherche exhaustive ressemble donc à :
Code: Tout sélectionner
liste[0]=(5,5)
liste[1]=(5,4)

for a in range(5,7+1):
  for b in range(3,6+1):
     
    for c in range(1,9+1):
      for d in range(1,9+1):
        print(a,b,c,d)
        for k in range(c-2,c+2+1):
          cc=(k+9-1)%9+1
          for l in range(d-2,d+2+1):
            dd=(l+9-1)%9+1
            for kk in range(c-2,c+2+1):
              ccc=(kk+9-1)%9+1
              for ll in range(d-2,d+2+1):
                ddd=(ll+9-1)%9+1
                liste[2]=(-a,-b)
                liste[3]=(c,d)
                liste[4]=(cc,dd)
                liste[5]=(ccc,ddd)
                st(liste)
Et pour alterner les civilisations, il suffit de remplacer l'ordre 0,1,2,3,4,5 des indices x donnés dans liste[x] par 0,2,4,1,3,5.


J'ai obtenu un score de 19207 avec [(5, 5), (5, 4), (7, 4), (-2, -6), (-2, -5), (-2, -4)] qui est a compléter avec des (0,0) pour atteindre 42 années.

À partir de ce score, j'ai essayé de trouver le meilleur score en complétant avec une 7ème colonie, puis une 8ème, jusqu'à 11 ou 12. Essayer de placer plus de 12 colonies ne m'a jamais donné un meilleur score, alors j'ai fini par ne tester que jusqu'à 12.

J'ai également essayé, en partant d'une liste avec un bon score, de parcourir toutes les positions possibles pour deux couples qui se suivent (de rangs rang1 et rang2) de la liste.
Code: Tout sélectionner
rang1=9
rang2=rang1+1
for a in range(0,10):
  print(a)
  for b in range(0,10):
    print(b)
    for aa in range(0,10):
      for bb in range(0,10):
        liste[rang1]=(a,b)
        liste[rang2]=(aa,bb)
        st(liste)
        liste[rang2]=(-aa,-bb)
        st(liste)
        liste[rang1]=(-a,-b)
        st(liste)
        liste[rang2]=(aa,bb)
        st(liste)


Autre essai effectué : en partant d'une liste donnant un score de 20266 (liste [(5, 5), (5, 4), (7, 4), (-2, -6), (-2, -5), (-2, -4), (5, 9), (-6,-1), (-6, -8), (-8, -6), (-3, -8), (0, 0), (-6, -5)] à compléter jusqu'à 42 années) j'ai essayé de décaler de 0 ou de 1, horizontalement ou verticalement, vers la gauche ou vers la droite, vers le haut ou vers le bas, chacune des colonies placées en espérant améliorer mon score... sans succès. :(
Code: Tout sélectionner
for i1 in [-1,0,1]:
  for j1 in [-1,0,1]:
    for i2 in [-1,0,1]:
      for j2 in [-1,0,1]:
        for i3 in [-1,0,1]:
          for j3 in [-1,0,1]:
            for i4 in [-1,0,1]:
              for j4 in [-1,0,1]:
                print(i1,j1,i2,j2,i3,j3,i4,j4,100*((i1+1)/3+(j1+1)/9+(i2+1)/27+(j2+1)/81+(i3+1)/243+(j3+1)/729+(i4+1)/2187)+(j4+1)/6561)
                for i5 in [-1,0,1]:
                  for j5 in [-1,0,1]:
                    for i6 in [-1,0,1]:
                      for j6 in [1]:
                        for i7 in [-1,0,1]:
                          for j7 in [-1,0,1]:
                            liste=[(5, 5), (5, 4), (7, 4), (-2, -6), (-2, -5), (-2, -4), (5+i1, 9+j1),(-6+i2, -1+j2), (-6+i3, -8+j3), (-8+i4, -6+j4), (-3+i5, -8+j5), (0+i6, 0+i6), (-6+i7, -5+j7), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0,0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0)]
                            st(liste)
La ligne avec les fractions permet simplement d'afficher le pourcentage d'avancement de la recherche.


J'ai obtenu de nombreux scores entre 20000 et 20453, sans jamais faire mieux. En voyant le détail de la liste proposée par Pavel, j'ai compris (mais un peu tard) qu'une liste qui donne un excellent score ne provient pas forcément d'un seed qui donne un très bon score. Ma recherche des meilleurs seed n'était donc pas la meilleure stratégie, mais quand on ne connait ni le recuit simulé, ni les algorithmes génétiques... :p

Je tiens à remercier toutes les personnes qui ont permis l'organisation de ce concours avec un aussi grand nombre de lots de qualité ! Merci !! :D
viewtopic.php?f=49&t=23051&p=249030#p249029


2nd :
cent20 n'intervient lui que 9 fois :
  • 3 fois pour doper les Atlantes
  • puis 6 fois pour doper les Muens
Il nous repousse ainsi le record à pas moins de 20972 points en l'an 42 ! :bj:
Dommage toutefois que cela dure moins, les Atlantes ne mettant que 102 ans à conquérir le monde pour 44277 points.
cent20 a écrit:Après le concours de rentrée 2019 - Le défi Python / Pokémon passionnant nous nous sommes attaqué au défi historique, proposé par les sites internet TI-Planet et Planète Casio et les équipes de bénévoles passionnés qui animent ces communautés.


LE CONTEXTE
Il existait autrefois au coeur du grand océan appelé Pacifique un empire, l’empire de Mu. Grâce à l’énergie du soleil qu’ils avaient réussi à maîtriser complètement les Lémuriens menaient une vie tranquille et prospère. A la même époque, une autre civilisation celle de l’Atlantide régnait au centre de l’autre océan, l’Atlantique. Les Atlantes eux aussi savaient contrôler la puissance du soleil et ils avaient construit un puissant empire.
Mais un jour, la guerre éclata entre la terre de Mu et l’Atlantide pour une raison si insignifiante que l’histoire elle-même l’a oubliée. La guerre dura longtemps, de nombreuses années, car les forces des deux puissances étaient égales. Jusqu’au jour où les hommes firent usage de l’arme solaire. C’est ainsi que ces deux grandes civilisations disparurent, englouties au fond des deux océans…

Tu n’as rien compris ? Normal, cela fait parti du challenge !
(lire l’intégralité du défi : Concours de rentrée 2019 - défi langage historique)

Il était possible de participer avec un script en Casio-Basic, TI-Basic, ou en Python. Nous avons bien évidement choisi le langage Python pour sa souplesse, et la capacité que nous avions à le faire tourner sur un PC sur divers IDE Python.

Dans la suite de l’article, le "nous" fait référence aux participants cent20 et Golden Man, car nous avons réalisé les recherches en commun.


PREMIERS TESTS
Tout commence par des premiers tests à la main, et en tout premier lieu nous avons commencé par neutraliser le traitement graphique du script, les affichages textes, pour chercher à l’aveugle par ce que sinon cela n’est pas assez difficile...
Code: Tout sélectionner
from math import log10,sqrt
def init():
    global atmu,n,j,s,ma,mb,mc,w,fp,fm
   
    atmu = []
    n = 9
    j = 0
    s = 0
    w = 5
    fp = 0
    fm = 0
    ma = [[0]*n for k in range(n)]
    mb = [[0]*n for k in range(n)]
    mc = [[0]*n for k in range(n)]

"""
A CREUSER

def dr():
    global s,j,w # sjw (je sais pas si c'est fait expres, mais c'est tres drole)
    sw=320
    d,h=min(sw//n,221//n),(color(0,0,0),color(255,255,255))
    b=sw-1-n*d
   
    for i in range(0,n*d+1,d):
        fill_rect(b,i,n*d,1,h[0])
        fill_rect(b+i,0,1,n*d,h[0])
       
    for y in range(0,n):
        for x in range(0,n):
            t=255-(255*abs(ma[y][x])//w)
            fill_rect(b+x*d+1,y*d+1,d-1,d-1,ma[y][x]<0 and (t,t,255) or ma[y][x]>0 and (255,t,t) or h[1])
           
    draw_string(" ATLEMU ",1,1,color(255,255,0),color(127,127,127))
    draw_string("Muen\ndo(1,c,l)",0,19,color(0,0,255),h[1])
    draw_string("Atlante\ndo(-1,c,l)",0,53,color(255,0,0),h[1])
    draw_string("Passer\ndo(0)",0,87,color(255,0,255),h[1])
    draw_string("An: "+str(j)+"\nScore:\n"+str(s)[:10],0,n*d-49)
   
"""

def do(*ar):
   
    global j,gp,gm,fp,fm,s
   
    j = j+1 # Indice de la liste des couples et nombre d'annees
    k = ar[0] # Notre premier argument (le camp choisi (ou passer))
    v = (len(ar)%2) or ar[len(ar)-1] # v = 1 ou 0 selon la longueur (3 ou 1)
    (sc,sl) = (len(ar)>=3) and (ar[1],ar[2]) or (0,0) # Les deux derniers
   
    # permet de recuperer les deux derniers elements de do(a,b,c)
    # a = equipe ; b = colonnes ; c = lignes
   
    k = k and k//abs(k) # Change pas k (fausse piste je pense)
   
    # Changement de nom
    gp = fp
    gm = fm
   
    for y in range(n):
        # mb possiblement une sauvegarde
        # mc devient une copie de mb
        mb[y]=mc[y].copy()
       
    for y in range(n):
        for x in range(n):
           
            o = ma[y][x]
           
            # Le gros tas
            ma[y][x] = ma[y][x]+w*(ma[y][x]==0 and x==sc and y==sl)*((k>0)-(k<0))+(ma[y][x]<=0 and (x-sc or y-sl or k==0) and mb[y][x]//10==3)*((ma[y][x]==0)*w-ma[y][x]*(not(not(ma[y][x]))))-(ma[y][x]>=0 and (x-sc or y-sl or k==0) and mb[y][x]-10*(mb[y][x]//10)==3)*((ma[y][x]==0)*w+ma[y][x]*(not(not(ma[y][x]))))
           
            if o and ma[y][x]==o:
               
                ls=(-1,w>abs(ma[y][x]))
                ma[y][x]=ma[y][x]+(ma[y][x]>0)*ls[mb[y][x]//10==3 or mb[y][x]//10==4]-(ma[y][x]<0)*ls[mb[y][x]-10*(mb[y][x]//10)==3 or mb[y][x]-10*(mb[y][x]//10)==2]
           
            if ma[y][x]-o:
               
                fp = fp+(ma[y][x]>0 and not(o))-(o>0 and not(ma[y][x]))
                fm = fm+(ma[y][x]<0 and not(o))-(o<0 and not(ma[y][x]))
               
                if not(o) and ma[y][x] or o and not(ma[y][x]):
                    for dl in range(-1,2):
                        for dc in range(-1,2):
                            if dl or dc:
                                mc[y+dl+(dl<0 and y==0)*n-(dl>0 and y==n-1)*n][x+dc+(dc<0 and x==0)*n-(dc>0 and x==n-1)*n]+=(ma[y][x]<0)-(o<0 and 0==ma[y][x])+10*((ma[y][x]>0)-(o>0 and 0==ma[y][x]))
    if max(fp,gp)*max(fm,gm):
        s=s/(1+abs(k)*log10(sqrt(j)))+fp*fm*min(fp,gp)*min(fm,gm)/max(fp,gp)/max(fm,gm)
   
    # The final code !
    # Il est ici
    # Chaque elements est de la forme (sc*k+k,sl*k+k)
   
    atmu.append((sc*k+k,sl*k+k))
   
    if v:
        # dr()
        print("Bon score ? Envoie la liste\n'atmu' a info@tiplanet.org")
    return s
def st(l,v=False):
    init()
    for p in l:
       
        # C'est ici qu'on triche !
        # On va pas utiliser une liste de couple, mais une liste de liste
        # comme ca, c'est modifiable comme on veut
       
        # J'ai mis v sur False pour pas avoir le message "Bon score..."
       
        s=do((p[0]>0)-(p[0]<0),abs(p[0])-1,abs(p[1])-1,v)
    # dr()
    return s
init()

actions = [[0,0] for k in range(42)]
rien = [0,0]
scores = []
refscores = []
def chasse():
    for k in range(100): # On va tester au max
        for i in range(42):
            scores = []
            for t in [-1,1]:
                for col in range(1,10):
                    for lig in range(1,10):
                        actions[i] = [t*(col+1),t*(lig+1)]
                        scores.append(st(actions))
                        refscores.append([t,col,lig])
            actions[i] = rien
            scores.append(st(actions))
            refscores.append(rien)
            if refscores[scores.index(max(scores))] != rien:
                actions[i] = [refscores[scores.index(max(scores))][0]*(refscores[scores.index(max(scores))][1]+1),refscores[scores.index(max(scores))][0]*(refscores[scores.index(max(scores))][2]+1)]
            else:
                actions[i] = rien
            print("Annee",i,":",max(scores))


Tout commence avec des tirages aléatoires très aléatoires sans aucune réflexion, et ayant réussi à fabriquer une liste de 5 couples avec un score acceptable (on le pense alors !), on essaye de l’améliorer, et de tirer d’autres listes de 5 couples acceptables.
Code: Tout sélectionner
import random
def aleat5():
    m = 42
    l = [(-2,-2), (2,3), (-2,-4), (2,5), (-4,-3)] # la liste de départ
    while len(l)<m:
        l.append((0,0))
    scoremax = st(l)
    print("score liste : ", scoremax)
    equipe = [1, -1]
    l = []
    tirage = 0   
    while scoremax <100000:
        tirage+=1
        l = []
        for i in range(5):       
            random.shuffle(equipe)
            l.append((equipe[0]*random.randint(1,9),equipe[0]*random.randint(1,9)))
        while len(l)<m:
            l.append((0,0))
        scorerandom = st(l)   
       
        if scorerandom > scoremax:
            print("Meilleur score", scorerandom)
            print("Liste",l[0:5])
            scoremax = scorerandom
        if tirage%1000==0:
            print("Tirages aléatoire : ",tirage)

Cette méthode est un échec, les scores générés ne dépassent pas 100 ! Nous pensions que 100 était en score acceptable car on l’a comparé naïvement au score maxi de 43.x obtenu sur le défi précédent.


ET SI ON EN TIRAIT 10 COUPLES ?
Au lieu de tirer 5 couples, on décide d’en tirer 10.

Pour rappel à ce stade nous sommes toujours aveugles, nous n’avons aucun rendu graphique à analyser pour affiner notre stratégie.
Code: Tout sélectionner
import random
def aleat10():
    m = 42
    scoremax = 100
    print("score aleat5 : ", scoremax)
    equipe = [1, -1]
    tirage = 0   
    while scoremax <100000:
        tirage+=1
        l = []
        for i in range(10):       
            random.shuffle(equipe)
            l.append((equipe[0]*random.randint(1,9),equipe[0]*random.randint(1,9)))
        while len(l)<m:
            l.append((0,0))
        scorerandom = st(l)       
        if scorerandom > scoremax:
            print("Meilleur score", scorerandom)
            print("Liste",l[0:10])
            scoremax = scorerandom
        if tirage%1000==0:
            print("Tirages aléatoire : ",tirage)

Assez rapidement, on obtient des score aux alentours de 16000-17000.

Comme au pays des aveugles les borgnes sont rois, on décide alors de continuer les tirages aléatoires de n couples et dans le même temps de développer notre propre couche graphique histoire d’y voir quelques choses et de laisser passer un peu de lumière...
Meilleur score 16685.07457023799
Liste [(-8, -3), (-4, -6), (-9, -1), (-1, -1), (4, 7), (-5, -4), (5, 9), (6, 7), (-4, -3), (-2, -5)]
Meilleur score 17304.672747006774
Liste [(7, 6), (5, 7), (7, 5), (-4, -7), (-3, -5), (-5, -5), (-3, -9), (-6, -5), (-3, -5), (-9, -8)]



TIRAGES ALÉATOIRES DE N COUPLES
Bien évidemment, on lance les fonctions aleatn(annee) avec des valeurs pour la variable annee comprise entre 1 et 42 mais tout ceci est très long, un unique script tourne sur un unique IDE Python.
Code: Tout sélectionner
def aleatn(annee):
    m = 42
    scoremax = 100
    print("score kiki : ", scoremax)
    tirage = 0   
    while scoremax <100000:
        tirage+=1
        l = []
        for i in range(annee):
            l.append(((-1)**i*random.randint(1,9),(-1)**i*random.randint(1,9)))
        while len(l)<m:
            l.append((0,0))
        scorerandom = st(l)
        if scorerandom > 15000:
            print("bon score", scorerandom)
            print("Liste",l[0:annee])
        if scorerandom > scoremax:
            print("========== Meilleur score : ", scorerandom)
            print("================== Liste = ",l[0:annee])
            scoremax = scorerandom
        if tirage%1000==0:
            print("Tirages aléatoire : ",tirage)



LA PROBLÉMATIQUE DU MULTI-THREAD
Nous n’arrivons pas à faire tourner nos scripts en multi thread sur Python en utilisant les outils adéquates, nous commençons donc par faire du multi thread manuel :
  • 2 PCs = 2 scripts qui tournent 😄
  • 3 IDE = 3 scripts qui tournent. 😅
  • 2 PCs avec 3 IDE = 6 scripts 🤣

Et puis sur pycharm nous arrivons enfin à faire tourner 10-12 scripts en parallèle.
(oui enfin, nous avions autant de fichiers que de [i]threads, cela ressemblait vraiment à un classeur d’élève de 2nde)[/i]

Maîtrisant le multi thread cela fut le début de folles nuits des tirages aléatoires
Il faut bien occuper le Ryzen 7 2700 et ses 16 threads !


La première nuit, les fonctions aleatn(annee) furent lancées avec tous les entiers possible entre 4 et 14.
Je vais me coucher. J’ai lancé les 10 scripts en parallèle on verra demain matin si on a cassé le score de Pavel.


Et le lendemain matin les résultats furent dépouillées.


DES NOUVELLES DE LA COUCHE GRAPHIQUE
En parallèle, nous nous sommes occupés de recréer l’interface graphique en l’améliorant légèrement pour pouvoir voir comment le programme fonctionnait et, accessoirement, ce que l’on obtenait avec nos tirages.

Nous avons choisit tKinter pour ce travail et fixé un cahier des charges :
  • Un espace pour voir la grille.
  • Un petit commentaire pour expliquer le fonctionnement de la GUI.
  • Une reconnaissance de l’entrée des touches pour entrer les do() plus vite.
  • Un espace pour entrer des commandes spéciales (st() par ex). La détection des touches doit être désactivée pour saisir
  • Un historique :
    • Une grille (plus visuelle).
    • Sous forme de texte.
Ainsi, il a fallu créer la fenêtre.
Code: Tout sélectionner
interface = Tk()
interface.resizable(False,False)
interface.title('Concours AT//MU')

# Utilisable
utilisable = Frame(interface,borderwidth=0)
utilisable.pack(side=LEFT)
canevas = Canvas(utilisable,width=500,height=400,bg="white")
canevas.pack(side=TOP)
saisie = StringVar()
barreSaisie = Entry(utilisable,width=60,textvariable=saisie)
barreSaisie.pack(side=RIGHT)
barreSaisie.configure(state="readonly")
label = Label(utilisable,text="'W' pour (ne plus) ecrire")
label.pack(side=LEFT)
labelScore = canevas.create_text(10,240,text="An : 0 // Score = 0",anchor=NW)
canevas.create_text(10,270,text="Appuyez sur + ou - sur le clavier numerique pour choisir votre camp",anchor=NW)
canevas.create_text(10,290,text="Puis, toujours sur le clavier numerique, selectionnez votre colonne puis votre ligne avec les",anchor=NW)
canevas.create_text(10,305,text="touches 1 a 9.",anchor=NW)
canevas.create_text(10,325,text="Attention, la case (1;1) est la case en haut a gauche !",anchor=NW)
canevas.create_text(10,345,text="Pour passer une annee, appuyez sur le point du clavier numerique.",anchor=NW)
canevas.create_text(10,365,text="Pour recommencer une partie, appuyez sur 'R'.",anchor=NW)
canevas.create_text(10,385,text="Il est possible de rentrer des commandes speciales a tout moment en appuyant sur 'W'.",anchor=NW)

# Historique
historique = Frame(interface,borderwidth=0)
historique.pack(side=RIGHT)
canevasHist = Canvas(historique,width=400,height=230,bg="white")
canevasHist.pack(side=TOP)
listeHist = ScrolledText(historique,width=50,height=11)
listeHist.pack(side=BOTTOM)

Ceci étant fait, on crée une fonction récupérant les événements claviers.

Attention : On prend bien soin de lier cette fonction à la fenêtre : interface.bind("<Key>",event)
Cette ligne envoie à la fonction event() la valeur quand une touche est pressée.
Code: Tout sélectionner
isWriting = False
commande = ["","",""]
index = 1

def event(touche):
    global isWriting,index,commande
    touche = touche.keysym
    if touche == "w":
        if isWriting:
            barreSaisie.configure(state="readonly")
            saisie.set("do("+commande[0]+","+commande[1]+","+commande[2]+")")
        else:
            barreSaisie.configure(state="normal")
            saisie.set("")
        isWriting = isWriting == False # paradoxe du menteur
    if touche == "r":
        init()
        dr(2,0,0)
    if touche == "plus" and not isWriting:
        commande[0]="1"
    if touche == "minus" and not isWriting:
        commande[0]="-1"
    if touche == "BackSpace" and not isWriting:
        commande[index-1] = ""
        if index > 1:
            index -= 1
    if touche == "1" and not isWriting and index<3:
        commande[index] = "0"
        index += 1
    if touche == "2" and not isWriting and index<3:
        commande[index] = "1"
        index += 1
    if touche == "3" and not isWriting and index<3:
        commande[index] = "2"
        index += 1
    if touche == "4" and not isWriting and index<3:
        commande[index] = "3"
        index += 1
    if touche == "5" and not isWriting and index<3:
        commande[index] = "4"
        index += 1
    if touche == "6" and not isWriting and index<3:
        commande[index] = "5"
        index += 1
    if touche == "7" and not isWriting and index<3:
        commande[index] = "6"
        index += 1
    if touche == "8" and not isWriting and index<3:
        commande[index] = "7"
        index += 1
    if touche == "9" and not isWriting and index<3:
        commande[index] = "8"
        index += 1
    if touche == "Return":
        try:
            eval(saisie.get())
            saisie.set("")
            index=1
            commande=["","",""]
        except:
            print("aie")
    if touche == "period" and not isWriting:
        do(0)
    if not isWriting:
        saisie.set("do("+commande[0]+","+commande[1]+","+commande[2]+")")

Mais, un problème de taille était toujours présent, modifier la couche graphique pré-codée avec kandinsky.

Voici donc ce qu’on a pu faire.
Code: Tout sélectionner
def dr(camp,xHist,yHist):
    global s,j,w,labelScore
    sw=320
    d=min(sw//n,221//n)
    b=sw-1-n*d
   
    for i in range(0,n*d+1,d):
        canevas.create_rectangle(b,10+i,b+n*d,i+11,fill=hexColor(0,0,0),outline="")
        canevas.create_rectangle(b+i,10,b+i+1,n*d+10,fill=hexColor(0,0,0),outline="")
        canevasHist.create_rectangle(b,10+i,b+n*d,i+11,fill=hexColor(0,0,0),outline="")
        canevasHist.create_rectangle(b+i,10,b+i+1,n*d+10,fill=hexColor(0,0,0),outline="")
       
    if camp != 0 and camp != 2:
        t=255-(255*abs(ma[yHist][xHist])//w)
        canevasHist.create_rectangle(b+xHist*d+1,yHist*d+11,b+xHist*d+d,yHist*d+10+d,fill=camp<0 and hexColor(t,t,255) or camp>0 and hexColor(255,t,t),outline="")
        listeHist.insert(END,str((xHist*camp+camp,yHist*camp+camp))+"\n")
    elif camp == 0:
        listeHist.insert(END,"(0, 0)\n")
    else:
        listeHist.delete(1.0,END)
       
    for y in range(0,n):
        for x in range(0,n):
            t=255-(255*abs(ma[y][x])//w)
            canevas.create_rectangle(b+x*d+1,y*d+11,b+x*d+d,y*d+10+d,fill=ma[y][x]<0 and hexColor(t,t,255) or ma[y][x]>0 and hexColor(255,t,t) or hexColor(255,255,255),outline="")
            if camp == 2:
                canevasHist.create_rectangle(b+x*d+1,y*d+11,b+x*d+d,y*d+10+d,fill=ma[y][x]<0 and hexColor(t,t,255) or ma[y][x]>0 and hexColor(255,t,t) or hexColor(255,255,255),outline="")
           
           
    canevas.itemconfig(labelScore,text="An: "+str(j)+" // Score: "+str(s)[:10])

On remarque que les couleurs sont générées au moyen d’un code RGB, or tKinter n’accepte que des chaines de caractères, donc (cours de NSI ;) ), on convertit les valeurs en hexadécimal et on crée un code de la forme "#rrggbb".
Code: Tout sélectionner
def hexColor(r,g,b):
    r = "0" + hex(r)[2:]
    g = "0" + hex(g)[2:]
    b = "0" + hex(b)[2:]
    return "#"+r[len(r)-2:len(r)]+g[len(g)-2:len(g)]+b[len(b)-2:len(b)]

On obtient ainsi le résultat suivant.

Bon au cours du développement de cette couche graphique, on a constaté que Pavel avait codé la sienne de son coté et qu’il l’avait rendue publique pendant le concours. Heureusement bien peu ont compris l’importance de ces simulations graphiques.


ANALYSE DES RÉSULTATS
A partir de là, nous avons commencé à faire des tirages aléatoires sans IA.

Les 30 000 000 de tirages réalisés pendant la nuit furent analysés en détails, et des grilles de sudoku furent coloriées pour identifier les positions initiales de 6 couples ayant de gros scores.

Nous avons eu confirmation que cela ressemblait au jeu de la vie et avons compris quelques règles :
  • Il faut semer 3 cases différentes mais proches d’une même colonie pour avoir un développement exponentiel.
  • Quand les colonies Atlantes et Muennes se rencontrent, elles se détruisent. Une trop forte densité d’une colonie amène aussi à son auto destruction par le centre.
  • Il existe des états stables mais nous ne les avons pas trouvé optimaux en terme de score à la fin de l’an 42.
  • Le score monte plus vite si les deux colonies se développent, donc aleatn(5) ne produira jamais un gros score, aleatn(6) lui peut faire un gros score.
Pour affiner les résultats, nous avons décidé de sauvegarder les bonnes listes et non plus uniquement les meilleures listes.


NUITS DE FOLIE : 6 À 12 SCRIPTS QUI TOURNENT EN PARALLÈLE
Quelques nuits de folies plus tard ...
Code: Tout sélectionner
listealeat = []
tirage = [0 for k in range(42)]

best_list =  []
best_scor = 0

good_list = []
good_scor = []
good_indice = 0

def sauvegarde(sauveliste,score,tirage,annee):
    global best_indice, best_scor, good_list, good_scor, good_indice, best_list
    if score > 15500: #Le chiffre de 15500 a régulièrement été augmenté
        # On sauvegarde les listes de couples donnant 15500 min
        good_list.append(sauveliste)
        good_scor.append(score)
        good_indice+=1
    if score > best_scor:
         # On sauvegarde la meilleur liste trouvée
        best_list = sauveliste[0:annee]
        best_scor = score
        print("\n======= Meilleur score ======== tirage n° ",tirage, "sur",annee, "années ======== ")
        print("Score : ",score)
        print("liste = ",best_list[0:annee])

def calcule_score(liste,tirage,annee):
    m=42
    sauveliste = liste
    # print(sauveliste)
    # input()
    while len(liste)<m:
        liste.append((0,0))
    score = st(liste)
    sauvegarde(sauveliste,score,tirage,annee)

def forcealeat(annee,nbtirage):
    global best_scor, good_indice
    for j in range(nbtirage):
        listealeat = []
        tirage[annee]+=1
        for i in range(annee):
                listealeat.append(((-1)**i*random.randint(1,9),(-1)**i*random.randint(1,9)))
                # le choix de faire un coup négatif un coup positif peut se discuter...
                random.shuffle(listealeat)
        calcule_score(listealeat,tirage[annee],annee) 
    print(30*"##")
    print("fini,",nbtirage, "tirages de",annee, "couples aléatoires")
    print("bonne liste : ",good_indice)
    print("MeilleurScore : ",best_scor)
    print("liste = ",best_list)

def forcealeatgeometrie6(annee,nbtirage):
    global best_scor, good_indice
    for j in range(nbtirage):
        listealeat = []
        tirage[annee]+=1
        col1 = random.randint(1,6)
        lig1 = random.randint(1,9)
        col2 = random.randint(1,9)
        lig2 = random.randint(1,6)
        listealeat.append((col1,lig1))
        listealeat.append((col1+1,lig1))
        listealeat.append((col1+2,lig1))
        listealeat.append((-1*col2,-1*lig2))
        listealeat.append((-1*col2,-1*(lig2+1)))
        listealeat.append((-1*col2,-1*(lig2+2)))
        random.shuffle(listealeat)
        calcule_score(listealeat,tirage[annee],annee) 
    print(30*"##")
    print("fini,",nbtirage, "tirages de",annee, "couples aléatoires")
    print("bonne liste : ",good_indice)
    print("MeilleurScore : ",best_scor)
    print("liste = ",best_list)



JEUX AVEC LE MOTEUR GRAPHIQUE
A l’aide du moteur graphique, on a pu analyser les figures donnant des états stables. C’est à dire qu’à partir d’une configuration donnée, on obtient une configuration qui n’évolue plus dans le temps.

Ainsi, on obtient les résultats suivants.

1er état stable, avant-après :

2ème état stable, avant-après :

Un 3ème, très joli :

Avec ces états, on observe un autre comportement du programme, les bords interagissent entre eux.


TIRAGES ALÉATOIRES AVEC IA
Nos résultats étaient satisfaisants et ils nous permettait d’obtenir un score supérieur à 18 000, mais beaucoup de tirage étaient gâchés car l’algorithme manquait de discernement.

Nous avons alors repris les coloriages et amélioré notre script de tirage. L’heure de l’IA avait sonné.
Oui on utilise facilement le mot IA alors que ... on a juste réfléchit et que les scripts sont eux toujours aussi stupides.

Ce script a réalisé à lui tout seul plus de 20 000 000 de tirage, déjà parce qu’il était beau, et ensuite parce que nous voulions obtenir une liste significative de tirage ayant un score supérieur à 18 000.

forcealeatIA(6,7000000) nous au ainsi donné 154 tirages certifiés supérieurs à 18 000.
Code: Tout sélectionner
def forcealeatIA(annee, nbtirage):
    global best_scor, good_indice
    for j in range(nbtirage):
        listealeat = []
        tirage[annee] += 1
        na = random.randint(1, 9)
        ma = random.randint(1, 9)
        nlist = [max(na - 1, 1), na, min(na + 1, 9)]
        mlist = [max(ma - 1, 1), ma, min(ma + 1, 9)]
        pa = random.randint(1, 9)
        qa = random.randint(1, 9)
        plist = [max(pa - 1, 1), pa, min(pa + 1, 9)]
        qlist = [max(qa - 1, 1), qa, min(qa + 1, 9)]
        for i in range(annee // 2):
            listealeat.append((random.choice(nlist), random.choice(mlist)))
            listealeat.append(((-1) * random.choice(plist), (-1) * random.choice(qlist)))
        random.shuffle(listealeat)
        goodliste(listealeat, tirage[annee], annee)
    print(30 * "##")
    print("fini,", nbtirage, "tirages de", annee, "couples aléatoires")
    print("bonne liste : ", good_indice)
    print("MeilleurScore : ", best_scor)
    print("liste = ", best_list)

Ces tirages ont alors été mélangés aléatoirement, histoire de s’assurer vérifier que un autre ordre ne nous donnerait pas un meilleur score.

La variable goodliste contenait à ce moment là une liste de listes, nos 154 listes que nous avons mélangés 100 000 fois procédant ainsi à 15 000 000 nouveaux tirages.
Code: Tout sélectionner
def improve_liste():
    global goodliste
    listetraiteeok = 0
    for listeatraiter in goodliste:
        listetraiteeok += 1
        annee = len(listeatraiter)
        for i in range(100000):
            listemelange = listeatraiter[0:annee]
            random.shuffle(listemelange)
            calcule_score(listemelange, i, annee)
        if listetraiteeok % 10 == 0:
            print("liste mélangées :", listetraiteeok, "1000 fois")

In fine, nous avons obtenu trois 4 listes ayant un score supérieur à 19 000.
Code: Tout sélectionner
[(-1, -4), (-2, -5), (8, 1), (-3, -5), (7, 1), (7, 3)]
[(2, 3), (2, 4), (-6, -7), (1, 2), (-6, -9), (-5, -7)]
[(5, 3), (7, 3), (7, 4), (-1, -7), (-3, -7), (-1, -6)]
[(5, 5), (4, 5), (4, 3), (-6, -8), (-5, -8), (-4, -8)]

MeilleurScore : 19207.913058803344
liste = [(5, 5), (4, 5), (4, 3), (-6, -8), (-5, -8), (-4, -8)]



DERNIÈRE APPROCHE GAGNANTE
La dernière approche (gagnante) fut de procéder par force brute sur des listes ayant un bon patrimoine génétique.

Nous avions à notre disposition des nombreuses listes courtes avec des scores supérieur à 18 000 voir 19 000. Et si nous cherchions à les rallonger ?

Certains résultats obtenus par forcealeatIA(9,1000000) étaient surprenant. Certaines listes de 9 couples avaient un bon score, mais si on ne prenait que la liste des 6 premiers couples le score était mauvais.

Un script sur mesure fut donc codé.

La variable goodliste contenait à ce moment là une unique liste, que l’on voulait compléter.
  • add_liste(goodliste, an, 1) quelques secondes, 163 tirages
  • add_liste(goodliste, an, 2) quelques minutes, 26 569 tirages
  • add_liste(goodliste, an, 3) quelques heures, plus de 4 000 000 de tirages
Nous n’avons pas testé add_liste(goodliste, an, 4) par manque de temps.

Par contre, sur 6,8,12 thread le script add_liste(goodliste, an, 3) a tourné non stop sur des listes sélectionnées avec amour au moyen des scripts forcealeatIA(annee, nbtirage) qui continuait à tourner, dès fois que ...
Code: Tout sélectionner
def add_liste(listeatraiter, annee, rangsup=1):
    liste = listeatraiter.copy()
    # on essaie avec (0,0)
    liste.append((0, 0))
    listescore = liste.copy()
    calcule_score(listescore, 0, annee + 1)
    if rangsup - 1 > 0:
        add_liste(liste, annee + 1, rangsup - 1)
    liste.pop(len(liste) - 1)
    # on essaie avec (+,+)
    for i in range(1, 10, 1):
        for j in range(1, 10, 1):
            liste.append((i, j))
            listescore = liste.copy()
            calcule_score(listescore, 10 * i + j, annee + 1)
            if rangsup - 1 > 0:
                add_liste(liste, annee + 1, rangsup - 1)
            liste.pop(len(liste) - 1)
    # on essaie avec (-,-)
    for i in range(-9, 0, 1):
        for j in range(-9, 0, 1):
            liste.append((i, j))
            listescore = liste.copy()
            calcule_score(listescore, 10 * i + j, annee + 1)
            if rangsup - 1 > 0:
                add_liste(liste, annee + 1, rangsup - 1)
            liste.pop(len(liste) - 1)

an = len(goodliste)
add_liste(goodliste, an, 2)
print(good_list)



CHRONOLOGIE DES SCORES OBTENUS
  1. 15/10 17:00 : 15016
    Pour l’instant on pédale dans la semoule
    global s,j,w # sjw, je ne sais pas si c’est fait exprès mais...
  2. 15/10 19:34 : 17142
    On n’a toujours aucun graphique ni aucune idée de ce qui se passe mais si ça ressemble fortement à des multiplications matricielles.
  3. 16/10 14:16 : 18157
    Score de la nuit sur 10 000 000 de tirages pas vraiment optimisés.
  4. 23/10 10:30 : 18860
    Objectif 19000 avant la fin de la journée.
  5. 23/10 11:30 : 19117
    Prochain objectif : 19430 (pour doubler un autre candidat).
  6. 24/10 10:07 : 19675
    Finalement 19430 n’était qu’une formalité.
    Maintenant pour aller jusqu’à 21700 il va falloir trouver une autre méthode, celle-ci est un peu longue, mais comme il faut chauffer un peu la maison je ne suis responsable d’aucun meurtre supplémentaire de pingouin.
  7. 24/10 21:13 : 20180
    500 points de plus ! Et c’est pas fini !
  8. 28/10 22:12 : 20475
    Il me tarde de savoir comment a fait Pavel parce que j’ai tout donné et que j’ai 7 scripts qui moulinent sur mon PC...
  9. 28/10 22:12 : 20972
    Je ne perds pas espoir de finir 1er, mais stratégiquement je me dis que j’ai peut-être intérêt à envoyer mes scores le dernier jour pour que le 1er ne puisse pas réagir...
    C’est beau de rêver ... 20972 fut notre meilleur score.


CONCLUSIONS
Une estimation basse du nombre de tirages que nous avons réalisé donne 100 000 000 de tirages. Mais comme les scripts tournaient non stop en parallèle, nous pensons qu’on s’approche plus des 200 000 000 de tirages et simulations diverses pas du tout optimales.

Ne maîtrisant pas encore les exports / imports CSV en Python nous avons été limités par la nécessité d’arrêter manuellement les scripts, de copier / coller les bons résultats et de relancer les scripts, mais pour le défi de l’année prochaine nous seront prêts.

Félicitation une nouvelle fois à Pavel qui a dominé les 3 épreuves mais semble ne pas partir avec les mêmes connaissances de base que le simple visiteur des sites TI-Planet et Planète Casio.

L’année prochaine, il est probable que l’on donnera le concours Python en devoir maison facultatif aux élèves de spé NSI de Terminale de notre lycée, histoire de voir s’ils ont fixé des connaissances et s’ils font preuve d’initiative et d’autonomie.

Se classer dans les 10 premiers : 18/20, coefficient 0,42.
Se classer devant le prof : 20/20, coefficient 0,666.
https://nsi.xyz/concours-de-rentree-201 ... -en-python


1er :
Pavel omniprésent sur TI-Planet et sur Planète Casio intervient quant à lui jusqu'à 10 fois :
  • 3 fois au nom du peuple Atlante
  • puis 7 fois au nom du peuple Muen
Il explose ainsi le score en l'an 42 avec 21960 points ! :bj:
Mais ce n'est pas tout car Pavel nous exhibe également la configuration ultime. A partir de l'an 26 les deux populations font la paix et entrent ainsi en stabilité parfaite. Le score atteint ainsi des sommets avec par exemple pas moins de 191160 points au record de 277 ans, et continue ensuite son chemin vers l'infini et au-delà, une première place largement méritée ! :#tritop#:
Pavel a écrit:
Voici quelques explications de ma méthode pour obtenir 21960 points. J'ai commencé à jouer sur ma TI-83 Premium CE mais je n'étais pas assez patient pour attendre au moins 15 secondes après chaque tour et j'ai vite abandonné cette idée. Ensuite, j'ai légèrement modifié le script Numworks en remplaçant Kandinsky par tkinter et j'ai continué à jouer sur un PC. La version modifiée du script ci-contre se trouve également dans ce dépôt.
Code: Tout sélectionner
from math import log10,sqrt
from tkinter import *

master = Tk()
master.resizable(0, 0)

canvas = Canvas(master, width=320, height=240)
canvas.pack()

def color(r, g, b):
  return '#%02x%02x%02x' % (r, g, b)

def fill_rect(x, y, w, h, color):
  y += 18
  canvas.create_rectangle(x, y, x + w, y + h, fill=color, outline='')

def draw_string(text, x, y, fg=color(0,0,0), bg=None):
  y += 18
  t = canvas.create_text(x, y, anchor=NW, text=text, fill=fg)
  if bg is not None:
    r = canvas.create_rectangle(canvas.bbox(t), fill=bg, outline='')
    canvas.tag_lower(r, t)

def clear():
  canvas.delete('all')
  canvas.create_rectangle(0, 18, 320, 240, fill=color(255, 255, 255), outline='')
  canvas.create_rectangle(0, 0, 320, 18, fill=color(255, 183, 52), outline='')

def init():
  global atmu,n,j,s,ma,mb,mc,w,fp,fm
  atmu,n,j,s,w,fp,fm=[],9,0,0,5,0,0
  ma,mb,mc=[[0]*n for k in range(n)],[[0]*n for k in range(n)],[[0]*n for k in range(n)]

def dr():
  global s,j,w
  sw=320
  d,h=min(sw//n,221//n),(color(0,0,0),color(255,255,255))
  b=sw-1-n*d
  clear()
  for i in range(0,n*d+1,d):
    fill_rect(b,i,n*d,1,h[0])
    fill_rect(b+i,0,1,n*d,h[0])
  for y in range(0,n):
    for x in range(0,n):
      t=255-(255*abs(ma[y][x])//w)
      fill_rect(b+x*d+1,y*d+1,d-1,d-1,ma[y][x]<0 and color(t,t,255) or ma[y][x]>0 and color(255,t,t) or h[1])
  draw_string(" ATLEMU ",1,1,color(255,255,0),color(127,127,127))
  draw_string("Muen\ndo(-1,c,l)",0,19,color(0,0,255),h[1])
  draw_string("Atlante\ndo(1,c,l)",0,53,color(255,0,0),h[1])
  draw_string("Passer\ndo(0)",0,87,color(255,0,255),h[1])
  draw_string("Recommencer\ninit()",0,121,color(0,0,0),h[1])
  draw_string("An: "+str(j)+"\nScore:\n"+str(s)[:10],0,n*d-49)

def do(*ar):
  global j,gp,gm,fp,fm,s
  j,k,v,(sc,sl)=j+1,ar[0],(len(ar)%2) or ar[len(ar)-1],(len(ar)>=3) and (ar[1],ar[2]) or (0,0)
  k,gp,gm=k and k//abs(k),fp,fm
  for y in range(n):mb[y]=mc[y].copy()
  for y in range(n):
    for x in range(n):
      o,ma[y][x]=ma[y][x],ma[y][x]+w*(ma[y][x]==0 and x==sc and y==sl)*((k>0)-(k<0))+(ma[y][x]<=0 and (x-sc or y-sl or k==0) and mb[y][x]//10==3)*((ma[y][x]==0)*w-ma[y][x]*(not(not(ma[y][x]))))-(ma[y][x]>=0 and (x-sc or y-sl or k==0) and mb[y][x]-10*(mb[y][x]//10)==3)*((ma[y][x]==0)*w+ma[y][x]*(not(not(ma[y][x]))))
      if o and ma[y][x]==o:
        ls=(-1,w>abs(ma[y][x]))
        ma[y][x]=ma[y][x]+(ma[y][x]>0)*ls[mb[y][x]//10==3 or mb[y][x]//10==4]-(ma[y][x]<0)*ls[mb[y][x]-10*(mb[y][x]//10)==3 or mb[y][x]-10*(mb[y][x]//10)==2]
      if ma[y][x]-o:
        fp,fm=fp+(ma[y][x]>0 and not(o))-(o>0 and not(ma[y][x])),fm+(ma[y][x]<0 and not(o))-(o<0 and not(ma[y][x]))
        if not(o) and ma[y][x] or o and not(ma[y][x]):
          for dl in range(-1,2):
            for dc in range(-1,2):
              if dl or dc:mc[y+dl+(dl<0 and y==0)*n-(dl>0 and y==n-1)*n][x+dc+(dc<0 and x==0)*n-(dc>0 and x==n-1)*n]+=(ma[y][x]<0)-(o<0 and 0==ma[y][x])+10*((ma[y][x]>0)-(o>0 and 0==ma[y][x]))
  if max(fp,gp)*max(fm,gm):s=s/(1+abs(k)*log10(sqrt(j)))+fp*fm*min(fp,gp)*min(fm,gm)/max(fp,gp)/max(fm,gm)
  atmu.append((sc*k+k,sl*k+k))
  if v:
    dr()
    print("Bon score ? Envoie la liste\n'atmu' a info@tiplanet.org")
  return s

def st(l,v=True):
  init()
  for p in l:s=do((p[0]>0)-(p[0]<0),abs(p[0])-1,abs(p[1])-1,v)
  dr()
  return s

init()

dr()

if __name__== "__main__":
  master.mainloop()

Je me suis beaucoup amusé avec le mode interactif de ce jeu et en même temps j'ai remarqué les particularités suivantes de ce jeu :
  • il faut trois colonies de la même civilisation pour que les colonies commencent à se multiplier
  • le calcul du score n'est pas sensible au décalage horizontal ou vertical et toute solution peut être transformée en l'un des deux types de solutions suivantes :
    • la toute première colonie est en position (0,0) et cette colonie est Muenne
    • la toute première colonie est en position (0,0) et cette colonie est Atlante
Pour maximiser le score, j'ai utilisé l'algorithme de recuit simulé et j'ai réécrit le calcul du score en C pour pouvoir calculer le score le plus rapidement possible.

J'ai passé beaucoup de temps à ajuster les paramètres de l'algorithme et j'ai aussi remarqué les points suivants:
  • les solutions où la première colonie est Atlante ont tendance à apporter plus de points
  • les meilleures solutions prennent moins de 12 tours pour réaliser le semis
Enfin, ma méthode a pris la forme suivante:
  • au premier tour, mettre une colonie Atlante à (0,0)
  • à chaque itération de recuit simulé, faire les modifications suivantes:
    • changer aléatoirement l'un des 10 prochains tours en plaçant une colonie sur une position libre
    • vérifier les 10 prochains tours un par un en essayant tous les 163 mouvements possibles et garder une combinaison avec le score maximum
  • recommencer plusieurs fois avec différentes séquences de nombres pseudo-aléatoires
Pour être sûr d'avoir de bonnes séquences de nombres pseudo-aléatoires, j'ai pris l'algorithme WELL512.
Code: Tout sélectionner
#include <errno.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>

struct STATE
{
  int8_t code[42];
  int8_t board[81 * 42];
  double score;
};

/*
WELL512 algorithm
http://www.iro.umontreal.ca/~panneton/WELLRNG.html
implemented by Chris Lomont
http://lomont.org/papers/2008/Lomont_PRNG_2008.pdf
*/
uint32_t buf[16];
uint32_t pos;
uint32_t wellrng512()
{
  uint32_t a, b, c, d;
  a = buf[pos];
  c = buf[(pos + 13) & 15];
  b = a ^ c ^ (a << 16) ^ (c << 15);
  c = buf[(pos + 9) & 15];
  c ^= (c >> 11);
  a = buf[pos] = b ^ c;
  d = a ^ ((a << 5) & 0xDA442D24UL);
  pos = (pos + 15) & 15;
  a = buf[pos];
  buf[pos] = a ^ b ^ d ^ (a << 2) ^ (b << 18) ^ (c << 28);
  return buf[pos];
}

double score(struct STATE *state)
{
  double s;
  int8_t i, j, k, l, dx, dy, lp, lm, o, x, y, xn, yn;
  int8_t dp, dm, fp, fm, gp, gm, maxp, maxm, minp, minm;
  int8_t ma[81], mp[81], mm[81], np[81], nm[81];

  s = 0.0;
  fp = 0;
  fm = 0;
  memset(ma, 0, 81);
  memset(mp, 0, 81);
  memset(mm, 0, 81);

  for(j = 0; j < 42; ++j)
  {
    i = state->code[j];
    l = abs(i) - 1;
    k = (i > 0) - (i < 0);

    gp = fp;
    gm = fm;

    memcpy(np, mp, 81);
    memcpy(nm, mm, 81);

    memcpy(state->board + j * 81, ma, 81);

    for(i = 0; i < 81; ++i)
    {
      o = ma[i];
      if(i == l && k != 0)
      {
        if(ma[i] == 0) ma[i] = 5 * k;
      }
      else
      {
        ma[i] += (np[i] == 3) * ((ma[i] == 0) * 5 - (ma[i] < 0) * ma[i]) - (nm[i] == 3) * ((ma[i] == 0) * 5 + (ma[i] > 0) * ma[i]);
      }
      if(ma[i] == o && o != 0)
      {
        lp = np[i] == 3 || np[i] == 4 ? abs(ma[i]) < 5 : -1;
        lm = nm[i] == 3 || nm[i] == 2 ? abs(ma[i]) < 5 : -1;
        ma[i] += (ma[i] > 0) * lp - (ma[i] < 0) * lm;
      }
      if(ma[i] != o && (ma[i] == 0 || o == 0))
      {
        dp = (ma[i] > 0) - (o > 0);
        dm = (ma[i] < 0) - (o < 0);
        fp += dp;
        fm += dm;
        x = i % 9;
        y = i / 9;
        for(dx = -1; dx < 2; ++dx)
        {
          for(dy = -1; dy < 2; ++dy)
          {
            if(dx == 0 && dy == 0) continue;
            yn = y + dx;
            yn = yn < 0 ? 8 : yn > 8 ? 0 : yn;
            xn = x + dy;
            xn = xn < 0 ? 8 : xn > 8 ? 0 : xn;
            mp[yn * 9 + xn] += dp;
            mm[yn * 9 + xn] += dm;
          }
        }
      }
    }
    maxp = fp > gp ? fp : gp;
    maxm = fm > gm ? fm : gm;
    minp = fp < gp ? fp : gp;
    minm = fm < gm ? fm : gm;
    if(maxp != 0 && maxm != 0)
    {
      s = s / (1 + abs(k) * log10(sqrt(j + 1))) + 1.0 * fp * fm * minp * minm / maxp / maxm;
    }
  }
  return s;
}

void init(struct STATE *state)
{
  memset(state->code, 0, 42);

  state->code[0] = 1;

  memset(state->board, 0, 81 * 42);

  state->score = score(state);
}

void random_walk(struct STATE *state)
{
  int8_t i, imax, j, l;
  double s, smax;

  for(l = 0; l < 2; ++l)
  {
    while(1)
    {
      i = wellrng512() % 163 - 81;
      j = wellrng512() % 10 + 1;

      if(i == 0 || state->board[j * 81 + abs(i) - 1] == 0)
      {
        state->code[j] = i;
        break;
      }
    }
  }

  for(l = 0; l < 1; ++l)
  {
    for(j = 1; j < 12; ++j)
    {
      imax = 0;
      smax = 0.0;
      for(i = -81; i < 82; ++i)
      {
        state->code[j] = i;
        s = score(state);
        if(smax < s)
        {
          imax = i;
          smax = s;
        }
      }
      state->code[j] = imax;
      state->score = smax;
    }
  }
}

void print(struct STATE *state)
{
  int8_t i, j, k, l;

  printf("%.9f ", state->score);
  for(j = 0; j < 42; ++j)
  {
    i = state->code[j];
    l = abs(i) - 1;
    k = (i > 0) - (i < 0);
    printf("(%d, %d), ", k * (l % 9 + 1), k * (l / 9 + 1));
  }
  printf("\n");
}

int main(int argc, char *argv[])
{
  struct STATE current, next;
  double delta, result, t;
  unsigned seed;
  int8_t i;

  result = 0.0;

  while(1)
  {
    seed = time(NULL);
    srand(seed);
    printf("seed: %d\n", seed);
    pos = 0;
    for(i = 0; i < 16; ++i)
    {
      buf[i] = rand() ^ (rand() << 16) ^ (rand() << 31);
    }

    init(&current);

    t = 1.0;

    while(t > 0.001)
    {
      t *= 0.999;

      next = current;

      random_walk(&next);

      if(result < next.score)
      {
        result = next.score;
        print(&next);
      }

      delta = next.score - current.score;
      if(delta >= 0 || wellrng512() < RAND_MAX * exp(delta / t))
      {
        current = next;
      }
    }
  }

  return EXIT_SUCCESS;
}

Après plusieurs heures, j'ai eu la chance de trouver une séquence de nombres aléatoires permettant à mon code de converger vers 21960 en quelques minutes. Je suis très heureux que cette solution, en même temps, apporte beaucoup de points et crée un monde absolument stable dans lequel les deux civilisations coexisteront pendant des millions d'années.

Enfin, voici un lien vers mon code en C également ci-contre.
Code: Tout sélectionner
#include <errno.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>

struct STATE
{
  int8_t code[42];
  int8_t board[81 * 42];
  double score;
};

/*
WELL512 algorithm
http://www.iro.umontreal.ca/~panneton/WELLRNG.html
implemented by Chris Lomont
http://lomont.org/papers/2008/Lomont_PRNG_2008.pdf
*/
uint32_t buf[16];
uint32_t pos;
uint32_t wellrng512()
{
  uint32_t a, b, c, d;
  a = buf[pos];
  c = buf[(pos + 13) & 15];
  b = a ^ c ^ (a << 16) ^ (c << 15);
  c = buf[(pos + 9) & 15];
  c ^= (c >> 11);
  a = buf[pos] = b ^ c;
  d = a ^ ((a << 5) & 0xDA442D24UL);
  pos = (pos + 15) & 15;
  a = buf[pos];
  buf[pos] = a ^ b ^ d ^ (a << 2) ^ (b << 18) ^ (c << 28);
  return buf[pos];
}

double score(struct STATE *state)
{
  double s;
  int8_t i, j, k, l, dx, dy, lp, lm, o, x, y, xn, yn;
  int8_t dp, dm, fp, fm, gp, gm, maxp, maxm, minp, minm;
  int8_t ma[81], mp[81], mm[81], np[81], nm[81];

  s = 0.0;
  fp = 0;
  fm = 0;
  memset(ma, 0, 81);
  memset(mp, 0, 81);
  memset(mm, 0, 81);

  for(j = 0; j < 42; ++j)
  {
    i = state->code[j];
    l = abs(i) - 1;
    k = (i > 0) - (i < 0);

    gp = fp;
    gm = fm;

    memcpy(np, mp, 81);
    memcpy(nm, mm, 81);

    memcpy(state->board + j * 81, ma, 81);

    for(i = 0; i < 81; ++i)
    {
      o = ma[i];
      if(i == l && k != 0)
      {
        if(ma[i] == 0) ma[i] = 5 * k;
      }
      else
      {
        ma[i] += (np[i] == 3) * ((ma[i] == 0) * 5 - (ma[i] < 0) * ma[i]) - (nm[i] == 3) * ((ma[i] == 0) * 5 + (ma[i] > 0) * ma[i]);
      }
      if(ma[i] == o && o != 0)
      {
        lp = np[i] == 3 || np[i] == 4 ? abs(ma[i]) < 5 : -1;
        lm = nm[i] == 3 || nm[i] == 2 ? abs(ma[i]) < 5 : -1;
        ma[i] += (ma[i] > 0) * lp - (ma[i] < 0) * lm;
      }
      if(ma[i] != o && (ma[i] == 0 || o == 0))
      {
        dp = (ma[i] > 0) - (o > 0);
        dm = (ma[i] < 0) - (o < 0);
        fp += dp;
        fm += dm;
        x = i % 9;
        y = i / 9;
        for(dx = -1; dx < 2; ++dx)
        {
          for(dy = -1; dy < 2; ++dy)
          {
            if(dx == 0 && dy == 0) continue;
            yn = y + dx;
            yn = yn < 0 ? 8 : yn > 8 ? 0 : yn;
            xn = x + dy;
            xn = xn < 0 ? 8 : xn > 8 ? 0 : xn;
            mp[yn * 9 + xn] += dp;
            mm[yn * 9 + xn] += dm;
          }
        }
      }
    }
    maxp = fp > gp ? fp : gp;
    maxm = fm > gm ? fm : gm;
    minp = fp < gp ? fp : gp;
    minm = fm < gm ? fm : gm;
    if(maxp != 0 && maxm != 0)
    {
      s = s / (1 + abs(k) * log10(sqrt(j + 1))) + 1.0 * fp * fm * minp * minm / maxp / maxm;
    }
  }
  return s;
}

void init(struct STATE *state)
{
  memset(state->code, 0, 42);

  state->code[0] = 1;

  memset(state->board, 0, 81 * 42);

  state->score = score(state);
}

void random_walk(struct STATE *state)
{
  int8_t i, imax, j, l;
  double s, smax;

  for(l = 0; l < 2; ++l)
  {
    while(1)
    {
      i = wellrng512() % 163 - 81;
      j = wellrng512() % 10 + 1;

      if(i == 0 || state->board[j * 81 + abs(i) - 1] == 0)
      {
        state->code[j] = i;
        break;
      }
    }
  }

  for(l = 0; l < 1; ++l)
  {
    for(j = 1; j < 12; ++j)
    {
      imax = 0;
      smax = 0.0;
      for(i = -81; i < 82; ++i)
      {
        state->code[j] = i;
        s = score(state);
        if(smax < s)
        {
          imax = i;
          smax = s;
        }
      }
      state->code[j] = imax;
      state->score = smax;
    }
  }
}

void print(struct STATE *state)
{
  int8_t i, j, k, l;

  printf("%.9f ", state->score);
  for(j = 0; j < 42; ++j)
  {
    i = state->code[j];
    l = abs(i) - 1;
    k = (i > 0) - (i < 0);
    printf("(%d, %d), ", k * (l % 9 + 1), k * (l / 9 + 1));
  }
  printf("\n");
}

int main(int argc, char *argv[])
{
  struct STATE current, next;
  double delta, result, t;
  unsigned seed;
  int8_t i;

  seed = 1571773356;
  srand(seed);
  printf("seed: %d\n", seed);
  pos = 0;
  for(i = 0; i < 16; ++i)
  {
    buf[i] = rand() ^ (rand() << 16) ^ (rand() << 31);
  }

  init(&current);

  result = 0.0;

  t = 1.0;

  while(t > 0.001)
  {
    t *= 0.999;

    next = current;

    random_walk(&next);

    if(result < next.score)
    {
      result = next.score;
      print(&next);
    }

    delta = next.score - current.score;
    if(delta >= 0 || wellrng512() < RAND_MAX * exp(delta / t))
    {
      current = next;
    }
  }

  return EXIT_SUCCESS;
}
viewtopic.php?f=49&t=23051&start=130#p247941


Merci beaucoup à tous pour ces participations de haute facture ! :bj:

14 lots sont prévus pour vous récompenser, et nous allons maintenant pouvoir procéder à leur choix en commentaires. @Pavel, à toi l'honneur. ;)



Référence : https://www.planet-casio.com/Fr/forums/ ... sic-!.html
Lien vers le sujet sur le forum: Résultat concours rentrée 2019 - défi langage calculatrice (Commentaires: 371)

-
Rechercher
-
Social TI-Planet
-
Sujets à la une
Comparaisons des meilleurs prix pour acheter sa calculatrice !
Aidez la communauté à documenter les révisions matérielles en listant vos calculatrices graphiques !
Phi NumWorks jailbreak
123
-
Faire un don / Premium
Pour plus de concours, de lots, de tests, nous aider à payer le serveur et les domaines...
Faire un don
Découvrez les avantages d'un compte donateur !
JoinRejoignez the donors and/or premium!les donateurs et/ou premium !


Partenaires et pub
Notre partenaire Jarrety Calculatrices à acheter chez Calcuso
-
Stats.
1345 utilisateurs:
>1316 invités
>23 membres
>6 robots
Record simultané (sur 6 mois):
6892 utilisateurs (le 07/06/2017)
-
Autres sites intéressants
Texas Instruments Education
Global | France
 (English / Français)
Banque de programmes TI
ticalc.org
 (English)
La communauté TI-82
tout82.free.fr
 (Français)