π
<-
Chat plein-écran
[^]

Résultat du concours de rentrée 2020 - Défi Python de Xuanwu

Résultat du concours de rentrée 2020 - Défi Python de Xuanwu

Unread postby Lephe » 10 Nov 2020, 20:14

Salut à la communauté TI-Planet ! On se retrouve aujourd'hui pour analyser et classer les participations à notre Défi Python de Xuanwu, le premier défi de du concours de rentrée 2020 ! :)


Nous avons reçu
154 participations de 28 personnes
, le plus grand nombre de personnes individuelles et second plus grand nombre de participations toutes éditions confondues. Là-dedans, 6 personnes se sont placées dans la guilde Planète Casio et 16 dans la guilde TI-Planet. Merci à tous ! o/

Image

L'objectif de cette épreuve était de parcourir un labyrinthe en consommant le minimum d'énergie à l'aide d'un véhicule programmable. Les modalités ont été détaillées par Hackcell dans un topic d'entraide si vous voulez voir les détails ; les principaux éléments sont les suivants :

• Les contrôles disponibles sont de la forme avancer, tourner à gauche et tourner à droite.
• Il y a un coût fixe pour chaque action.
• Il y a aussi un coût sur le nombre de décimales des valeur spécifiées : avancer(1.3937) coûte plus cher que avancer(1.4).
• Il y avait plusieurs chemins et les chemins plus longs recevaient un petit bonus pour équilibrer.

Voyons voir ce que vous avez réussi à trouver avec ces règles ! Nous avons rédigé quelques commentaires pour chacune de vos participations, n'hésitez pas à ajouter des détails sensationnels et autres techniques secrètes dans les commentaires. :D


Le classement



26.
Image
KikooDX
(ImageImage) :
320011.24538193
(Programme : x37.py)

Notre première participation est de bien des façons également la meilleure. Voyez-vous, il y a un secret dans ce labyrinthe. Si vous tournez de 2⁹ radians vers la droite tout en avançant de 1337 pas entre chaque rotation, vous serez emmené·e tout droite à la sortie ! Définitivement la méthode la plus élégante !

Au fond cette technique reflète bien l'usage quotidien des calculatrices de niveau Lexibook, et ça se voit puisque le score final s'approche du rapport prix/qualité de la machine. x3

Image


25.
Anonyte
(Image) :
161.84356628353
(Programme : x18.py)

La participation suivante nous vient d'Anonyte. Personne n'a eu de mal à situer, vu le calcul du score, que les chemins ayant le moins de segments seraient les moins chers à autres facteurs égaux. On attaque donc avec un chemin de longueur 11, des angles et longueurs ajustés à la main - les angles au dixième, parfois au centième.

Ce score de 161 représente une amélioration de 99.949% par rapport à la participation précédente, la plus grosse séparation de toute l'épreuve. :troll:

Image


24.
Image
OulanB
(Image) :
138.59776036691
(Programme : x38.py)

En ajustant les longueurs au dixième également, OulanB évite les collisions avec les murs, qui sont lourdement pénalisées sur le score. On gagne immédiatement 23 points sur le résultat. Dans l'ensemble tout le monde a fait attention à ne pas croiser les murs quitte à s'arrêter au milieu des couloirs.

Image


23.
Image
Arm234
(Image) :
132.33617133049
(Programme : x84.py)

Le programme d'Arm234 est le premier à utiliser un chemin de 10 segments. Les longueurs sont ajustées au centième, ce qui ajoute entre 10 et 20 points, mais l'économie d'un segment (une orientiation à 5 points et un mouvement à 8 points, plus les décimales) permet de compenser. Ce qui montre bien que la première étape devait être de trouver le chemin le plus court sans se soucier du calcul des décimales. ;)

Image


22.
M4x1m3
(Image) :
105.42754591515
(Programme : x20.py)

Ce parcours de M4x1m3 est certainement le plus tordu de toutes les soumissions ! Malgré un bon détour, il atteint un score de 105 points. J'admets ne pas être certain de comment il en arrive là. :lol:

Image


21.
Image
Robin M.
:
104.18973099423
(Programme : x107.py)

Le chemin emprunté par Robin M. est le seul à passer par la ligne supérieure. C'est un passage que j'avais envisagé en ajoutant le bonus pour les chemins plus longs. Il n'est pas très compétitif (malheureusement ce problème laisse peu d'espace aux variations sur le chemin), mais ça reste une bonne approche qui s'avance très près de la barre de 100 points.

Image


20.
Image
Darks
(ImageImage) :
91.41917680793
(Programme : x52.py)

Avec Dark Storm on arrive au point du classement où tout le monde utilise la même technique de sortie. Ce zig-zag final permet d'éviter des tours et cache encore une surprise que le top 13 a su s'approprier. C'est aussi la dernière participation à 10 segments et la première en-dessous de 100 points. Le point d'équilibre parfait !

Image


19.
Image
CaptainLuigi
(ImageImage) :
81.601629520489
(Programme : x146.py)

C'est ce chemin qu'on découvre avec CaptainLuigi, à 9 segments, qui est utilisé par le plus de participants : 10 en tout. On est tout juste avant la limite de 80 de score et l'optimisation s'apprête à descendre dans les fins détails de distance, de décimales sur les angles, et de décimales sur le score.

Image


18.
Image
bebertii
(ImageImage) :
76.379566366772
(Programme : x123.py)

