Esta pregunta tiene sus altibajos


33

La entrada constará de los siguientes caracteres:

  • ^: Sube uno
  • v: Baja uno
  • o k: sube dos
  • o j: baja dos

Por ejemplo, la siguiente entrada:

^^▲^v▼▲^^v

produciría el siguiente resultado:

        ^
   ^   ^ v
  ▲ v ▲

 ^   ▼
^

Secuencias de escape que mueven el cursor como \e[B no están permitidas. Debe producir la salida utilizando espacios y líneas nuevas.

Aquí hay algunos casos de prueba más.

▲v^v^v^v^v^v^v^v▲

                ▲
▲ ^ ^ ^ ^ ^ ^ ^ 
 v v v v v v v v

^^^^^^^▲▲▲▼▼▼vvvvvv

         ▲

        ▲ ▼

       ▲   ▼

      ^     ▼
     ^       v
    ^         v
   ^           v
  ^             v
 ^               v
^                 v

v^^vv^^vvv^v^v^^^vvvv^^v^^vv

  ^   ^         ^
 ^ v ^ v       ^ v       ^
v   v   v ^ ^ ^   v   ^ ^ v
         v v v     v ^ v   v
                    v

1
¿Se permite el espacio final? Lineas vacias?
xnor

2
¿Qué pasa con los idiomas que no admiten Unicode? ¿Se pueden usar caracteres alternativos?
Pomo de la puerta

1
@xnor Se le permiten espacios finales y / o líneas vacías.
absenta

2
@Pomo de la puerta Permitiré jbajar dos veces y ksubir dos veces también.
absenta

1
@xnor Lo malo: / El comentario es correcto y edité las reglas incorrectamente. Lo arreglará ahora.
Absenta

Respuestas:


9

Pyth, 27 bytes

jCm.<.[*5lzd\ =+Ztx"v ^k"dz

Pruébelo en línea: Demostración o conjunto de pruebas

Yo uso ky en jlugar de y . Hay muchas líneas vacías iniciales y finales. Tienes que buscar un poco para encontrar la imagen. Aquí hay una versión de 34 bytes , que elimina todas las líneas vacías iniciales y finales.

j.sCm.<.[*5lzd\ =+Ztx"v ^k"dz]*lzd

Pruébelo en línea: Demostración o conjunto de pruebas

Explicación:

jCm.<.[*5lzd\ =+Ztx"v ^k"dz  implicit: Z = 0
  m                       z  map each char d from input string z to:
                  x"v ^k"d     find d in the string "v ^k", -1 if not found
                 t             -1, that gives -2 for j, -1 for v, 1 for ^ and 2 for k
              =+Z              add this number to Z
     .[*5lzd\                  append spaces on the left and on the right of d, 
                               creating a 5*len(input_string) long string
   .<           Z              rotate this string to the left by Z chars
jC                           transpose and print on lines

16

Ilegible , 2199 2145 2134 2104 2087 2084 bytes

Soporta tanto k/ jcomo / sintaxis.

En una buena tradición ilegible, aquí está el programa formateado en fuente proporcional, para ofuscar la distinción entre apóstrofes y comillas dobles:

'"" "" ""' "" "" "" "" '"" "" "" "" "" "'" "" "" '"" "" "'" "" "" "' "" '""' "" '""' "" "'" "'" "" "" "" "" "" "" "" "" "" "'" ""' "" '" "'" "" "" ""' "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" '"" ""'"" ""' "" "" '"" "" ""' "" '""' "" '""' "" '"" "" "" "" "'" "" "" " '""' "" '""' "" '"" "'" "" "" "" "" "" "" "" "" "" "" "" '""' "" '" "'" ""' "" "" "" "" '"" "" "" "" "" ""' "" "" "" "" "" "" "" "" """'" "'" "'" "'" "'" "'" "" '"" "" "" ""' "" "" "" "" "" "" "" "'" " '""' "" "'" "" "" "" "'" "" "" "'" "'" "'" "'" "'" "'" "" '""' "" ' "" "'" "" "" "'" "" '"" "" "" ""' "" "" "" "" "" "" "" "" "" "" "'"" "'" "" "" "" "" "" "" "" "'" "" "" "" '"" "" "" "" "" "" "" ""' " "" '"" "" "" "" "" ""' "" "" "" "" "" '"" "" "" "" "" "" "" "" "" "" "" "" '"" "'" "" '""' "" "" "" "" "" "" "" "" "" "" "" "" "" "" "'""' "" '""' "" '""' "" "'" ""' "" '""' "" "'" "" "" "" "" "'" "" "" "" "" '"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" '""' "" '""' "" '"" "" "" "" ""' "" "'" "'" "'" ""' "" '"""'" "" "" "" ""' "" "" "" "" "" '"" ""' "" '""' "" "" "" "" "" "" '" "" '"" "" "'" "" "" "'" "" "" "" "" "" "" "" "" "" "" ""' " "'" "'" "'" "'" "" '"" "" "" "" "" "" "" "" ""' "" "" "" '""' ""'""' "" "'" "" "" "'" "'" "'" "'" ""' "" '"" "" "" "" "" ""' "" '"" "'" ""' "" "" "" '""' "" '"" "'" "'" "" "" "" "" "" "" "" "" "" "" " '""' "" "'" "" "" "" "'" "" "" "'" "'" "" '"" "" "" "" "" "'" "" '"" "" "" "" '"" "" "" "'" "" "" "" "" "" "'" "" "" "" "" ""' "" "" "" '"" "" "" ""' "" "" "" "'" "'" "'" "" "" "" "" "" "" "" "" "" "" "'" "'" "'" "" '"" "" ""' "" '""' "" "'" "" "" "" "" "" "" "" "" "" "'"" "'" "" '"" "" ""' "" '"" "'" "'" "" "" "" "" "" "" "" "" "" "" "" '"" "" "" "'" "" "" "" "'" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " "" "" '"" "" ""' "" '""' "" '"" "'" "'" "" "" "" "" "" "'" "'" ""'"" ""' "" "" "" "" "'" "" "" "" "" ""' "" "" "" "" "" "" "'" "" "" " '""' "" '"" "'" "'" "" "" ""' "" '""' "" "'" "" "" "" "" "" "" "" "" "" "'" "'" "" '""' "" "" "" "" "" "" "'" "" "'" "" "" "" "" "'" "'"" "" "" "'" "" "" "" "" ""' "" "" "" "" "" "" "" "" "" "" "'" "" "" "'" ""' "" "" "" "" '"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" '"" "'" "'" "" "" ""' "" "" "" "" "" '"" "" "" "" "" "" "" "" "'"" '""' "" "'" "" "" "" "" "" "" ""' "" '"" "" "" "" ""' "" "" "" "" "'" "" "" "'" "'" ""' "" '""' "" '""' "" '"" "" "" "" "'" "'" "'" " '""' "" "'" "" "" "" "" "" ""' "" "" "" "" "" "" "" "" "" "" "" """'" "" "" "" "'" "" "" "'" "" "" "" "" ""' "" "" "" "" "" "" "" "" '" "" "" "" '"" "" "" ""' "" "" "" "" "" "" "" "" "" "" "" "" "" "" "'" "" '""' "" '"" "" "" "'" "" "" "" "" "" '"" "" "" "" "" "" "" """'" ""' "" '""' "" '""' "" '""' "" '""' "" '""' "" '""' "" '""' "" '""' "" '""' "" '""' "" '""' "" "" "" "" "" "" "" "" "" "" '"" "" " "" '"" "'" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" """" "" "'" "'" ""

Este fue un desafío increíble. ¡Gracias por tu publicación!

Explicación

Para tener una idea de lo que ilegible puede y no puede hacer, imagine Brainfuck con una cinta infinita en ambas direcciones, pero en lugar de un puntero de memoria moviendo una celda a la vez, puede acceder a cualquier celda de memoria desreferenciando un puntero. Esto resulta bastante útil en esta solución, aunque otras operaciones aritméticas, incluido el módulo, deben realizarse a mano.

Aquí está el programa como pseudocódigo con comentarios del director:

// Initialize memory pointer. Why 5 will be explained at the very end!
ptr = 5

// FIRST PASS:
// Read all characters from stdin, store them in memory, and also keep track of the
// current line number at each character.

// We need the +1 here so that EOF, which is -1, ends the loop. We increment ptr by 2
// because we use two memory cells for each input character: one contains the actual
// character (which we store here); the other will contain the line number at which the
// character occurs (updated at the end of this loop body).
while ch = (*(ptr += 2) = read) + 1:

    // At this point, ch will be one more than the actual value.
    // However, the most code-economical way for the following loop is to
    // decrement inside the while condition. This way we get one fewer
    // iteration than the value of ch. Thus, the +1 comes in handy.

    // We are now going to calculate modulo 4 and 5. Why? Because
    // the mod 4 and 5 values of the desired input characters are:
    //
    //  ch  %5  %4
    //  ^   1
    //  v   2
    //  k   3
    //  j   4
    //  ▲   0   2
    //  ▼   0   0
    //
    // As you can see, %5 allows us to differentiate all of them except ▲/▼,
    // so we use %4 to differentiate between those two.

    mod4 = 0      // read Update 2 to find out why mod5 = 0 is missing
    while --ch:
        mod5 = mod5 ? mod5 + 1 : -4
        mod4 = mod4 ? mod4 + 1 : -3

    // At the end of this loop, the value of mod5 is ch % 5, except that it
    // uses negative numbers: -4 instead of 1, -3 instead of 2, etc. up to 0.
    // Similarly, mod4 is ch % 4 with negative numbers.

    // How many lines do we need to go up or down?
    // We deliberately store a value 1 higher here, which serves two purposes.
    // One, as already stated, while loops are shorter in code if the decrement
    // happens inside the while condition. Secondly, the number 1 ('""") is
    // much shorter than 0 ('""""""""'""").
    up = (mod5 ? mod5+1 ? mod5+3 ? 1 : 3 : 2 : mod4 ? 3 : 1)
    dn = (mod5 ? mod5+2 ? mod5+4 ? 1 : 3 : 2 : mod4 ? 1 : 3)

    // As an aside, here’s the reason I made the modulos negative. The -1 instruction
    // is much longer than the +1 instruction. In the above while loop, we only have
    // two negative numbers (-3 and -4). If they were positive, then the conditions in
    // the above ternaries, such as mod5+3, would have to be mod5-3 etc. instead. There
    // are many more of those, so the code would be longer.

    // Update the line numbers. The variables updated here are:
    // curLine = current line number (initially 0)
    // minLine = smallest linenum so far, relative to curLine (always non-positive)
    // maxLine = highest linenum so far, relative to curLine (always non-negative)
    // This way, we will know the vertical extent of our foray at the end.

    while --up:
        curLine--
        minLine ? minLine++ : no-op
        maxLine++

    while --dn:
        curLine++
        minLine--
        maxLine ? maxLine-- : no-op

    // Store the current line number in memory, but +1 (for a later while loop)
    *(ptr + 1) = curLine + 1

// At the end of this, minLine and maxLine are still relative to curLine.
// The real minimum line number is curLine + minLine.
// The real maximum line number is curLine + maxLine.
// The total number of lines to output is maxLine - minLine.

// Calculate the number of lines (into maxLine) and the real minimum
// line number (into curLine) in a single loop. Note that maxLine is
// now off by 1 because it started at 0 and thus the very line in which
// everything began was never counted.
while (++minLine) - 1:
  curLine--
  maxLine++

// Make all the row numbers in memory positive by adding curLine to all of them.
while (++curLine) - 1:
  ptr2 = ptr + 1
  while (ptr2 -= 2) - 2:    // Why -2? Read until end!
    *ptr2++

// Finally, output line by line. At each line, we go through the memory, output the
// characters whose the line number is 0, and decrement that line number. This way,
// characters “come into view” in each line by passing across the line number 0.
while (--maxLine) + 2:    // +2 because maxLine is off by 1
  ptr3 = 5
  while (ptr -= 2) - 5:
    print (*((ptr3 += 2) + 1) = *(ptr3 + 1) - 1) ? 32 : *ptr3   // 32 = space
  ptr = ptr3 + 2
  print 10  // newline

Esto en cuanto a la lógica del programa. Ahora tenemos que traducir esto a ilegible y usar algunos trucos de golf más interesantes.

Las variables siempre se desreferencian numéricamente en No legible (por ejemplo, se a = 1convierte en algo parecido *(1) = 1). Algunos literales numéricos son más largos que otros; el más corto es 1, seguido de 2, etc. Para mostrar cuánto más largos son los números negativos, aquí están los números de -1 a 7:

-1  '""""""""'""""""""'"""  22
 0  '""""""""'"""           13
 1  '"""                     4
 2  '""'"""                  7
 3  '""'""'"""              10
 4  '""'""'""'"""           13
 5  '""'""'""'""'"""        16
 6  '""'""'""'""'""'"""     19
 7  '""'""'""'""'""'""'"""  22

Claramente, queremos asignar la variable # 1 a la que ocurre con mayor frecuencia en el código. En el primer ciclo while, esto es definitivamente mod5, que aparece 10 veces. Pero no necesitamos mod5más después del primer ciclo while, por lo que podemos reasignar la misma ubicación de memoria a otras variables que usaremos más adelante. Estos son ptr2y ptr3. Ahora se hace referencia a la variable 21 veces en total. (Si está tratando de contar el número de ocurrencias usted mismo, recuerde contar algo comoa++ dos veces, una para obtener el valor y otra para establecerlo).

Solo hay otra variable que podemos reutilizar; después de calcular los valores del módulo, chya no es necesario. upy dnaparece el mismo número de veces, así que cualquiera está bien. Fusionémonos chcon up.

Esto deja un total de 8 variables únicas. Podríamos asignar las variables 0 a 7 y luego iniciar el bloque de memoria (que contiene los caracteres y los números de línea) en 8. ¡Pero! Como 7 tiene la misma longitud en el código que −1, también podríamos usar las variables −1 a 6 e iniciar el bloque de memoria en 7. ¡De esta manera, cada referencia a la posición de inicio del bloque de memoria es ligeramente más corta en el código! Esto nos deja con las siguientes tareas:

-1    dn
 0                      ← ptr or minLine?
 1    mod5, ptr2, ptr3
 2    curLine
 3    maxLine
 4                      ← ptr or minLine?
 5    ch, up
 6    mod4
 7... [data block]

Ahora esto explica la inicialización en la parte superior: es 5 porque es 7 (el comienzo del bloque de memoria) menos 2 (el incremento obligatorio en la primera condición while). Lo mismo ocurre con las otras dos ocurrencias de 5 en el último bucle.

Tenga en cuenta que, dado que 0 y 4 tienen la misma longitud en el código, ptry minLinepodrían asignarse de cualquier manera. ... ¿O podrían?

¿Qué pasa con el misterioso 2 en el penúltimo bucle while? ¿No debería ser este un 6? Solo queremos disminuir los números en el bloque de datos, ¿verdad? Una vez que llegamos a 6, estamos fuera del bloque de datos y debemos detenernos. ¡Sería una vulnerabilidad de seguridad de error de error de desbordamiento de búfer!

Bueno, piensa en lo que pasa si no nos detenemos. Decrementamos las variables 6 y 4. La variable 6 es mod4. Eso solo se usa en el primer ciclo while y ya no es necesario aquí, por lo que no se hace daño. ¿Qué pasa con la variable 4? ¿Qué crees que debería ser ptro debería ser la variable 4 minLine? Así es, ¡ minLineya no se usa en este momento! Por lo tanto, la variable # 4 es minLiney podemos disminuirla de manera segura y no hacer daño.

ACTUALIZACIÓN 1! Golfed desde 2199 a 2145 bytes por darse cuenta de que dnpuede también fusionarse con mod5, a pesar de que mod5todavía se utiliza en el cálculo del valor de dn! La nueva asignación de variables es ahora:

 0    ptr
 1    mod5, dn, ptr2, ptr3
 2    curLine
 3    maxLine
 4    minLine
 5    ch, up
 6    mod4
 7... [data block]

ACTUALIZACIÓN 2! Golfó de 2145 a 2134 bytes al darse cuenta de que, dado mod5que ahora está en la misma variable que dn, que se cuenta a 0 en un ciclo while, mod5ya no necesita inicializarse explícitamente a 0.

ACTUALIZACIÓN 3! Golfó de 2134 a 2104 bytes al darse cuenta de dos cosas. Primero, aunque la idea del "módulo negativo" valió la pena mod5, el mismo razonamiento no se aplica mod4porque nunca probamos, mod4+2etc. Por lo tanto, cambiar mod4 ? mod4+1 : -3a mod4 ? mod4-1 : 3nos lleva a 2110 bytes. En segundo lugar, dado mod4que siempre es 0 o 2, podemos inicializar mod4a 2 en lugar de 0 e invertir los dos ternarios (en mod4 ? 3 : 1lugar de mod4 ? 1 : 3).

ACTUALIZACIÓN 4! Jugó desde 2104 hasta 2087 bytes al darse cuenta de que el ciclo while que calcula los valores del módulo siempre se ejecuta al menos una vez, y en tal caso, Ilegible le permite reutilizar el valor de la última declaración en otra expresión. Por lo tanto, en lugar de while --ch: [...]; up = (mod5 ? mod5+1 ? [...]ahora tenemos up = ((while --ch: [...]) ? mod5+1 ? [...](y dentro de ese ciclo while, calculamos mod4primero, así que esa mod5es la última declaración).

ACTUALIZACIÓN 5! Golfé de 2087 a 2084 bytes al darme cuenta de que en lugar de escribir las constantes 32y 10(espacio y nueva línea), puedo almacenar el número 10 en la variable (ahora no utilizada) # 2 (llamémosla ten). En lugar de ptr3 = 5escribir ten = (ptr3 = 5) + 5, luego se 32vuelve ten+22y se print 10vuelve print ten.


Esto es ... horrible ... +1
kirbyfan64sos

6

CJam, 37 bytes

r_,2*:L3*S*f{\_iImd8-g\8>)*L+:L\t}zN*

Esto imprime líneas vacías antes y después de la salida deseada, que ha sido permitida por el OP .

Pruébelo en línea en el intérprete de CJam .

Cómo funciona

r_     e# Read a token from STDIN and push a copy.
,2*:L  e# Compute its length, double it and save it in L.
3*S*   e# Push a string of 6L spaces.
f{     e# For each character C in the input, push C and the string of spaces; then
  \    e#   Swap C with the string of spaces.
  _i   e#   Push a copy of C and cast it to integer.
  Imd  e#   Push quotient and remainder of its division by 18.
  8-g  e#   Push the sign((C%18) - 8). Gives -1 for ^ and ▲, 1 for v and ▼.
  \    e#   Swap the result with the quotient.
  8>)  e#   Push ((C/18) > 1) + 1. Gives 2 for ▲ and ▼, 1 for ^ and v.
  *    e#   Multiply both results. This pushes the correct step value.
  L+:L e#   Add the product to L, updating L.
  \t   e#   Replace the space at index L with C.
}      e# We've built the columns of the output.
z      e# Zip; transpose rows with columns.
N*     e# Join the rows, separating by linefeeds.

Creo que sería justo afirmar explícitamente como una advertencia que su solución produce grandes cantidades de nuevas líneas adicionales antes y después del resultado deseado ...
Timwi

Adicional. (No pensé que fuera necesario ya que el OP permitió explícitamente líneas vacías).
Dennis

3

Pitón 2, 102

s=input()
j=3*len(s)
exec"w='';i=j=j-1\nfor c in s:i-='kv_^j'.find(c)-2;w+=i and' 'or c\nprint w;"*2*j

Imprime línea por línea.

Recorre los caracteres en la entrada y rastrea la altura actual. La altura se actualiza por uno de los +2, +1, -1, -2calculados por 'kv_^j'.find(c)-2. Probablemente hay una cadena mod que es más corta

Cuando la altura actual es igual al número de línea (que puede ser negativo), agregamos el carácter actual a la línea y, de lo contrario, agregamos un espacio. Luego, imprimimos la línea. En realidad, es más corto comenzar la altura en el número de línea actual y restar los cambios de altura, agregando el carácter cuando llega el valor 0.

Los números de línea abarcan un rango lo suficientemente grande como para que una secuencia de dos arriba o dos abajo permanezca dentro de él. En realidad, hay una buena cantidad de exceso. Si tuviéramos un límite superior en la longitud de entrada, sería más corto escribir, digamos j=999.

Sorprendentemente, i and' 'or cfue más corto de lo habitual [' ',c][i==0]. Tenga en cuenta que ipuede ser negativo, lo que elimina algunos trucos habituales.


2

MATLAB, 116

function o=u(a)
x=0;y=1;o='';for c=a b=find(c=='j^ vk')-3;y=y+b;if y<1 o=[zeros(1-y,x);o];y=1;end
x=x+1;o(y,x)=c;end

Es un comienzo. El jy khacer que sea un dolor en el cuello ya que no puedo encontrar una manera de mapear matemáticamente desde y j^vkhacia [-2 -1 1 2]MATLAB sin reconocer el Unicode (aparentemente, tanto arriba como abajo tienen un valor de 26 en MATLAB. ¡Vaya!), Hay muchos bytes desperdiciados haciendo el mapeo.

Al inspirarse en la solución @xnors, el código se puede reducir en otros 14 caracteres mapeando el carácter de control dentro del bucle for.

También se desperdician muchos bytes tratando de explicar si la cadena de entrada envía el patrón nuevamente debajo del índice en el que comenzó (tal vez si hubiera un límite en la longitud de la cadena podría simplificar ese bit).

Y en su forma legible:

function o=u(a)
%We start in the top left corner.
x=0; %Although the x coordinate is 1 less than it should be as we add one before storing the character
y=1;
o=''; %Start with a blank array
for c=a
    %Map the current character to [-2 -1 1 2] for 'j^vk' respectively.
    b=find(c=='j^ vk')-3;
    y=y+b; %Offset y by our character
    if y<1 %If it goes out of range of the array
        o=[zeros(1-y,x); o]; %Add enough extra lines to the array. This is a bit of a hack as 0 prints as a space in MATLAB.
        y=1; %Reset the y index as we have now rearranged the array
    end
    x=x+1; %Move to the next x coordinate (this is why we start at x=0
    o(y,x)=c; %Store the control character in the x'th position at the correct height.
end

Funcionaria b=[-2 -1 1 2](a==[106 107 94 118])? Funciona en octava. ¡O incluso b=[-2 -1 1 2](a-94==[12 13 0 24])si quieres afeitarte un byte más!
wchargin

@WChargin no funciona en MATLAB. Lamentablemente, el comportamiento de las ==paradas deja de funcionar, y también en MATLAB no se puede poner un ()después de un [].
Tom Carpenter

Hmm ... ¡podrías cambiar el idioma a Octave! :) (Octave también tiene +=, fwiw.)
wchargin

@WChargin Eso es trampa = P Pero estoy de acuerdo, Octave tiene muchos atajos que Matlab no tiene.
flawr

2

JavaScript (ES6), 140

Pruebe a ejecutar el fragmento a continuación en un navegador compatible con EcmaScript 6 (probado en Firefox).

f=s=>[...s].map(c=>{for(t=r[y+=c>'▲'?2:c>'v'?-2:c>'^'?1:-1]||x;y<0;y++)r=[,...r];r[y]=t+x.slice(t.length)+c,x+=' '},y=0,r=[x=''])&&r.join`
`

// Less golfed

f=s=>(
  y=0,
  x='',
  r=[],
  [...s].forEach( c =>
    {
      y += c > '▲' ? 2 : c > 'v' ? -2 : c > '^' ? 1 : -1;
      t = r[y] || x;
      while (y < 0)
      {
        y++;
        r = [,...r]
      }  
      r[y] = t + x.slice(t.length) + c;
      x += ' '
    }
  ),
  r.join`\n`
)  


//Test

;[
  '^^▲^v▼▲^^v'
, '▲v^v^v^v^v^v^v^v▲'
, '^^^^^^^▲▲▲▼▼▼vvvvvv'
, 'v^^vv^^vvv^v^v^^^vvvv^^v^^vv'  
].forEach(t=>document.write(`${t}<pre>${f(t)}</pre>`))
pre { border:1px solid #777 }


1

GS2, 34 bytes

Este calcula correctamente los límites de salida para que no se produzca un exceso de espacio en blanco. Aquí está mi solución en hexadecimal

5e 20 76 6a 05 3e 26 ea 30 e0 6d 40 28 26 cf d3
31 e9 d0 4d 42 5e e2 b1 40 2e e8 29 cf d3 5c e9
9a 54

Una pequeña explicación está en orden. En la pila tenemos la entrada del usuario como una matriz de códigos ASCII. El programa comienza en una cadena literal debido a 05. Aquí vamos.

  5e 20 76 6a      # ascii for "^ vj"
  05               # finish string literal and push to stack
  3e               # index - find index in array or -1 if not found
  26               # decrement
ea                 # map array using block of 3 instructions (indented)

  30               # add 
e0                 # create a block of 1 instruction
6d                 # scan (create running total array of array using block)
40                 # duplicate top of stack
28                 # get minimum of array
26                 # decrement
cf                 # pop from stack into register D (this is the "highest" the path goes)

  d3               # push onto stack from register D
  31               # subtract
e9                 # map array using block of 2 instructions

d0                 # push onto stack from register A (unitialized, so it contains stdin)

  4d               # itemize - make singleton array (also is single char string)
  42               # swap top two elements in stack
  5e               # rjust - right justify string
e2                 # make block from 3 instructions
b1                 # zipwith - evaluate block using parallel inputs from two arrays
40                 # duplicate top of stack

  2e               # get length of array/string
e8                 # map array using block of 1 instruction
29                 # get maximum of array
cf                 # pop from stack into register D (this is the "lowest" the path goes)

  d3               # push from register D onto stack
  5c               # ljust - left justify string
e9                 # map array using block of two instructions
9a                 # transpose array of arrays
54                 # show-lines - add a newline to end of each element in array

GS2, 24 bytes

También tengo una solución de 24 bytes que no tiene mucho cuidado al calcular el tamaño de salida, y termina con espacios en blanco adicionales. Sin embargo, prefiero el que tiene el espacio en blanco al mínimo.

5e 20 76 6a 05 3e 26 ea 30 e0 6d d0 08 4d 42 d1
30 5e d1 5c 09 b1 9a 54

1

Crayón , 13 bytes (no competidor)

O"^ vj"\CynIq

Pruébalo en línea!Utiliza las flechas reales porque por qué no.

No compite porque Crayon es mucho más nuevo que este desafío.

Cómo funciona

Crayon es un lenguaje basado en pila diseñado para ser asesino en los desafíos de arte ASCII. Se basa en la base de un "lienzo" de salida bidimensional y un "crayón", un cursor que recorre este lienzo. Todo lo que se envía a la salida se dibuja en el lienzo en la posición del crayón y en la dirección en la que se encuentra el crayón. Por defecto, el crayón apunta al Este (a la derecha).

O"^ v▼"\CynIq   Implicit: input string is on top of the stack
O               For each char I in the input string:
 "^ v▼"          Push this string.
       \         Swap the top two items (so I is on top).
        C        Take the index of I in the string.
                 This returns 3 for ▼, 2 for v, 0 for ^, and -1 for ▲.
         y       Move the crayon by this number of spaces on the Y-axis (south).
          n      Move the crayon one position north.
                 The crayon has now been translated 2 positions south for ▼,
                 1 south for v, 1 north for ^, and 2 north for ▲.
           Iq    Draw I at the crayon. This automatically moves the crayon forward
                 by the length of I, which is 1 in this case.

0

pb - 136 bytes

^w[B!0]{>}v[3*X]<[X]<b[1]^[Y]^>w[B!0]{t[B]<vw[B=0]{v}>w[T=107]{^^b[T]t[0]}w[T=94]{^b[T]t[0]}w[T=118]{vb[T]t[0]}w[T!0]{vvb[T]t[0]}^[Y]^>}

Usos ky en jlugar de y .

Un par de notas:

  • Escape sequences that move the cursor such as \e[B are not allowed. You must produce the output using spaces and newlines.¡Sigo esta regla! pb utiliza el concepto de "pincel" para generar caracteres. El pincel se mueve alrededor del "lienzo" y puede imprimir un personaje inmediatamente debajo de él. Sin embargo, la implementación real imprime el personaje usando espacios y líneas nuevas.
  • No iba a molestarme con este desafío a pesar de que pensé que sería divertido con pb hasta que vi la decisión que dice eso You are allowed trailing spaces and/or empty lines. Esto es por un par de razones:
    • PB no puede no haber espacios finales. Siempre produce una salida rectangular, rellenando con espacios si es necesario.
    • Este programa produce muchas líneas vacías. No sabe qué tan alta será la salida cuando comience a producirla, por lo que para una entrada de longitud ncomienza en Y=3n+1. El -1es porque está bajando 3ndeY=-1 , y a partir de Y=2n-1falla por una entrada de todos k.

¡Puedes ver este programa en acción en YouTube! Esta versión está ligeramente modificada ya que solo se reduce a n-1. Funciona para esta entrada, pero fallará para otros. Sin embargo, captura mucho mejor.

Con comentarios:

^w[B!0]{>}             # Go to the end of the input
v[3*X]                 # Go down 3 times the current X value
<[X]<                  # Go to X=-1 (off screen, won't be printed)
b[1]                   # Leave a non-zero value to find later
^[Y]^>                 # Back to the beginning of the input
w[B!0]{                # For every byte of input:
    t[B]                 # Copy it to T
    <vw[B=0]{v}>         # Go 1 to the right of the character to the left
                         # (either the last one printed or the value at X=-1)
                         # Move the correct amount for each character and print it:
    w[T=107]{^^b[T]t[0]} # k
    w[T=94]{^b[T]t[0]}   # ^
    w[T=118]{vb[T]t[0]}  # v
    w[T!0]{vvb[T]t[0]}   # j (Every other possibility sets T to 0, so if T is not 0
                         #    it must be j. T!0 is shorter than T=106)
    ^[Y]^>               # To the next byte of input to restart the loop
}

0

Ceilán, 447 bytes

import ceylon.language{o=null,v=variable,s=shared}s void y(){v L c;v L f;v L l;v Integer i=0;class L(v L?p,v L?n){s v String t="";s L u=>p else(f=p=L(o,this));s L d=>n else(l=n=L(this,o));s void a(Character c)=>t=t+" ".repeat(i-t.size)+c.string;}f=l=c=L(o,o);for(x in process.readLine()else""){switch(x)case('^'){c=c.u;}case('v'){c=c.d;}case('▲'|'k'){c=c.u.u;}case('▼'|'j'){c=c.d.d;}else{}c.a(x);i++;}print(f.t);while(f!=l){f=f.d;print(f.t);}}

O con saltos de línea para "legibilidad": import ceylon.language{o=null,v=variable,s=shared}s void y(){v L c;v L f;v L l;v Integer i=0;class L(v L?p,v L?n){s v String t="";s L u=>p else(f=p=L(o,this));s L d=>n else(l=n=L(this,o));s void a(Character c)=>t=t+" ".repeat(i-t.size)+c.string;}f=l=c=L(o,o);for(x in process.readLine()else""){switch(x)case('^'){c=c.u;}case('v'){c=c.d;}case('▲'|'k'){c=c.u.u;}case('▼'|'j'){c=c.d.d;}else{}c.a(x);i++;}print(f.t);while(f!=l){f=f.d;print(f.t);}}

Esto funciona tanto con la entrada ▲ / ▼ como con la entrada j / k (si tuviéramos que admitir solo uno de ellos, el programa sería 8 bytes más corto). La última línea de salida está vacía cuando la posición de inicio estaba en ella (es decir, la primera entrada fue una o ^y nunca volvimos a estar debajo de eso más tarde). La entrada que no sea uno de los caracteres especificados simplemente se imprimirá tal cual, sin cambiar la línea:

v^^vv^^vvv^v^v^^^Hellovvvv^^v^^vv

  ^   ^         ^Hello
 ^ v ^ v       ^      v       ^
v   v   v ^ ^ ^        v   ^ ^ v
         v v v          v ^ v   v
                         v

Aquí hay una versión formateada (753 bytes):

shared void y() {
    variable L c;
    variable L f;
    variable L l;
    variable Integer i = 0;
    class L(variable L? p, variable L? n) {
        shared variable String t = "";
        shared L u => p else (f = p = L(null, this));
        shared L d => n else (l = n = L(this, null));
        shared void a(Character c) => t = t + " ".repeat(i - t.size) + c.string;
    }
    f = l = c = L(null, null);
    for (x in process.readLine() else "") {
        switch (x)
        case ('^') { c = c.u; }
        case ('v') { c = c.d; }
        case ('▲' | 'k') { c = c.u.u; }
        case ('▼' | 'j') { c = c.d.d; }
        else {}
        c.a(x);
        i++;
    }
    print(f.t);
    while (f != l) {
        f = f.d;
        print(f.t);
    }
}

Este es un programa "orientado a objetos" casi directo ... la clase (local) L(buffer de línea) almacena una línea de texto (in t), así como punteros (anulables) al siguiente ( n) y al anterior ( p) línea. Los atributos (no anulables) u(para arriba) y d(para abajo) inicializan aquellos si es necesario (con un puntero inverso a sí mismo), y en este caso también hacen un seguimiento de la primera y última línea en general (en el fyl variables ).

El amétodo (append) agrega un carácter a esta línea, incluidos algunos espacios eventualmente necesarios.

cEs la línea actual. Analizamos la cadena de entrada (usando readLinecomo la entrada debe estar en una línea) usando una instrucción switch que actualiza la línea actual y luego llama al método append.

Después de realizar el análisis, iteramos sobre las líneas desde la primera hasta la última, imprimiendo cada una de ellas. (Esto destruye el fpuntero, si fuera necesario después, deberíamos haber usado una variable separada para esto).

Algunos trucos usados ​​para jugar al golf:

  • Algunas cosas que en otros idiomas serían palabras clave en realidad son solo identificadores en el ceylon.languagepaquete, y se pueden renombrar con un alias de importación. Usamos esto para las anotaciones shared(usado 5 ×) y variable(usado 6 ×), así como para el objeto null(usado 4 ×):

    import ceylon.language{o=null,v=variable,s=shared}
    

    (Trivia: The Formatter en el IDE de Ceilán formatea algunas anotaciones de lenguaje incorporadas, entre ellas variabley shared, al colocarlas en la misma línea que la declaración anotada, contrasta con las anotaciones personalizadas, que se colocan en una línea separada encima de la declaración. Esto hace que la versión formateada del programa de golf sea ilegible, por lo tanto, cambié las alias-importaciones para esta versión).

    this, void, case, elseSon palabras clave reales y no se puede renombrar esta manera, y Integer, Stringy Characteraparece sólo una vez cada uno, por lo que no hay nada que ganar mediante la importación.

  • Originalmente también tenía una clase ScreenBuffer separada (que hacía un seguimiento de la lista vinculada de buffers de línea, el índice actual, etc.), pero como solo había un objeto, se optimizó.

  • Esa clase Screenbuffer también tenía upy downmétodos, que fueron llamados desde el analizador (y lo hicieron currentLine = currentLine.uprespectivamente currentLine = currentLine.down). Demostró que hacer esto directamente en el interruptor del analizador es más corto. También permitió escribir currentLine = currentLine.up.up(que luego se convirtió c = c.u.u) en lugar de currentLine = currentLine.up;currentLine = currentLine.up.

  • Originalmente pasamos el índice actual como argumento al método append (e incluso al analizador desde el bucle); tener una variable en la función que contiene es más corto.

  • Originalmente, mi método printAll usaba el puntero actual y lo movía primero hacia arriba hasta que la línea actual estaba vacía, y luego hacia abajo mientras imprimía cada línea. Esto se rompió al usar ▲ y ▼ para saltar sobre las líneas, por lo que tuvimos que agregar explícitamente algo en esas líneas saltadas. Hacer un seguimiento de la primera / última línea resultó más fácil (aunque hizo necesario usar dos declaraciones de impresión, porque no hay un ciclo do-while en Ceilán).

  • Originalmente tenía algo como esto:

      String? input = process.readLine();
      if(exists input) {
         for(x in input) {
             ...
         }
      }
    

    process.readLinedevuelve nullsi no hay una línea que pueda leerse (porque la entrada se ha cerrado), y el compilador de Ceilán me exige que verifique eso antes de acceder input. Como en este caso no quiero hacer nada, puedo usar elelse operador que devuelve su primer argumento si no es nulo, y de lo contrario su segundo argumento, guardando la variable y la instrucción if. (Esto también nos permitiría codificar una entrada por defecto para la prueba: for (x in process.readLine() else "^^▲^v▼▲^^v") {)


0

JavaScript (ES6), 228 bytes

E=(r,p=(' '[M='repeat'](Z=r.length)+',')[M](Z*4),i=Z*2,k=0)=>Z>k?E(r,(p.split(',').map((o,q)=>q==i?o.slice(0,k)+r[k]+o.slice(k++):o)).join`,`,i+(H={'^':-1,k:-2,j:2,v:1})[r[k]],k):p.split(',').join`
`.replace(/\s+\n$|^\s+\n/g,'')

Bueno, aquí hay una solución recursiva (bastante larga) que pasa todos los casos de prueba dados. Fue un lindo desafío. Esto usa kyj en lugar de y .

Fragmento de prueba

Aunque el envío en sí solo puede manejar k,j, el siguiente fragmento puede manejar ambos k,jy ▼,▲.

E=(r,p=(' '[M='repeat'](Z=r.length)+',')[M](Z*4),i=Z*2,k=0)=>Z>k?E(r,(p.split(',').map((o,q)=>q==i?o.slice(0,k)+r[k]+o.slice(k++):o)).join`,`,i+(H={'^':-1,k:-2,j:2,v:1})[r[k]],k):p.split(',').join`
`.replace(/\s+\n$|^\s+\n/g,'')
Input: <input type="text" oninput=o.textContent=E(this.value.replace(/▲/g,'k').replace(//g,'j'))></input>
<pre id='o'></pre>

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.