Esta questão tem seus altos e baixos

33

A entrada consistirá nos seguintes caracteres:

  • ^: Suba um
  • v: Desça um
  • ou k: sobe dois
  • ou j: desça duas

Por exemplo, a seguinte entrada:

^^▲^v▼▲^^v

produziria a seguinte saída:

        ^
   ^   ^ v
  ▲ v ▲

 ^   ▼
^

Sequências de escape que movem o cursor como \e[Bnão são permitidas. Você deve produzir a saída usando espaços e novas linhas.

Aqui estão mais alguns casos de teste.

▲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
absinto
fonte
1
O espaço à direita é permitido? Linhas vazias?
Xnor
2
E os idiomas que não suportam Unicode? Caracteres alternativos podem ser usados?
Maçaneta
1
@xnor Você tem espaços à direita e / ou linhas vazias.
absinto
2
@ Doorknob Vou permitir jdescer duas vezes e ksubir duas vezes também.
absinto
1
@xnor Meu problema: / O comentário está correto e eu editei as regras de forma errada. Vai consertar agora.
absinto

Respostas:

9

Pitão, 27 bytes

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

Experimente on-line: Demonstration or Test Suite

Eu uso ke em jvez de e . Existem muitas linhas vazias iniciais e finais. Você precisa procurar um pouco para encontrar a imagem. Aqui está uma versão de 34 bytes , que remove todas as linhas vazias iniciais e finais.

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

Experimente on-line: Demonstration or Test Suite

Explicação:

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
Jakube
fonte
16

Ilegível , 2199 2145 2134 2104 2087 2084 bytes

Suporta tanto k/ jcomo também / sintaxe.

Em boa tradição ilegível, eis o programa formatado em fonte proporcional, para ofuscar a distinção entre apóstrofos e aspas duplas:

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

Este foi um desafio incrível. Obrigado por postar!

Explicação

Para ter uma idéia do que o ilegível pode ou não fazer, imagine Brainfuck com uma fita infinita nas duas direções, mas, em vez de um ponteiro de memória mover uma célula de cada vez, você pode acessar qualquer célula de memória desmarcando um ponteiro. Isso é bastante útil nessa solução, embora outras operações aritméticas - incluindo o módulo - tenham que ser feitas manualmente.

Aqui está o programa como pseudocódigo com o comentário do diretor:

// 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

Tanta coisa para a lógica do programa. Agora precisamos traduzir isso para Ilegível e usar mais alguns truques de golfe interessantes.

As variáveis ​​são sempre desreferenciadas numericamente em Ilegível (por exemplo, a = 1torna-se algo parecido *(1) = 1). Alguns literais numéricos são mais longos que outros; o menor é 1, seguido por 2, etc. Para mostrar o número de números negativos mais longos, aqui estão os 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 alocar a variável nº 1 à que ocorre com mais frequência no código. No primeiro loop while, esse é definitivamente o mod5que ocorre 10 vezes. Mas não precisamos mod5mais depois do primeiro loop while, para que possamos realocar o mesmo local de memória para outras variáveis ​​que usamos mais tarde. Estes são ptr2e ptr3. Agora a variável é referenciada 21 vezes no total. (Se você estiver tentando contar o número de ocorrências, lembre-se de contar algo como a++duas vezes, uma para obter o valor e outra para defini-lo.)

Há apenas uma outra variável que podemos reutilizar; depois que calculamos os valores do módulo, chnão é mais necessário. upe dnsuba o mesmo número de vezes, então qualquer um está bem. Vamos mesclar chcom up.

Isso deixa um total de 8 variáveis ​​únicas. Poderíamos alocar variáveis ​​de 0 a 7 e iniciar o bloco de memória (contendo os caracteres e os números de linha) em 8. Mas! Como 7 tem o mesmo comprimento de código que -1, também poderíamos usar as variáveis ​​-1 a 6 e iniciar o bloco de memória em 7. Dessa forma, toda referência à posição inicial do bloco de memória é um pouco mais curta em código! Isso nos deixa com as seguintes atribuições:

-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]

Agora, isso explica a inicialização no topo: é 5 porque é 7 (o início do bloco de memória) menos 2 (o incremento obrigatório na primeira condição while). O mesmo vale para as outras duas ocorrências de 5 no último loop.

Observe que, como 0 e 4 têm o mesmo comprimento no código, ptre minLinepodem ser alocados de qualquer maneira. ... Ou poderiam?