Avec le même chemin que le CaptainLuigi, mais 4 décimales de moins dans la spécification des angles et des longueurs, bebertii inaugure la catégorie 70-79 de score, qui est la dizaine finale. Aucun chemin soumis ne produisait un score en-dessous de 72 (décimales non comprises). De là à vous dire si c'est possible ou non... je vous laisse émettre les hypothèses.

Image


17.
Afyu
(ImageImage) :
76.000906078003
(Programme : x64.py)

Ce chemin est l'alternative à 9 segments. La plupart des meilleurs scores se sont battus entre cette version et celle des deux soumissions précédentes. La différence n'est pas énorme, mais c'est intéressant de voir alterner les formes au fur et à mesure qu'on monte en score. J'ai tenté d'équilibrer le score pour qu'il y ait plus d'un chemin optimal mais ce sont les deux qui tiennent la compétition.

Si vous avez regardé le code de génération, c'est ce que Wikipédia appelle le fusion aléatoire de chemins sauf qu'on continue de retirer des murs une fois le labyrinthe connexe, justement pour qu'il y ait plus de solutions.

Afyu nous a même donné une explication de sa méthode. ^^

Afyu wrote:Effectivement, j'ai tout fait moi même, mais sans décortiquer le script, donc j'ai raté l'astuce des angles à une seule décimale.
Pendant mes recherches, au début, j'ai choisi des arrondis, mais pas forcément au dixième

Code: Select all
distance[a]=int(100*distance[a]+1)/100

simplement parce que l'écriture avec un grand nombre de 9 après la virgule (dû à la méthode de calcul en binaire des ordi) des nombres déterminés par mon algorithme me dérangeait "esthétiquement". :p
J'ai effectivement le "bon" chemin (aux ajustements d'angles et de distances près) et j'ai également longuement travaillé sur le chemin finalement également choisi par Pavel. J'avais trouvé l'astuce de mettre une dernière distance hors bornes pour améliorer le score, mais ça n'a pas suffi.
(message original)

Image


16.
Image
Dubs
(ImageImage) :
74.750056119786
(Programme : x139.py)

La participation de Dubs est la seule rendue sur HP Prime. Pour rappel, le calcul des collisions et du score est fait purement formellement, et n'est pas impacté par l'affichage. Donc la notation est indépendante du modèle (sauf cas pathologiques de résultats de calcul en flottant). Notez qu'on revient au premier chemin de 9 segments.

Image


15.
Image
cent20
(Image) :
73.04042664132
(Programme : x102.py)

Alors qu'on se rapproche de la barre fatidique des 72, on repasse sur le chemin alternatif de 9 segments. À ce stade tout le monde limite au maximum l'utilisation des décimales, que les solutions soient optimisées à la main ou pas.

L'idée de compter les décimales vous surprendra peut-être. L'intuition c'est que si on autorise des nombres quelconques sans pénalité, il devient beaucoup plus facile, une fois qu'on a une idée générale du chemin à prendre, de calculer les angles et les longueurs qui optimisent la distance parcourue, le total d'angle parcouru, ou à peu près n'importe quelle métrique de votre choix.

De façon générale, les problèmes sur les réels sont
plus faciles
que les problèmes sur les entiers. Cette contrainte visait à vous empêcher de calculer les optimaux avec un programme en trois clics. Même si, vous le verrez à la fin du classement, ça s'est retourné contre moi puisque la pénalité était trop forte et du coup le nombre de valeurs viables (à 0.1 près) était faible, ce qui a permis à certains candidats de faire du brute-force.

Image


14.
Image
grandben49
(Image) :
73.003909873986
(Programme : x137.py)

Vous remarquerez que tout le monde ne fait pas le zig-zag final de la même façon. Certains le prennent de façon plus serrée, comme grandben49, alors que d'autres en font des paquets pour faire le long aller-retour possible. Ça vient du bonus attribué aux chemins les plus longs. Il n'y a de coût que pour utiliser les fonctions et spécifier des décimales. Une fois le nombre de segments fixé, c'est plus rentable de parcourir le plus de longueur possible pour minimiser le score.

Image


13.
Image
Ne0tuX
(ImageImage) :
72.747717453626
(Programme : x150.py)

Ne0tux est le premier dans ce classement à avoir utilisé le bonus de longueur (qu'il a remarqué de justesse) lors de la sortie du labyrinthe. Voyez-vous, pour une raison complètement intentionnelle que j'avais absolument prévue et validée durant les tests, le programme continue de vous faire avancer une fois que vous avez passé la sortie. :sry:

Du coup, si vous prenez un angle rasant pour sortir du labyrinthe le plus à l'horizontal possible, le chemin peut se prolonger sur un bon paquet de cases avant d'atteindre le mur fixé en bas de l'écran. Tout ce parcours supplémentaire s'ajoutant bien entendu au bonus de longueur, ce qui permet de réduire le score final.

Bravo à tous ceux qui s'en sont rendus compte à la lecture du code. ^^

Ne0tux wrote:J'ai procédé de façon un peu originale ; une réminiscence des défis de dessin des années précédentes. J'ai commencé par lire le code puis confirmer certaines intuitions via la GUI de Pavel. Puis j'ai téléchargé le code sur mon smartphone et imprimé le labyrinthe sur papier, avant de partir pour 15 jours de congés sans PC ni Wifi. Avec mon bout de papier, une règle, un rapporteur et la volonté de faire un nombre minimal de traits les plus longs possibles et passant par le centre des "portes", j'ai pu tracer une sorte de "couloir des possibles".

J'en ai testé plusieurs sur smartphone (sans GUI) et validant ma solution finale via la version Oméga en ligne. Comme comparer était fastidieux depuis mon petit écran, je n'ai pas cherché plus loin que le 1e digit pour la rotation (ça tombe bien, il fallait le moins de digit possible). Sauf sur l'un des premiers points, ce qui explique que je sois resté à 72. Pour la longueur des segments c'était moins drôle car la mesure sur mon papier ne correspondait pas : souvent on pouvait approcher un mur, augmenter la longueur et quand même diminuer le score. J'ai bien faillit ne pas le voir !

La seule "optimisation" scriptée pour moi concernait la longueur et l'orientation des deux derniers segments, pour aller chercher un x en dehors du labyrinthe le plus loin possible.
(message original)

Image


12.
jacobly
(Image) :
71.056893450111
(Programme : x31.py)

Une autre participation qui se démarque est celle de jacobly, qui n'utilise... que des entiers. Vous avez bien entendu : un peu d'imagination, une bonne heure de recherche et une calculatrice lui ont visiblement suffit pour passer sous la barre des 72. Je vous cache pas que je m'y attendais pas à celle-là. :whistle:

jacobly wrote:Not much to say about my method, just spent about an hour finding the shortest path with the original program, and couldn't be bothered optimizing floating-point error for the update.
(message original)

Image


11.
Image
Filoji
(ImageImage) :
71.018891561397
(Programme : x96.py)

Certains de ces commentaires sont très complets donc je vous laisse avec les explications. :)

