CJam, 139 octets
Eh bien, cela a pris plusieurs heures pour arriver à quelque chose qui semble terminé. Il semble que le temps nécessaire pour optimiser agressivement le code CJam soit plus grand que O (n) qui concerne la taille du code ...
Vous pouvez l' essayer en ligne , mais pour toute entrée pour laquelle le meilleur chemin est d'au moins 6 opérations, vous devriez probablement l' essayer hors ligne avec un interprète plus rapide.
Écrasé:
q_'$-_'^-:T;'^#\'^-'$#W{)2$5Y$5b+{:D[L"_T<W%_N#)_@>N+N#X-Ue>+-"_"W%-U"--2'<t2'>t'++'(')]=~0e>T,e<D3/1$T<N\+W%N#X?:X;}/2$-}g5b{" ^v<>"=}%]W=
Développé et commenté:
q "Read the input";
_'$- "Remove the end marker";
_'^-:T; "Remove the start marker and save the text";
'^# "With only the end marker removed, locate the start marker";
\'^-'$# "With only the start marker removed, locate the end marker";
W "Initialize the path number to -1";
{ "Do...";
) "Increment the path number";
2$ "Initialize the cursor position to that of the start marker";
5Y$5b+ "Convert the path number to base 5, then add a leading 5
(the leading 5 will act to initialize the column memory)";
{:D "For each digit in the path digit string:";
[ "Begin cases:";
L "0: Do nothing";
"_T<W%_N#)_@>N+N#X-Ue>+-"
"REFS: [ 1 ][ 2 ][ 3 ]45
1: [1] Calculate the distance to the end of the previous
line (0 if no such line)
[2] Calculate the length of the previous line (0 if
no such line)
[3] Calculate the distance to move backwards in the
previous line as the maximum of the length of the
previous line minus the column memory and 0
[4] Calculate the total distance to move as the sum
of [1] and [3]
[5] Subtract [4] from the cursor position";
_"W%-U"- "2: Start with a base of the logic of case 1, but with a
few operations adjusted.";
-2'<t2'>t " [1] Calculate the distance to the *start* of the
*next* line (0 if no such line)
[2] Calculate the length of the *next* line (0 if no
such line)
[3] Calculate the distance to move *forwards* in the
*next* line as the *minimum* of the length of the
*next line* and *the column memory*
[4] Calculate the total distance to move as the sum
of [1] and [3]";
'++ " [5] *Add* [4] *to* the cursor position";
'( "3: Decrement the cursor position";
') "4: Increment the cursor position";
]=~ "Execute the case corresponding to the path digit mod 5";
0e>T,e< "Clamp the cursor position to [0, text length]";
D3/ "Check if the path digit is not 0, 1, or 2...";
1$T<N\+W%N# "Calculate the current column";
X?:X; "If the above check succeeded, update the column memory";
}/ "End for each";
2$- "Subtract the end marker position from the cursor position";
}g "... While the above subtraction is nonzero";
5b "Convert the path number to base 5";
{" ^v<>"=}% "Map each digit in the path string to its operation symbol";
]W= "Clean up";
Dans l'ensemble, c'est une solution assez simple. Il "exécute" les chiffres de la représentation en base 5 d'un numéro de chemin qui est incrémenté à chaque itération, en commençant par 0, jusqu'à ce qu'un chemin fonctionne. Les chiffres 1- 4mappent les opérations vers le haut, le bas, la gauche et la droite, et 0ne font rien. La première itération utilisant un chemin de 0capture juste le cas dégénéré. Tous les autres chemins qui contiennent un 0ne sont jamais sélectionnés car ce ne sont que des versions de chemins déjà testés avec des no-op ajoutés.
L'état est modélisé de la manière la plus minimaliste possible: le texte avec les marqueurs de début et de fin supprimés, la position du curseur dans le texte et la «mémoire des colonnes». Les retours à la ligne sont généralement traités comme n'importe quel autre caractère, il n'y a donc pas de concept de ligne et la position du curseur n'est qu'un index. Cela rend les déplacements à gauche et à droite simples, qui sont simplement implémentés comme décrémentation et incrémentation (avec serrage à la taille du texte). Monter et descendre est un peu plus délicat, mais toujours gérable.
La réutilisation du code était une tactique d'optimisation assez vitale. En voici quelques exemples:
- Écrire le code pour monter d'une manière telle qu'il est plus petit de générer le code pour descendre vers le bas à l'exécution que d'écrire son propre code. Cela se fait en copiant le code pour remonter et supprimer / remplacer quelques caractères.
- La mise à jour de la "mémoire de colonne" se fait conditionnellement sur la base du chiffre de chemin divisé par 3 au lieu d'être codé dans la logique de l'opération. Cela permet également l'initialisation de la mémoire de colonne en ajoutant une
5opération fictive au début de la chaîne de chemin d'accès, ce qui se produit également en utilisant la 0logique no-op en raison de l'indexation du tableau circulaire et qu'il n'y a que 5 opérations définies.
Dans l'ensemble, je suis très heureux de la façon dont cela s'est produit. C'est certainement le plus de travail que j'ai mis dans une réponse de golf de code à ce jour (pour quelque chose qui tient dans un tweet!?). Le temps d'exécution est cependant assez épouvantable. CJam n'est pas exactement le langage le plus rapide pour commencer et cet algorithme a une complexité de quelque chose comme O (m * 5 n ) , où m est la taille de l'entrée et n est la taille de la sortie. Heureusement, la vitesse ne compte pas!