E os misteriosos 2 no penúltimo loop while? Isso não deveria ser um 6? Queremos apenas diminuir os números no bloco de dados, certo? Quando chegamos a 6, estamos fora do bloco de dados e devemos parar! Seria uma vulnerabilidade de segurança de falha de erro de bug de estouro de buffer!

Bem, pense no que acontece se não pararmos. Nós decrementamos as variáveis ​​6 e 4. A variável 6 é mod4. Isso é usado apenas no primeiro loop while e não é mais necessário aqui, para não causar danos. E a variável 4? O que você acha que deveria ser a variável 4ptr ou deveria ser minLine? Isso mesmo, minLinetambém não é mais usado neste momento! Assim, a variável nº 4 é minLinee podemos diminuí-la com segurança e não causar danos!

ATUALIZAÇÃO 1! Jogou golfe de 2199 a 2145 bytes ao perceber que tambémdn pode ser mesclado , embora ainda seja usado no cálculo do valor paramod5mod5dn ! A nova atribuição de variável agora é:

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

ATUALIZAÇÃO 2! Golfou de 2145 a 2134 bytes ao perceber que, desdemod5 agora está na mesma variável que dn, que é contada como 0 em um loop while, mod5não precisa mais ser explicitamente inicializada como 0.

ATUALIZAÇÃO 3! Jogou de 2134 a 2104 bytes ao realizar duas coisas. Primeiro, embora valha a pena a idéia do “módulo negativo” mod5, o mesmo raciocínio não se aplica a mod4porque nunca testamos contra mod4+2etc. Portanto, mudar mod4 ? mod4+1 : -3para mod4 ? mod4-1 : 3nos leva a 2110 bytes. Segundo, como mod4sempre é 0 ou 2, podemos inicializar mod4para 2 em vez de 0 e reverter os dois ternários (em mod4 ? 3 : 1vez de mod4 ? 1 : 3).