Filoji wrote:
1 - Découverte

C'était la catastrophe, entre le topic d'entraide et les calculs incompréhensibles, je me disais que c'était peine perdue... Mais j'ai persévéré, et ai trouvé enfin le premier chemin ! (142 pts)
Bon, après j'ai continué et j'ai trouvé mieux (120 pts)

2 - Le sub 100

Je rejoins PC et Casio pour avoir la meilleur équipe (Parce que Lexibook :E)
Grâce à Bzh, j'ai trouvé le bon chemin (Il avait fait ça à l'arrache sur Gimp), et je trouve mes 1ers sub 100 !!! (88 pts)
Ensuite, Pavel nous partage son outil pour améliorer notre score, et je m’améliore encore (75 pts, 72 pts)

3 - La course aux décimales

C'est bon, j'ai compris la technique... Mais quelques heures trop tard !
J'arrive ex aequo avec toute les personnes de ce rang, et je cherche alors à faire le moins augmenter mon score pour pouvoir trouver un score unique
Ça y est, j'ai trouvé, Merci Pavel, j'ai séché ton programme pour enfin trouver les 71,01889156139690 et les 200 unités de déplacement pour optimiser le plus ma consommation

Fin, voilà, c'est pas extraordinaire, mais c'est moi qui l'ai fait ^^
(message original)

Image


10.
Image
TIny_Hacker
(Image) :
71.000399584431
(Programme : x151.py)

Pas mal de gens ont utilisé l'interface graphique de Pavel pour faire leurs tests. Critor et moi avions une version SDL2 de polycalc.py pour tester rapidement sur PC (... même si Critor a enduré la mise en compatibilité avec tous les modèles), mais Pavel a carrément créé un outil interactif pour explorer le labyrinthe. Alors tout de suite les scores sont descendus pas mal. :p

Voilà une image de l'explorateur interactif de Pavel, puis l'explication de TIny_Hacker.

Image

TIny_Hacker wrote:Honestly, I only did this well because of Pavel's GUI, which allowed me to test my ideas faster than manually typing them out, and to tweak things as I went. I started by figuring out on paper what path had the fewest number of segments and went from there. Eventually, I discovered that shortening the decimal on turns would decrease the score, and finally that adding a 0.000049999 (or something like that) could decrease the score without changing the path itself. Afterward, I just messed around till I got as low of a score as I could. That's about all there was to it!
(message original)

Image


9.
dvon
(Image) :
71.000243500836
(Programme : x152.py)

Pour sa part, dvon a utilisé un algorithme aléatoire, visiblement en déplaçant au hasard les angles de quasi-multiples de 2π le long du chemin pour obtenir un meilleur score. Le sujet imposait des limitations pour éviter ce genre de méthode, bravo pour les avoir contournées ! :)

Cette participation est la première à utiliser des variations d'angle et de distance inférieures à 10⁻⁵. En effet, à cause de différences de calcul d'une machine à l'autre, il a fallu faire pas mal de compromis sur l'évaluation du nombre de décimales. Un de ces compromis était d'arrondir à 5 chiffres après la virgule... ce que les participants observateurs se sont empressés d'utiliser à leur avantage.

dvon wrote:For my solution, I started with the GUI shared by Pavel. I added code to try to automatically tweak argument values to get lower scores. But this didn't help, because (as I figured out eventually) the best scores were always from the values with only one digit after the decimal point.

In the end I used a version of the GUI modified just a little bit. I added code to output a record of scores for everything I tried a long a path, so that I could make sure I was doing at least as well in the current attempt as in previous attempts, and I made it possible to tweak angle and distance arguments by +-0.000004 units (and not round
the tweak away), since this slight difference wouldn't affect the part of the score based on the number of characters needed to represent the value. Also, for each turn I experimented with adding or subtracting a full rotation (i.e., about 2pi but not exactly because of the 1/10 increments) and was able to avoid using any angles that would be treated as 4-character values in that part of the scoring.
(message original)

Image


8.
Ruadh
(ImageImage) :
71.000066133741
(Programme : x112.py)

