L'utilisateur CarpetPython a publié une nouvelle approche de ce problème qui met beaucoup plus l'accent sur les solutions heuristiques, en raison d'un espace de recherche accru. Personnellement, je pense que ce défi est beaucoup plus gentil que le mien, alors pensez à l'essayer!
Vector racing est un jeu addictif qui peut être joué avec un stylo et une feuille de papier à la règle. Vous tracez un circuit arbitraire sur le papier, définissez un début et une fin, puis vous dirigez votre voiture de la taille d'un point par tour. Arrivez à la fin le plus vite possible, mais faites attention de ne pas vous retrouver dans un mur!
La piste
- La carte est une grille à deux dimensions, où chaque cellule a des coordonnées entières.
- Vous vous déplacez sur les cellules de la grille.
- Chaque cellule de la grille fait partie de la piste ou constitue un mur.
- Exactement une cellule de piste est la coordonnée de départ.
- Au moins une cellule de piste est désignée comme objectif. Atterrir sur l'un de ceux-ci complète la course. Les cellules à objectifs multiples ne sont pas nécessairement connectées.
Diriger la voiture
Votre voiture démarre à une coordonnée donnée et avec un vecteur vitesse (0, 0)
. À chaque tour, vous pouvez ajuster chaque composante de la vitesse ±1
ou la laisser telle quelle. Ensuite, le vecteur de vitesse résultant est ajouté à la position de votre voiture.
Une image peut aider! Le cercle rouge était votre position le dernier tour. Le cercle bleu est votre position actuelle. Votre vitesse est le vecteur du cercle rouge au cercle bleu. À ce tour, en fonction de la manière dont vous ajustez votre vélocité, vous pouvez passer à n’importe quel cercle vert.
Si vous atterrissez dans un mur, vous perdez immédiatement.
Ta tâche
Vous l'avez deviné: écrivez un programme qui, avec une piste de course en entrée, dirige la voiture vers l'une des cellules de but en aussi peu de virages que possible. Votre solution doit pouvoir traiter raisonnablement bien des pistes arbitraires et ne pas être spécifiquement optimisée par rapport aux scénarios de test fournis.
Contribution
Lorsque votre programme est appelé, lisez stdin :
target
n m
[ASCII representation of an n x m racetrack]
time
target
est le nombre maximum de tours que vous pouvez effectuer pour terminer la piste, et time
votre budget temps total pour la piste, en secondes (pas nécessairement un nombre entier). Voir ci-dessous pour plus de détails sur le timing.
Pour la piste délimitée par une nouvelle ligne, les caractères suivants sont utilisés:
#
- murS
- le départ*
- un but.
- toutes les autres cellules de voie (c.-à-d. Route)
Toutes les cellules en dehors de la n x m
grille fournie sont supposées être des murs.
L'origine des coordonnées est dans le coin supérieur gauche.
Voici un exemple simple:
8
4.0
9 6
###...***
###...***
###...***
......###
S.....###
......###
En utilisant l'indexation basée sur 0, la coordonnée de départ serait (0,4)
.
Après chaque déménagement, vous recevrez d'autres informations:
x y
u v
time
Où x
, y
, u
, v
sont tous les entiers à base 0. (x,y)
est votre position actuelle et (u,v)
votre vitesse actuelle. Notez que x+u
et / ou y+v
pourrait être hors limites.
time
est ce qui reste de votre budget temps, en secondes. N'hésitez pas à l'ignorer. Ceci ne concerne que les participants qui souhaitent réellement mener à bien leur mise en œuvre.
Lorsque le jeu est terminé (parce que vous avez atterri dans un mur, que vous êtes sorti des limites, que vous avez dépassé les target
tours, que vous n’avez plus atteint le but ou que vous avez atteint le but), vous recevez une ligne vide.
Sortie
Pour chaque tour, écrivez sur stdout :
Δu Δv
où Δu
et Δv
sont chacun l' un des -1
, 0
, 1
. Ceci sera ajouté (u,v)
pour déterminer votre nouvelle position. Juste pour clarifier, les instructions sont les suivantes
(-1,-1) ( 0,-1) ( 1,-1)
(-1, 0) ( 0, 0) ( 1, 0)
(-1, 1) ( 0, 1) ( 1, 1)
Une solution optimale pour l'exemple ci-dessus serait
1 0
1 -1
1 0
Notez que le contrôleur ne se lie pas à stderr , vous êtes donc libre de l’utiliser pour tout type de sortie de débogage dont vous pourriez avoir besoin lors du développement de votre bot. Veuillez supprimer / commenter tout résultat de ce type dans votre code soumis, cependant.
Votre bot peut prendre une demi-seconde pour répondre à chaque tour. Pour les tours qui prennent plus de temps, vous aurez un budget de temps (par piste) de target/2
secondes. Chaque fois qu'un tour prend plus d'une demi-seconde, le temps supplémentaire sera déduit de votre budget-temps. Lorsque votre budget temps est à zéro, la course en cours sera annulée.
Nouveau: pour des raisons pratiques, je dois définir une limite de mémoire (car la mémoire semble être plus contraignante que le temps pour des tailles de piste raisonnables). Par conséquent, je devrai abandonner tout test où le coureur utilise plus de 1 Go de mémoire, mesurée par Process Explorer en octets privés .
Notation
Il y a un repère de 20 pistes. Pour chaque piste:
- Si vous terminez la piste, votre score est le nombre de coups nécessaires pour atteindre une cellule de but divisée par
target
. - Si vous manquez de temps / mémoire ou si vous n'atteignez pas l'objectif avant la fin des
target
tours ou si vous atterrissez dans un mur / hors des limites à tout moment, votre score est2
. - Si votre programme n’est pas déterministe, votre score correspond à la moyenne de 10 passages sur cette piste (veuillez l'indiquer dans votre réponse).
Votre score global est la somme des scores de chaque piste. Le score le plus bas gagne!
En outre, chaque participant peut (et est fortement encouragé à) fournir une piste de référence supplémentaire , qui sera ajoutée à la liste officielle. Les réponses précédentes seront réévaluées, y compris cette nouvelle piste. Cela permet de s’assurer qu’aucune solution n’est trop adaptée aux cas de test existants et de prendre en compte les cas intéressants que j’aurais peut-être manqués (mais que vous pourriez remarquer).
Rupture de cravate
Maintenant qu'il existe déjà une solution optimale, ce sera probablement le facteur principal pour les scores des participants.
S'il y a une égalité (en raison de plusieurs réponses résolvant toutes les pistes de manière optimale ou autre), j'ajouterai des cas de test supplémentaires (plus grands) pour rompre l'égalité. Pour éviter tout préjugé humain lors de la création de ces liens, ceux-ci seront générés de manière fixe:
- Je vais augmenter la longueur des côtés
n
par10
rapport à la dernière piste générée de cette façon. (Je peux sauter des tailles si elles ne brisent pas la cravate.) - La base est ce vectoriel
- Celui-ci sera pixellisé à la résolution souhaitée à l'aide de cet extrait de Mathematica .
- Le début est dans le coin en haut à gauche. En particulier, ce sera la cellule la plus à gauche de la rangée la plus haute de cette extrémité de la piste.
- Le but est dans le coin en bas à droite. En particulier, ce sera la cellule la plus à droite de la rangée la plus basse de cette extrémité de la piste.
- La
target
volonté4*n
.
La piste finale du benchmark initial était déjà générée comme ceci, avec n = 50
.
Le controlle
Le programme qui teste les soumissions est écrit en Ruby et se trouve sur GitHub avec le fichier de référence que je vais utiliser. Il y a aussi un exemple de bot appelé randomracer.rb
ici, qui choisit simplement des mouvements aléatoires. Vous pouvez utiliser sa structure de base comme point de départ pour que votre bot voie comment fonctionne la communication.
Vous pouvez exécuter votre propre bot contre un fichier de piste de votre choix, comme suit:
ruby controller.rb track_file_name command to run your racer
par exemple
ruby controller.rb benchmark.txt ruby randomracer.rb
Le référentiel contient également deux classes Point2D
et Track
. Si votre soumission est rédigée en Ruby, n'hésitez pas à les réutiliser pour votre commodité.
Commutateurs de ligne de commande
Vous pouvez ajouter des commutateurs de ligne de commande -v
, -s
, -t
avant le nom du fichier de l'indice de référence. Si vous souhaitez utiliser plusieurs commutateurs, vous pouvez également utiliser, par exemple -vs
. Voilà ce qu'ils font:
-v
(verbose): utilisez-le pour produire un peu plus de résultats de débogage à partir du contrôleur.
-s
(silencieux): Si vous préférez garder vous-même votre position et votre vélocité sans vous soucier du budget temps, vous pouvez désactiver ces trois lignes de sortie à chaque tour (envoyé à votre soumission) avec ce drapeau.
-t
(pistes): vous permet de sélectionner des pistes individuelles à tester. Par exemple -t "1,2,5..8,15"
, les pistes 1, 2, 5, 6, 7, 8 et 15 ne seraient testées que. Merci beaucoup à Ventero pour cette fonctionnalité et l’analyseur d’options.
Votre soumission
En résumé, veuillez inclure les éléments suivants dans votre réponse:
- Ton score.
- Si vous utilisez un caractère aléatoire, indiquez-le afin que je puisse moyenner votre score sur plusieurs analyses.
- Le code pour votre soumission.
- Emplacement d'un compilateur ou interprète gratuit correspondant à la langue de votre choix et s'exécutant sur un ordinateur Windows 8.
- Instructions de compilation si nécessaire.
- Une chaîne de ligne de commande Windows pour exécuter votre soumission.
- Que votre soumission nécessite le
-s
drapeau ou non. - (facultatif) Une nouvelle piste résoluble qui sera ajoutée à l’indice de référence. Je vais déterminer un raisonnable
target
pour votre piste manuellement. Lorsque la piste est ajoutée au point de référence, je la modifie dans votre réponse. Je me réserve le droit de vous demander une autre piste (juste au cas où vous ajouteriez une piste disproportionnée, incluez des œuvres ASCII obscènes dans la piste, etc.). Lorsque j'ajoute le scénario de test à l'ensemble de références, je remplace la piste de votre réponse par un lien vers la piste dans le fichier de références afin de réduire l'encombrement de ce message.
Comme vous pouvez le constater, je testerai toutes les soumissions sur un ordinateur Windows 8. S'il n'y a absolument aucun moyen de faire fonctionner votre soumission sous Windows, je peux également essayer sur une machine virtuelle Ubuntu. Cela sera toutefois beaucoup plus lent. Par conséquent, si vous souhaitez respecter le délai imparti, assurez-vous que votre programme fonctionne sous Windows.
Que le meilleur pilote émerge vectoriel!
Mais je veux jouer!
Si vous voulez essayer le jeu vous-même pour en avoir une meilleure idée, il existe cette implémentation . Les règles utilisées ici sont légèrement plus sophistiquées, mais elles sont assez similaires pour être utiles, je pense.
Classement
Dernière mise à jour: 01/09/2014, 21:29 UTC Nombre de
pistes dans le repère: 25
Taille des égalités: 290, 440
- 6.86688 - Kuroi Neko
- 8.73108 - user2357112 - 2e soumission
- 9.86627 - nneonneo
- 10.66109 - user2357112 - 1ère soumission
- 12.49643 - Ray
- 40.0759 - pseudonyme117 (probabiliste)
Résultats détaillés du test . (Les scores pour les soumissions probabilistes ont été déterminés séparément.)
la source
400
, car cela correspond à la façon dont j'ai déterminé tous les autres objectifs (à l'exception du point d'égalité). Je mettrai à jour le post principal une fois que j'aurai réexaminé toutes les autres soumissions.C ++, 5.4 (déterministe, optimal)
Solution de programmation dynamique. Probablement optimal. Très rapide: résout les 20 tests en 0.2s. Devrait être particulièrement rapide sur les machines 64 bits. Suppose que le tableau compte moins de 32 000 places dans chaque direction (ce qui devrait être vrai, espérons-le).
Ce coureur est un peu inhabituel. Il calcule le chemin optimal sur la ligne de départ, puis exécute instantanément le chemin calculé. Il ignore le contrôle du temps et suppose qu'il peut terminer l'étape d'optimisation à temps (ce qui devrait être vrai pour tout matériel raisonnablement moderne). Sur des cartes excessivement grandes, le coureur a une faible chance de se gommer. Si vous pouvez le convaincre de commettre une erreur de segmentation, vous obtenez un point brownie et je le résoudrai pour utiliser une boucle explicite.
Compiler avec
g++ -O3
. Peut nécessiter C ++ 11 (pour<unordered_map>
). Pour exécuter, exécutez simplement l'exécutable compilé (aucun indicateur ni aucune option n'est pris en charge; toutes les entrées sont prises sur stdin).Résultats
Nouveau Testcase
la source
Python 2 , déterministe, optimal
Voici mon coureur. Je ne l'ai pas testé sur le benchmark (je ne savais toujours pas quelle version et quel installateur Ruby installer), mais cela devrait tout résoudre de manière optimale et dans les délais. La commande pour l'exécuter est
python whateveryoucallthefile.py
. Nécessite le-s
drapeau du contrôleur.Après avoir inspecté le pilote de nneonneo (sans le tester, car je n’ai pas non plus de compilateur C ++), j’ai constaté qu’il semblait effectuer une recherche presque exhaustive de l’espace-état, quel que soit le but ou la brièveté. un chemin a déjà été trouvé. J'ai également constaté que les règles de temps impliquent que la création d'une carte avec une solution longue et complexe nécessite une longue limite de temps. Ainsi, ma soumission de carte est assez simple:
Nouveau Testcase
(GitHub ne peut pas afficher la longue ligne. La piste est
*S.......[and so on].....
)Envoi supplémentaire: Python 2, recherche bidirectionnelle
C'est une approche que j'ai écrite il y a environ deux mois, lorsque j'essayais d'optimiser mon premier envoi en largeur. Pour les cas de test qui existaient à l'époque, cela n'apportait pas d'amélioration, donc je ne l'ai pas soumise, mais pour la nouvelle carte de kuroi, elle semble à peine se faufiler sous la limite de mémoire. Je m'attends toujours à ce que le résolveur de kuroi réussisse, mais je m'intéresse à la façon dont il résiste.
la source
n = 400
.) Merci de me prévenir si vous appliquez des optimisations afin que je puisse réexécuter les tests.Python 3: 6.49643 (Optimal, BFS)
Pour l'ancien fichier de référence de 20 cas, il a obtenu un score de 5,35643. La solution de @nneonneo n’est pas optimale car elle a obtenu 5.4. Quelques bugs peut-être.
Cette solution utilise BFS pour rechercher dans le graphique, chaque état de recherche se présente sous la forme (x, y, dx, dy). Ensuite, j'utilise une carte pour cartographier des états à des distances. Dans le pire des cas, sa complexité dans le temps et dans l’espace est O (n ^ 2 m ^ 2). Cela se produira rarement car la vitesse ne sera pas trop élevée ou le coureur se plantera. En fait, il a fallu 3 secondes sur ma machine pour compléter les 22 tests.
# Résultats
la source
O(√n)
ce qui rendrait votre miseO(n³)
en œuvre sur des grilles carrées (identiques aux autres, je suppose). Je vais ajouter un bris d'égalité pour marquer votre soumission par rapport à l'utilisateur 2357112 plus tard aujourd'hui.n=270
, ce qui explique pourquoi vous êtes maintenant en retard sur les deux autres soumissions "optimales". Cela étant dit, votre soumission est également la plus lente des trois. Elle aurait donc été troisième de toute façon, avec un point de départ plus important.RandomRacer, ~ 40.0 (moyenne sur 10 analyses)
Ce n'est pas que ce bot n'a jamais termine une piste, mais certainement beaucoup moins souvent qu'une fois en 10 tentatives. (Je reçois un score non-pire des cas toutes les 20 à 30 simulations ou à peu près.)
Cela consiste principalement à agir comme un cas de base et à démontrer une implémentation possible (Ruby) pour un coureur:
Le courir avec
la source
Random Racer 2.0, ~ 31
Eh bien, cela ne va pas battre le solveur optimal affiché, mais c’est une légère amélioration par rapport à un coureur aléatoire. La principale différence est que ce coureur envisagera uniquement d'aller au hasard là où il n'y a pas de mur, à moins qu'il ne manque d'endroits valides pour se déplacer, et s'il peut se déplacer vers un but qui tourne, ce sera le cas. Il ne bougera pas non plus pour rester au même endroit, à moins qu'il n'y ait pas d'autre mouvement disponible (improbable, mais possible).
Implémenté en Java, compilé avec java8, mais Java 6 devrait convenir. Aucun paramètre de ligne de commande. Il y a un assez bon groupe de hiérarchie, alors je pense que je fais bien Java.
Les résultats (meilleur cas que j'ai vu)
la source
.class
fichier pour une raison quelconque (au lieu du répertoire où se trouve le contrôleur). Cinglez-moi (avec un commentaire) si vous décidez d’ajouter un test, afin que je puisse l’ajouter au point de repère. Votre score était d’environ 33 sur 10 (voir le classement), mais cela pourrait bien changer à chaque nouvelle piste de test ajoutée à la référence.java -cp path/to/class/file VectorRacing