ATUALIZAÇÃO 4! Jogou de 2104 a 2087 bytes ao perceber que o loop while que calcula os valores do módulo sempre é executado pelo menos uma vez e, nesse caso, Ilegível permite reutilizar o valor da última instrução em outra expressão. Assim, em vez de while --ch: [...]; up = (mod5 ? mod5+1 ? [...]agora termosup = ((while --ch: [...]) ? mod5+1 ? [...] (e dentro desse loop while, calculamos mod4primeiro, de modo que essa mod5é a última declaração).

ATUALIZAÇÃO 5! Joguei de 2087 a 2084 bytes ao perceber que, em vez de escrever as constantes 32e 10(espaço e nova linha), posso armazenar o número 10 na variável # 2 (agora não utilizada) (vamos chamá-lo ten). Em vez de ptr3 = 5escrever ten = (ptr3 = 5) + 5, 32torna - se ten+22e print 10torna - se print ten.

Timwi
fonte
Isso é ... horrível ... +1 #
kirbyfan64sos #
6

CJam, 37 bytes

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

Isso imprime linhas vazias antes e depois da saída desejada, que foi permitida pelo OP .

Experimente online no intérprete CJam .

Como 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.
Dennis
fonte
Eu acho que seria justo declarar explicitamente como uma ressalva que sua solução produz grandes quantidades de novas linhas extras antes e depois da saída desejada ...
Timwi
Adicionado. (I não pensar que era necessário uma vez que a OP permitido explicitamente linhas vazias.)
Dennis
3

Python 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 linha por linha.

Faz um loop através de caracteres na entrada e rastreia a altura atual. A altura é atualizada por um dos +2, +1, -1, -2calculado por'kv_^j'.find(c)-2 . Provavelmente existe uma cadeia de mods mais curta

Quando a altura atual é igual ao número da linha (que pode ser negativa), acrescentamos o caractere atual à linha e, de outra forma, acrescentamos um espaço. Então, imprimimos a linha. Na verdade, é mais curto iniciar a altura no número da linha atual e subtrair as alterações de altura, acrescentando o caractere quando o valor atingir0 .

Os números das linhas abrangem um intervalo grande o suficiente para que uma sequência de dois ou dois pares permaneça nela. Na verdade, há uma boa quantidade de excesso. Se tivéssemos um limite superior no comprimento da entrada, seria mais curto escrever, digamosj=999 .

Surpreendentemente, i and' 'or cfoi mais curto que o habitual [' ',c][i==0]. Observe que ipode ser negativo, o que elimina alguns truques comuns.

xnor
fonte
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

É um começo. O je ktorná-lo uma dor no pescoço, como eu não consigo encontrar uma maneira de mapear matematicamente de j^vkpara[-2 -1 1 2] e com o MATLAB não reconhecendo o Unicode (aparentemente, tanto para cima quanto para baixo têm um valor de 26 no MATLAB. Vamos entender!), Existem muitos bytes desperdiçados no mapeamento.

Inspirando-se na solução @xnors, o código pode ser reduzido em outros 14 caracteres mapeando o caractere de controle dentro do loop for.

Também há muitos bytes desperdiçados tentando explicar se a string de entrada envia o padrão de volta abaixo do índice em que foi iniciada (talvez se houvesse um limite no comprimento da string, eu poderia simplificar esse bit).

E em sua forma legível:

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
Tom Carpenter
fonte
Funcionaria b=[-2 -1 1 2](a==[106 107 94 118])? Funciona em oitava. Ou mesmo b=[-2 -1 1 2](a-94==[12 13 0 24])se você quiser economizar mais um byte!
wchargin
O @WChargin não funciona no MATLAB. Infelizmente, o comportamento das ==paradas que funcionam, e também no MATLAB, você não pode colocar um ()após a [].
26615 Tom Carpenter
Hmm ... você pode mudar o idioma para Octave! :) (Oitava também tem +=, fwiw.)
wchargin
@WChargin Isso é trapaça = P Mas eu concordo, o Octave possui muitos atalhos que o Matlab não possui.
flawr
2

JavaScript (ES6), 140

Teste a execução do snippet abaixo em um navegador compatível com EcmaScript 6 (testado no 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 }

edc65
fonte
1

GS2, 34 bytes

Este calcula corretamente os limites de saída para que nenhum espaço em branco em excesso seja produzido. Aqui está a minha solução em 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

Uma pequena explicação está em ordem. Na pilha, temos a entrada do usuário como uma matriz de códigos ASCII. O programa inicia em uma string literal por causa do 05. Aqui vamos nós.

  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

Também tenho uma solução de 24 bytes que não toma muito cuidado ao calcular o tamanho da saída e acaba com espaço em branco extra. Eu prefiro aquele com o espaço em branco reduzido ao 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
recursivo
fonte
1

Lápis de cera , 13 bytes (não competitivo)

O"^ vj"\CynIq

Experimente online! Usa as setas reais porque porque não.

Não competir porque o Crayon é muito mais novo que esse desafio.

Como funciona

O Crayon é uma linguagem baseada em pilha projetada para ser uma ameaça nos desafios da arte ASCII. Ele é construído em torno da base de uma "tela" de saída bidimensional e de um "giz de cera", um cursor que viaja por essa tela. Tudo o que é enviado para a saída é desenhado na tela na posição do giz de cera e na direção em que o giz de cera está voltado. Por padrão, o giz de cera aponta para o leste (à direita).

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.
ETHproductions
fonte
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]^>}

Usa ke em jvez de e .

Algumas notas:

  • Escape sequences that move the cursor such as \e[B are not allowed. You must produce the output using spaces and newlines.Eu sigo esta regra! O pb usa o conceito de "pincel" para gerar caracteres. O pincel se move pela tela e pode imprimir um caractere imediatamente abaixo dela. No entanto, a implementação real imprime o caractere usando espaços e novas linhas.
  • Eu não iria me incomodar com esse desafio, mesmo pensando que seria divertido com o pb até ver a decisão You are allowed trailing spaces and/or empty lines. Isso ocorre por alguns motivos:
    • pb não pode não ter espaços à direita. Sempre produz saída retangular, preenchendo espaços, se necessário.
    • Este programa produz muitas linhas vazias. Ele não sabe qual será a altura da saída quando começar a produzi-la, portanto, para uma entrada de comprimento, nela começa em Y=3n+1. O -1é porque ele está indo para baixo 3na partir de Y=-1, e a partir de Y=2n-1falhar por uma entrada de todos k.

Você pode assistir a este programa em ação no YouTube! Esta versão é ligeiramente modificada na medida em que apenas desce para n-1. Funciona para essa entrada, mas falhará para outras pessoas. No entanto, captura muito melhor.

Com comentários:

^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
}
undergroundmonorail
fonte
0

Ceilão, 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);}}

Ou com quebras de linha para "legibilidade": 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);}}