Déjà top 8, et on arrive sur la première optimisation à coup de sinus. Un des problèmes des toutes premières versions du script c'est que seul le coût des déplacements était pris en compte. Ce coût est entier, il n'y a donc rien à exploiter entre 71 et 72... ce qui aurait fait beaucoup trop d'égalités.

Du coup j'ai proposé de faire la modification arbitraire d'ajouter au score le sinus de la somme des longueurs et angles utilisés durant le parcours. C'est fourbe parce que comme les participations sont limitées à peu de décimales, il n'est pas facile d'atteindre les valeurs minimales du sinus, qui se situent sur des demi-multiples de π. Par chance, 11 est presque égal à 3.5π donc il était possible d'avoir un sinus de presque -1 et donc d'arriver à presque 71. :)

Ruadh wrote:En lisant le programme, j'ai pu apprendre qu'il fallait :
- minimiser le nombre de virages
- ne pas foncer dans les murs
- parcourir une distance d'au moins 200
- utiliser des distances et angles avec au plus une décimale

J'ai donc cherché manuellement un chemin qui respecte toutes ces propriétés et j'ai obtenu un score aux alentours de 72. J'ai ensuite remplacé certaines rotations afin de minimiser le sinus (tourner à gauche de α revient à tourner à droite de -α) et j'ai obtenu le score 71,00001411857056 que beaucoup de personnes avaient déjà obtenu. J'ai donc à nouveau modifié les rotations pour avoir un score plus élevé.
(message original)

Image


7.
Image
Alice
(ImageImage) :
71.000014118571
(Programme : x88.py)

Hackcell résume superbement l'intégralité des règles et techniques utilisées jusqu'ici. ^^

Hackcell wrote:Alors, j'ai vraiment procédé étape:

- Premier jet à la R.A.C.H.E (iso-1664) qui me donne dans les 150 points
-Lecture du code et écriture d'un topic sur ce dernier, je me rend donc compte qu'il faut minimisé le nombre de virage et maximiser la distance (dans la limite des 200 unité arbitraire)
- j'obtient donc un score d'environ 93.
- je me rends compte que l'on peut continuer une fois sortit du labyrhinte, ce qui facilite la maximisation de la distance, je descend a un score de ~83 (si continuer ainsi n'avais pas été possible, l'epreuve aurait sans doute été beaucoup plus challenging, mais c'etait fun quand même)
- grâce a ma connaissance du code, je me rends compte que le seul moyen de descendre c'est de supprimé un virage ou faire disparaitre les décimales. Or le meilleur score actuel est de 72 ce qui correspond au score que j'obtiendrait si j. supprimais ces decimales, je recherche donc de ce cotés, et bingo, 77, puis le fameux 72.
- enfin presque, entre temps il y a une régles en plus, on reçoit des points en fonction du sinus d'une fonction assez simple a manipuler, le seul probléme c'est que pour supprimé les décimales on se retrouve a se balader de 0.1 en 0.1 sur cette fonction, ce qui n'est pas l'idéal pour la minimiser, je test donc plusieur valeurs , change des virages a droite de theta par des a gauche de -theta, tente de continuer aprés la sortie pour explorer cette fonction en restant dans les conditions optimales (9 virages, pas plus d'une décimale) et finis avec un 71,000…
Je décide alor de m'arreter là jusqu'a ce qu'un score qui signifirais 8 virages soit trouvé, ce qui n'est pas arrivé.
(message original)

Image


6.
Image
Ti64CLi++
(ImageImage) :
71.000013644375
(Programme : x153.py)

Malgré l'utilisation d'un bon vieux sinus pour tenter de faire sortir des scores différents à tout le monde, Ti64CLi++ s'est retrouvé plusieurs dans la situation de devoir ajuster ses scores pour éviter de créer des égalités (qui étaient interdites). Les plus rapides y trouvent leur compte... cela dit je veut bien donner un cookie à qui saura produire une égalité sur le défi du Léviathan sans se concerter ! :E

Ti64CLi++ wrote:Alors, j'ai vraiment tout fais à la main.

J'ai commencé par tester le programme et voir quel score je pouvais obtenir comme premier jet, et c'est ainsi que j'ai envoyé mon premier score de 148.

Ensuite, j'ai vite compris que moins il y avait de segment, et plus ceux-ci étaient long tout en minimisant le chemin, meilleur le score était. Après plusieurs essais, j'ai donc obtenu les scores de 133 puis 99 puis 80. Entre temps, j'ai du donc changé de chemin pour descendre à 9 segments.

Là j'ai commencé à bloqué, puis une première lecture du code m'a permise de me rendre compte que les chiffres significatifs jouaient un rôle important dans le calcul du score. J'ai donc cherché un moyen de passer à un unique chiffre après la virgule. J'ai ainsi baissé mon score à 74 puis 73 puis 72.

Encore une fois, j'ai un peu galéré, mais après 1h de différents tests sur le même chemin, j'ai enfin passé la barre fatidique des 72. Il restait encore quelques améliorations à faire, mais après quelques changements minimes, je suis arrivé à mon score de 71.000014.
Tout ça pour me rendre compte plus tard dans la journée après mise à jour des participation, que Tituya avait envoyé le même score quelques 40 minutes plus tôt.
J'ai donc baissé mon score du minimum que je pouvais, et j'ai envoyé mon 71.00554.

Je suis resté sur ce score jusqu'à ce que _iPhoenix_ descende en dessous de moi, et me propose de m'aider si vraiment je coince. Il me dit donc de regarder attentivement la fonction cout, à laquelle je n'avais pas vraiment fait gaffe.
Après quelques réflexions et tests avec Python, je me suis aperçu que je pouvais encore baisser mon score en jouant sur les chiffres à 5 ou plus positions de la virgule à droite.
J'ai donc aisément réussi à baisser mon score en appliquant cette technique et j'ai obtenu 71.0000139, parce que comme un débile je n'ai appliqué ça qu'aux distances et non aux angles. Tout ça pour me rendre compte que, encore une fois, Tituya, n'avait lui pas fait cette erreur, et par la suite avais soumis un score de 71.0000136.

Enfin, quelques heures (pratiquement 2h tout pile) avant la fin du concours, j'ai retrouvé un peu de motivation, et me suis donc assuré la 6ème place en appliquant cette fois-ci la méthode aux angles. J'ai donc envoyé mon score de 71.00001364437452.
(message original)

Image


5.
Image
Tituya
(ImageImage) :
71.000013644375
(Programme : x141.py)

Le top 5 est excessivement complet dans ses explications, donc je leur laisse la parole !

Tituya wrote:On commence doucement avec une première tentative à 152. Ce score a bien chuté depuis :lol:

Image

À la toute première approche je n'ai absolument rien testé de précis, j'essaye simplement de voir à la main ce que je peux produire et comment contrôler cette
machine mystique
.

Un peu de lecture, ça ne fait pas de mal :


Je comprends cependant très vite que nous devons améliorer le nombre de virages pour changer la valeur du score. Je remarque en même temps que l'instruction `a_gauche` semble être plus rentable que sa compère `a_droite`.
Et en effet, cela me permet bien de diminuer mon score.

Je continue ma lecture du code. Nous avons une
distance maximale possible de 200
. Qui donne un bonus considérable sur le score final, il faut donc maximiser celui-ci !

L'art du bourrinage :


Dans une envie soudaine, je programme un code de bruteforce me permettant de trouver théoriquement le meilleur score possible. Je me rends vite compte que la vitesse de python et le nombre de calculs à faire rend juste impossible cette procédure :E

Je lance quand même ce script pour optimiser les 3 premiers virages. Qui me donne des résultats plus que corrects !
Je lance ainsi de suite des optimisations grâce à ce script d'une succession de virages. Ce qui m'amène à ce fameux score assez commun de
71,00001411857056


Puis je bloque.


Je pars en freestyle pour voir ce que ça donne :


Mais au bout d'un moment je me demande si je ne peux pas rajouter des 0 ou des 9 un peu partout sans aucune logique peut me permettre de descendre.
Dans ma tête, le principe est simple :

Il faut limiter au maximum la distance totale tout en gardant le score[6] à 200.

J'essaye, ça marche correctement... Super ! :p

Puis j'essaye des valeurs de plus en plus précise pour voir si ça change quelque chose, je me rends compte qu'en dessous de x.x99995, mon score descend.
J'optimise donc à la main chaque virages pour enfin arriver à mon score final :
71,00001364437450


Des tentatives théoriques


À partir de là, un peu de théorique. La précision des virgules est géré par le total (virage + distance). Je calcule alors ce que je dois enlever pour obtenir un score maximal.

Je n'ai cependant jamais réussi à trouver ce score... Peut-être qu'il est d'ailleurs impossible à avoir :@
Donc j'arrive avec ce magnifique score qui me donne la chance d'être 5e dans ce concours !
(message original)

Image


4.
Image
LeGmask
(Image) :
71.000009639162
(Programme : x149.py)

LeGmask wrote:Spoiler: j'ai tout fait a la main
Dans les faits la plupart de mes outils mon fait perdre plus de temps qu'autre chose, après nombreuse tentative je suis descendu a 100 et des brouettes et y suis resté bon nombre de temps, j'ai fini par craquée et est demandée des indices a _iPhoenix_ :)
C’est là que le massacre commence, de 1 j’avais pas le bon chemin, et de 2 j’avais des angles a 2 décimales …

Après quelque heure de recherche je finis finalement par descendre a 71,…14… sauf que spoiler, vu que je m’y suis pris encore une fois 3 mois après la course, le score était pris :notlikethis:
À ce point obligé de détériorer mon score afin de publier pour la première fois mon résultat.

Le cours de philo qui suit ne ma pas porter conseille et encore une fois _iPhoenix_ ma sauvée la mise avec un précieux indice, j’avais compris le code de l’arrondis, mais pas totalement vu que je n’avais pas pensée au tout petit décimal qui pourrait optimiser le tout encore plus 😊

Finalement je descends et me place en 6e position, là j’ai beau essayée tout ce que je peux je ne comprends pas, comment descendre beaucoup plus, puis encore une fois un indice sur le sinus par _iPhoenix_ ma remis sur le pied de guerre, j’ai donc cherché et vu qu’on pouvait descendre sur le sinus de 11 beaucoup plus proche de -1, la avec les décimaux j’ai pu descendre mon score et me placer 4e
Dans tous les cas je remercie grandement _iPhoenix_ pour tous ces petits conseils, sans lui je ne saurais sans doute pas là, et je reste une grande arnaque 😊.
(message original)

Image


3.
Image
_iPhoenix_
(Image) :
71.000009399186
(Programme : x134.py)

_iPhoenix_ wrote:After getting the opencv2 script from commandblockguy, I tried getting a path that worked, not thinking too much about scoring- I ended up with a score that was around 470 or so, not so great: (click any image to enlarge)

Image

After realizing that turning and moving had a fixed cost in addition to their distance, I tried to reduce the number of segments:

Image

Image

This got me to around 86 or so. (One interesting trick I employed was lengthening the last segment out of bounds)