Isso funciona com as entradas ▲ / ▼ e j / k (se tivéssemos que suportar apenas uma delas, o programa seria 8 bytes mais curto). A última linha de saída está vazia quando a posição inicial estava nela (ou seja, a primeira entrada era a ou ^e nunca mais chegamos a isso mais tarde). A entrada que não é um dos caracteres especificados será simplesmente impressa como está, sem mudar a linha:

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

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

Aqui está uma versão formatada (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 é um programa "orientado a objetos" quase direto ... a classe (local) L(buffer de linha) armazena uma linha de texto (in t), bem como ponteiros (anuláveis) para os próximos ( n) e anteriores ( p) linha. Os atributos (não anuláveis) u(para cima) ed (para baixo) inicializam aqueles se necessário (com um ponteiro reverso para si mesmo) e, nesse caso, também acompanham a primeira e a última linha geral (no fel variáveis ).

o a método (anexar) anexa um caractere a essa linha, incluindo alguns espaços eventualmente necessários.

cé a linha atual. Analisamos a string de entrada (usandoreadLine como a entrada deve estar em uma linha) usando uma instrução switch que atualiza a linha atual e, em seguida, chama o método append.

Após a conclusão da análise, iteramos as linhas da primeira à última, imprimindo cada uma delas. (Isso destrói of ponteiro, se necessário depois, deveríamos ter usado uma variável separada para isso.)

Alguns truques usados ​​para jogar golfe:

  • Algumas coisas que em outros idiomas seriam palavras-chave são na verdade apenas identificadores no ceylon.languagepacote e podem ser renomeadas com uma importação de alias - usamos isso para as anotações shared(usadas 5 ×) e variable(usadas 6 ×), bem como para o objeto null(usado 4 ×):

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

    (Curiosidades: o formatador no IDE do Ceilão formata algumas anotações de linguagem incorporadas, entre elas variable e shared, colocando-as na mesma linha da declaração anotada, contrasta com as anotações personalizadas, que são colocadas em uma linha separada acima da declaração. torna a versão formatada do programa de golfe ilegível, portanto, alterei o alias-imports novamente para esta versão.)

    this, void, case, elseSão palavras-chave reais e não pode ser renomeado desta maneira, e Integer, Stringe Characteraparecer apenas uma vez cada um, então não há nada a ser adquirida através da importação.

  • Originalmente, eu também tinha uma classe ScreenBuffer separada (que acompanhava a lista vinculada de buffers de linha, o índice atual e assim por diante), mas como havia apenas um objeto, ela foi otimizada.

  • Essa classe Screenbuffer também tinha upe downmétodos, que foram chamados a partir do analisador (e apenas o fizeram currentLine = currentLine.uprespectivamente currentLine = currentLine.down). Ele mostrou que fazer isso diretamente no comutador do analisador é mais curto. Também permitiu escrever currentLine = currentLine.up.up(que mais tarde se tornou c = c.u.u) em vez de currentLine = currentLine.up;currentLine = currentLine.up.

  • Originalmente, passamos o índice atual como argumento para o método append (e até para o analisador do loop) - ter uma variável na função que contém é mais curta.

  • Originalmente, meu método printAll usava o ponteiro atual e o movia primeiro para cima até que a linha atual estivesse vazia e depois para baixo enquanto imprimia cada linha. Isso quebrou ao usar ▲ e ▼ para pular linhas, então tivemos que acrescentar explicitamente algo nessas linhas saltadas. Manter o controle da primeira / última linha se mostrou mais fácil (embora tenha sido necessário o uso de duas instruções de impressão, porque não existe um ciclo de execução no Ceilão).

  • Originalmente, eu tinha algo parecido com isto:

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

    process.readLineretorna nullse não houver linha que possa ser lida (porque a entrada foi fechada) e o compilador Ceylon exige que eu verifique isso antes de acessar input. Como neste caso eu não quero fazer nada, posso usar de forma equivalente o elseoperador que retorna seu primeiro argumento, se não nulo, e o segundo argumento, salvando a variável e a instrução if. (Isso também nos permite codificar uma entrada padrão para testar: for (x in process.readLine() else "^^▲^v▼▲^^v") {)

Paŭlo Ebermann
fonte
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,'')

Bem, aqui está uma solução recursiva (bastante longa) que passa em todos os casos de teste fornecidos. Foi um bom desafio. Isso usak e jno lugar de e .

Snippet de teste

Embora o envio em si só possa manipular k,j, o seguinte snippet pode manipular ambos k,je ▼,▲.

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>

R. Kap
fonte