This all happened within an hour or so of me having the code, so I didn't really write or use any tools at this point- there was no need.

I eventually wrote a function that would let me give it points- this took me longer than I would care to admit (my trig is quite rusty). Here it is, in all of its glory:

Code: Select all
def move_to(x, y):
  cur_x, cur_y, cur_angle = state[0:3]
  a_gauche(round(cur_angle - atan2((y - cur_y), (x - cur_x)), 1))
  avancer(round(sqrt((x - cur_x) ** 2 + (y - cur_y) ** 2), 1))

I modified the functions for turning and for moving so they would dump code I could submit into a file- this was a really simple change and was extremely convenient.

For brute-forcing, I just defined a noise function that was easy for me to tweak (for example, changing it to a Gaussian distribution or tweaking the parameters). I mostly used brute-forcing to eliminate decimal places.

Code: Select all
def noise():
  return (random() - 0.5)/10

Throughout this process, commandblockguy was extremely helpful. I did feel a little guilty asking for help, but I made sure to at least drop hints to anyone who asked me in return (which ended up being a decent number of people) :)
(message original)

Image


2.
Image
Pavel
(ImageImage) :
71.000009399186
(Programme : x86.py)

Pavel wrote:Voici une explication de mon approche pour trouver une solution à ce défi.

J'ai commencé par essayer de comprendre comment la consommation est calculée. Voici les parties du code Python montrant tous les composants des calculs de consommation:

Code: Select all
def fix_angle(a):
  return a * 2 * asin(1) / pi

def a_gauche(a):
  global state
  state[7] += a
  state[5] += 5 + cout(a)

def avancer(l):
  global state
  state[7] += l
  state[5] += 8 + cout(l)
  while(l > 0):
    l -= .25
    state[6] += (state[6] < 200)

def aller_selon(f):
  global state
  state = [0, .5, 0, 0, .5, 0, 0, 0]
  f()
  state[5] += sin(fix_angle(state[7])) - state[6] // 2
  print('Consommation : ' + str(state[5]))

Apparemment, la consommation se compose des trois éléments suivants:

• `state[5]` = consommation de base
• `state[6]` = distance totale parcourue multipliée par quatre
• `state[7]` = angle total + distance totale

Ensuite, j'ai testé la fonction 'cout()' qui est utilisée dans les calculs de consommation:

Code: Select all
>>> from laby import *
>>> cout(5)
3
>>> cout(0.5)
3
>>> cout(0.05)
4
>>> cout(5e-3)
5
>>> cout(5e-4)
6
>>> cout(5e-5)
7
>>> cout(5e-6)
3

Il semble donc que la consommation puisse être minimisée en combinant les éléments suivants:

• minimiser la quantité de manoeuvres
• minimiser 'sin(state[7])'
• maximiser la distance totale parcourue
• ne pas utiliser plus d'un chiffre décimal après la virgule décimale
• essayer d'exploiter le faible coût du 'cout(5e-6)'

Pour minimiser 'sin(state[7])', j'ai utilisé le code Python suivant pour créer un tableau montrant les valeurs de la fonction 'sin()' pour différents angles avec un seul chiffre décimal après la virgule décimale:

Code: Select all
from math import pi, sin

l = []

for i in range(-10, 11):
  a = round(-pi/2 + 2 * pi * i, 1)
  l.append((a, sin(a)))

l.sort(key=lambda e: e[1])

for e in l:
  print('a = %5.1f -> sin(a) = %f' % e)

Voici le résultat:

Code: Select all
a = -64.4 -> sin(a) = -0.999996
a = -26.7 -> sin(a) = -0.999994
a =  11.0 -> sin(a) = -0.999990
a =  48.7 -> sin(a) = -0.999986
a =  42.4 -> sin(a) = -0.999934

De petites valeurs de 'state[7]' sont donc nécessaires pour une faible consommation. Vu que 'state[7]' est la somme des angles et des distances et que les distances ne peuvent pas être négatives, alors les valeurs des angles passés à la fonction 'a_gauche()' doivent être négatives.

Une fois que tout ça est devenu plus ou moins clair, j'ai modifié le code laby.py pour en faire une version qui peut être contrôlée comme un jeu vidéo avec les touches haut/bas/gauche/droite sur le clavier: https://gitea.planet-casio.com/Pavel/labygui

En utilisant cette approche, j'ai obtenu la solution suivante:

Code: Select all
from laby import *

def chemin():
  for e in [(-6.6, 2.3), (-7.3, 6.3), (-5.2, 4.6), (-4.8, 4.1), (-7.3, 6.3), (-8.3, 3.8), (-5.1, 3.8), (-2.3, 4.3), (9.1, 13.3)]:
    a_gauche(e[0])
    avancer(e[1])

aller_selon(chemin)

La consommation correspondant à cette solution est de 71.0000097934493.

À ce stade, je n'ai toujours pas exploité le faible coût du 'cout(5e-6)'. J'ai donc essayé d'ajouter ou de soustraire 5e-6 des distances et des angles. La solution qui m'a donné le score le plus bas (71.00000939918644) était la suivante:

Code: Select all
from laby import *

def chemin():
  for e in [(-6.6, 2.3), (-7.3, 6.3), (-5.2, 4.6), (-4.8, 4.1), (-7.3, 6.3), (-8.3, 3.8), (-5.1, 3.8), (-2.3, 4.3), (9.1, 13.3)]:
    a_gauche(e[0] - 5e-6)
    avancer(e[1] - 5e-6)

aller_selon(chemin)

Au moment où j'ai trouvé cette solution, elle était déjà soumise par commandblockguy et j'ai dû trouver la deuxième meilleure solution (71.00000939918645) en ajoutant de très petites valeurs aux angles et aux distances:

Code: Select all
from laby import *

def chemin():
  for e in [(-6.6, 2.3), (-7.3, 6.3), (-5.2, 4.6), (-4.8, 4.1), (-7.3, 6.3), (-8.3, 3.8), (-5.1, 3.8), (-2.3, 4.3), (9.1, 13.3)]:
    a_gauche(e[0] - 5e-6 + 1e-13)
    avancer(e[1] - 5e-6 + 1e-13)

aller_selon(chemin)
(message original)

Image


1.
commandblockguy
(Image) :
71.000009399186
(Programme : x75.py)

commandblockguy wrote:As for my strategy, I basically found a path through the maze by hand that had as few points as possible, without worrying about my score too much. I made sure to take a very shallow angle when exiting so that the path would be long enough to get the maximum score.

I then tested every single combination of angles and distances that would put me within some distance (if I remember correctly, about 1.5 tiles, though I changed it several times) of my original points, while still allowing me to get the maximum score. This was feasible because you get points off for each digit after the first decimal place, or before the units place, which means that there are only 100 angles and 100 distances to try for each point. The exception for this is the last point, which has to be more than 10 units away in order to meet the length requirement. This took a few hours to run in its entirety, and I was left with a few thousand paths. Prior to the scoring change, all of these paths would have left me with a score of 72, but after the scoring change it was now possible to get a fractional score.

Image
A "heatmap" of all the paths I found. The color of each point represents the last "target" point it was able to get to, with purple being the final point, outside of the maze.

The fractional part of the score was determined based on the sine of the sum of the angles and distances, which means that the input to sin() could be no more precise than to the tenths place. For the range of numbers that this sum could possibly be without adding a full point to my score, the tenth whose sine is closest to -1 is 11.0, and sin(11) is = -0.999990207.

Unfortunately, none of the few thousand paths that I had found added up to 11.0. However, I realized that I was only calling a_droite() in my path, and that if I replaced a_droite(x) with a_gauche(-x), x would be subtracted from the sum rather than added to it, without actually changing the validity of the path. I tried out every combination of a_droite and a_gauche calls for each of my few thousand paths, and found one that added up to 11.0, giving me a score of 71.0000097934493.

Here's the code that I used to find this path.

You'll notice that this is still very slightly off from my actual score - I realized that I could slightly decrease sin(sum) by slightly decreasing sum, and that I could slightly decrease sum by subtracting a tiny amount from each distance and angle. Normally, this would cause my score to increase by several full points because of the decimal places after the tenths place, but because the score is rounded to 5 decimal places before the length of the number is calculated, if the difference is less than 0.000005, you aren't penalized. So, I subtracted 0.0000049999... from each distance, to get a sum of 10.99991, a sine of -0.99999060081, and a final score of 71.00000939918644. I believe that this is within a floating-point error of the ideal solution.

Here's the solution that I submitted, for reference.

I actually tested all of this on a computer, as I didn't have my EP with me. I ported polycalc to use cv2 for drawing stuff.

I also tried to submit a few, uh, let's call them
gimmicky
, solutions. My first instinct was to try an integer overflow, but to my disappointment, Python doesn't actually have those. The numbers, they just keep
going
.

After that, I tried subclassing the float class so that it would return an empty string. Technically, this wasn't modifying the internal state of laby.py :p . I could have also returned a custom string class with a modified __len__ method, but in CPython __len__ must return a positive integer, which also gets converted into a regular integer, not one that I could subclass. Interestingly, MicroPython allows you to return a negative length for __len__, so I could have probably gotten a score of negative infinity if the admins didn't shut that idea down :p .

Finally, I also found a solution that's far better than the others that I decided not to submit since I was already in first. Here's the link if you want to give it a try for yourself.
(message original)

Image


Conclusion



Ce sujet de labyrinthe était assez simple dans son ensemble, mais avec pas mal de subtilités qui ont bien fait ressortir ce qu'on espérait - des solutions de tous niveaux, avec des approches presques toutes différentes et pas mal de fun à la clé d'après vos témoignages. :)

Mon regret personnel sur cet énoncé c'est l'existence d'une solution unique. J'ai eu plusieurs retours expliquant que l'attrait d'un des défis les plus populaire du concours de rentrée (le défi de Python consistant à constituer une équipe de Pokémon efficace) est l'existence de multiples solutions même au voisinage des meilleurs scores. On a modifié à ce moment-là le deuxième sujet en introduisant un état, la vitesse du ballon. Chaque ordre se construit sur le précédent et donc on ne peut pas optimiser les ordres un à la fois, ce qui rend plus pénible l'exploration de tout l'espace de solutions.

Mais le sujet qui arrive vraiment à éviter ça est le défi du Léviathan puisque l'espace de solutions est formé de programmes et là les solutions seront vraiment toutes uniques. Ce défi est toujours en cours d'ailleurs, allez y jeter un oeil ou deux ! :)

Un immense merci à tous les participants. J'espère que cet exercice vous aura plus, et on se retrouve bientôt pour les résultats du défi du Quetzalocoatl ! ;)
User avatar
LephePartenaire
Niveau 9: IC (Compteur Infatigable)
Niveau 9: IC (Compteur Infatigable)
Level up: 71.1%
 
Posts: 286
Joined: 15 Jun 2018, 19:53
Gender: Male

Online

Re: Résultat du concours de rentrée 2020 - Défi Python de Xu

Unread postby critor » 10 Nov 2020, 20:19

Merci. Félicitations pour ce compte-rendu d'excellente facture qui se lit comme un roman, mêlant une précision méticuleuse avec une bonne dose d'humour. :bj:

Je n'aurais pas fait mieux. ;)

Et bien évidemment, merci à tous les participants. :)
Image
User avatar
critorAdmin
Niveau 19: CU (Créateur Universel)
Niveau 19: CU (Créateur Universel)
Level up: 9.7%
 
Posts: 36270
Images: 9889
Joined: 25 Oct 2008, 00:00
Location: Montpellier
Gender: Male
Calculator(s):
Class: Lycée
YouTube: critor3000
Twitter: critor2000
Facebook: critor.ti
GitHub: critor

Re: Résultat du concours de rentrée 2020 - Défi Python de Xu

Unread postby cent20 » 10 Nov 2020, 20:55

Oui le compte rendu est un vrai régal à lire, même si je remarque que je n’ai reçu aucune réponse à mes multiples demandes pour disqualifier les 14 premiers... :troll:

Le côté « secret de la conception » et « aléa associés » ajoute un côté intriguant à ce défi.
Image
Enseignant de mathématiques et de spécialité NSI ( projets, tutos ...)
:favorite: NumWork, Python : démineur, snake, tétris
User avatar
cent20Premium
Niveau 13: CU (Calculateur Universel)
Niveau 13: CU (Calculateur Universel)
Level up: 39.1%
 
Posts: 524
Images: 38
Joined: 17 May 2012, 09:49
Location: Avignon
Gender: Male
Calculator(s):
Twitter: nsi_xyz

Re: Résultat du concours de rentrée 2020 - Défi Python de Xu

Unread postby Lephe » 10 Nov 2020, 22:15

Merci pour les retours ! Ça me fait très plaisir. La façon dont on conçoit les épreuves est parfois très différente de celle dont vous les abordez (c'est un peu le cas ici), et cette description clôt le puzzle d'une certaine façon. :)

(...) même si je remarque que je n’ai reçu aucune réponse à mes multiples demandes pour disqualifier les 14 premiers... :troll:

Tu es sûr que tu n'étais pas dans le top 14 au moment où tu as formulé la requête ? :troll:
User avatar
LephePartenaire
Niveau 9: IC (Compteur Infatigable)
Niveau 9: IC (Compteur Infatigable)
Level up: 71.1%
 
Posts: 286
Joined: 15 Jun 2018, 19:53
Gender: Male

Re: Résultat du concours de rentrée 2020 - Défi Python de Xu

Unread postby TIny_Hacker » 11 Nov 2020, 01:50

Very nice! Now to read the entire thing... :P Very excellent analyzation as well!
User avatar
TIny_Hacker
Niveau 7: EP (Espèce Protégée: geek)
Niveau 7: EP (Espèce Protégée: geek)
Level up: 18%
 
Posts: 24
Joined: 01 Oct 2020, 00:50
Gender: Male
Calculator(s):

Re: Résultat du concours de rentrée 2020 - Défi Python de Xu

Unread postby Ti64CLi++ » 11 Nov 2020, 10:51

Comme le dit critor, ça se lit vraiment très bien, bien joué :bj:
Merci à vous deux pour ce concours qui était, malgré toutes les égalités où je me suis fait avoir, très intéressant !
Image
User avatar
Ti64CLi++Modo
Niveau 16: CC2 (Commandeur des Calculatrices)
Niveau 16: CC2 (Commandeur des Calculatrices)
Level up: 7.2%
 
Posts: 3368
Images: 75
Joined: 04 Jul 2014, 14:40
Location: Clermont-Ferrand 63
Gender: Male
Calculator(s):
Class: MP
GitHub: Ti64CLi

Re: Résultat du concours de rentrée 2020 - Défi Python de Xu

Unread postby LeGmask » 11 Nov 2020, 10:56

Incroyable :bj: je me suis tellement amusé a faire ce concours. :D
User avatar
LeGmaskVIP
Niveau 11: LV (Légende Vivante)
Niveau 11: LV (Légende Vivante)
Level up: 70.5%
 
Posts: 38
Images: 4
Joined: 20 Dec 2019, 16:49
Gender: Male
Calculator(s):
Class: Term : Maths - SVT - Maths Expert
GitHub: LeGmask


Return to News Divers

Who is online

Users browsing this forum: Tituya and 4 guests

-
Search
-
Featured topics
Comparaisons des meilleurs prix pour acheter sa calculatrice !
Découvre les nouvelles fonctionnalités en Python de l'OS 5.2 pour les Nspire CX II
Découvre les nouvelles fonctionnalités en Python de l'OS 5.5 pour la 83PCE/84+C-T Python Edition
Omega, le fork étendant les capacités de ta NumWorks, même en mode examen !
1234
-
Donations / Premium
For more contests, prizes, reviews, helping us pay the server and domains...

Discover the the advantages of a donor account !
JoinRejoignez the donors and/or premium!les donateurs et/ou premium !


Partner and ad
Notre partenaire Jarrety Calculatrices à acheter chez Calcuso
-
Stats.
682 utilisateurs:
>662 invités
>14 membres
>6 robots
Record simultané (sur 6 mois):
6892 utilisateurs (le 07/06/2017)

-
Other interesting websites
Texas Instruments Education
Global | France
 (English / Français)
Banque de programmes TI
ticalc.org
 (English)
La communauté TI-82
tout82.free.fr
 (Français)