Це питання має свої злети і падіння


33

Вхід складається з таких символів:

  • ^: Підніміться один
  • v: Спуститися на одну
  • або k: Підніміться два
  • або j: Спустіться два

Наприклад, наступний вхід:

^^▲^v▼▲^^v

дасть такий вихід:

        ^
   ^   ^ v
  ▲ v ▲

 ^   ▼
^

Послідовності втечі, які переміщують курсор, такі як \e[Bне дозволяються. Ви повинні отримати результат, використовуючи пробіли та нові рядки.

Ось ще кілька тестових випадків.

▲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
Чи дозволений простір? Порожні рядки?
xnor

2
Що з мовами, які не підтримують Unicode? Чи можна використовувати альтернативні символи?
Дверна ручка

1
@xnor Дозволено пробіли та / або порожні рядки.
абсент

2
@Doorknob Я дозволяю jспускатися двічі та kтакож двічі підніматися.
абсент

1
@xnor Мій поганий: / Коментар правильний, і я неправильно відредагував правила. Виправимо зараз.
абсент

Відповіді:


9

Піт, 27 байт

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

Спробуйте в Інтернеті: Демонстрація або Тестовий набір

Я використовую kі jзамість і . Є багато провідних і кінцевих порожніх рядків. Щоб знайти зображення, вам доведеться досить небагато пошукати. Ось 34-байтна версія, яка видаляє всі провідні та остаточні рядки.

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

Спробуйте в Інтернеті: Демонстрація або Тестовий набір

Пояснення:

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

Нечитабельна , 2199 2145 2134 2104 2087 2084 байт

Підтримує як k/, jтак і / синтаксис.

За доброю нечитабельною традицією, ось програма, відформатована пропорційним шрифтом, щоб придушити різницю між апострофами та подвійними лапками:

"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" """ "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" """" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" """ "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" """" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" """ "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" """ "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" """ "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" """ "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" """ "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" """ "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" """" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" """ "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" """" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" """ "" "" "" ""

Це було дивовижною проблемою. Дякую за публікацію!

Пояснення

Щоб відчути, що не можна прочитати, а що не можна зробити, уявіть Brainfuck з нескінченною стрічкою в обох напрямках, але замість того, щоб вказівник пам’яті переміщав одну клітинку за часом, ви можете отримати доступ до будь-якої комірки пам’яті, відкинувши покажчик. Це дуже зручно в цьому рішенні, хоча інші арифметичні операції, включаючи модуль, потрібно виконувати вручну.

Ось програма як псевдокод з коментарем режисера:

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

Стільки для логіки програми. Тепер нам потрібно перекласти це на "Нечитабельно" і скористатися ще кількома цікавими трюками з гольфу.

Змінні завжди відмічаються чисельно в Нечитабельному (наприклад, a = 1стає чимось подібним *(1) = 1). Деякі числові літерали довші за інші; найкоротший - 1, за ним - 2 і т. д. Щоб показати, скільки довші від’ємні числа, ось цифри від -1 до 7:

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

Зрозуміло, ми хочемо віднести змінну №1 до тієї, яка найчастіше зустрічається в коді. У першому циклі while це, безумовно mod5, що з’являється в 10 разів. Але нам більше не потрібно mod5після першого циклу while, тому ми можемо переділити те саме місце пам'яті іншим змінним, які ми використовуємо згодом. Це є ptr2і ptr3. Зараз на цю зміну посилається 21 раз. (Якщо ви намагаєтесь порахувати кількість подій самостійно, не забудьте порахувати щось на зразок a++двічі, один раз для отримання значення та один раз для його встановлення.)

Є лише одна змінна, яку ми можемо повторно використовувати; після того як ми обчислили значення модуля, chце більше не потрібно. upі dnпридумуйте однакову кількість разів, тому або добре. Давайте об’єднаємось chіз up.

Це залишає загалом 8 унікальних змінних. Ми можемо виділити змінні від 0 до 7, а потім запустити блок пам'яті (що містить символи та номери рядків) з 8. Але! Оскільки 7 є такою ж довжиною в коді, що і -1, ми можемо також використовувати змінні від 1 до 6 і запустити блок пам'яті з 7. Таким чином, кожне посилання на початкове положення блоку пам'яті у коді трохи коротше! Це залишає нам такі завдання:

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

Тепер це пояснює ініціалізацію в самому верху: це 5, тому що це 7 (початок блоку пам'яті) мінус 2 (обов'язковий приріст у першій умові). Те саме стосується двох інших випадків 5 в останній циклі.

Зауважте, оскільки 0 і 4 однакові за довжиною в коді, ptrі їх minLineможна розподілити в будь-якому напрямку. ... Або вони могли?

Що з таємничим 2 у другому останньому циклі while? Чи не повинно це бути 6? Ми хочемо лише зменшити числа в блоці даних, правда? Як тільки ми досягнемо 6, ми знаходимося поза блоком даних, і нам слід зупинитися! Це було б вразливістю помилки помилки переповнення буфера!

Ну, подумайте, що станеться, якщо ми не зупинимось. Зменшуємо змінні 6 і 4. Змінна 6 є mod4. Це використовується тільки в першому циклі while і більше не потрібне тут, так що ніякої шкоди не було зроблено. Як щодо змінної 4? Як ви думаєте, ptrчи має бути змінною 4 чи має бути minLine? Правильно, minLineбільше не використовується в даний момент! Таким чином, змінна №4 є, minLineі ми можемо сміливо її зменшити і не завдати шкоди!

ОНОВЛЕННЯ 1! Golfed від 2199 до 2145 байт, розуміючи , що dnможе також бути об'єднаний з mod5, хоча mod5до цих пір використовується в обчисленні значення для dn! Нове призначення змінної зараз:

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

ОНОВЛЕННЯ 2! Поле з 2145 по 2134 байт, зрозумівши, що, оскільки mod5зараз він знаходиться в тій же змінній dn, що і нараховується до 0 за цикл, mod5більше не потрібно явно ініціалізувати до 0.

ОНОВЛЕННЯ 3! Гольфував з 2134 по 2104 байт, реалізуючи дві речі. По- перше, хоча ідея «негативний по модулю» варто його mod5, то ж міркування не відноситься до , mod4тому що ми ніколи не випробування проти і mod4+2т.д. Таким чином, зміна mod4 ? mod4+1 : -3до mod4 ? mod4-1 : 3призводить нас до 2110 байт. По-друге, оскільки mod4це завжди 0 або 2, ми можемо ініціалізувати mod4на 2 замість 0 і повернути два тернарі ( mod4 ? 3 : 1замість mod4 ? 1 : 3).

ОНОВЛЕННЯ 4! Поле з 2104 по 2087 байт, розуміючи, що цикл while, який обчислює значення модуля, завжди працює хоча б один раз, і в такому випадку Unreadable дозволяє повторно використовувати значення останнього твердження в іншому виразі. Таким чином, замість того, що while --ch: [...]; up = (mod5 ? mod5+1 ? [...]ми маємо зараз up = ((while --ch: [...]) ? mod5+1 ? [...](і всередині цього циклу while, ми обчислюємо mod4перше, так що mod5це останнє твердження).

ОНОВЛЕННЯ 5! Гольфував з 2087 по 2084 байт, зрозумівши, що замість того, щоб виписати константи 32і 10(пробіл та новий рядок), я можу зберігати число 10 у (зараз не використовується) змінній №2 (назвемо це ten). Замість того, щоб ptr3 = 5ми писати ten = (ptr3 = 5) + 5, тоді 32стає ten+22і print 10стає print ten.


Це ... жахливо ... +1
kirbyfan64sos

6

CJam, 37 байт

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

Це друкує порожні рядки до і після бажаного виводу, дозволеного ОП .

Спробуйте його в Інтернеті в інтерпретаторі CJam .

Як це працює

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.

Я думаю, було б справедливо лише чітко вказати як застереження, що ваше рішення створює велику кількість зайвих нових рядків до та після бажаного результату ...
Timwi

Додано. (Я не вважав за потрібне, оскільки ОП явно дозволила пусті рядки.)
Денніс

3

Пітон 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

Друкується рядок за рядком.

Проводить символи на вході та відстежує поточну висоту. Висота оновлюється однією з +2, +1, -1, -2обчислених 'kv_^j'.find(c)-2. Мабуть, модна ланцюжок коротша

Коли поточна висота дорівнює номеру рядка (що може бути негативним), ми додаємо поточний символ до рядка та іншим чином додаємо пробіл. Потім друкуємо рядок. Насправді коротше починати висоту на поточному номері рядка і віднімати зміни висоти, додаючи символ, коли значення потрапляє 0.

Номери рядків охоплюють достатньо великий діапазон, що послідовність до двох або вниз-двох залишатиметься в ньому. Власне, надлишкова кількість. Якби ми мали верхню межу вхідної довжини, писати було б коротше, скажімо j=999.

Дивно, але i and' 'or cбуло коротше, ніж зазвичай [' ',c][i==0]. Зауважте, що iможе бути негативним, що вирізає деякі звичні хитрощі.


2

МАТЛАБ, 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

Це початок. jІ kзробити його біль в шиї , як я не можу знайти метод математично відображення з j^vkв [-2 -1 1 2]і з MATLAB не визнаючи Unicode ( по- видимому , вгору і вниз , мають значення 26 у MATLAB. Піди розберися!), Є багато байт було витрачено на карту.

Маючи натхнення з рішення @xnors, код можна зменшити ще на 14 символів, зіставивши керуючий символ всередині циклу for.

Існує також багато байтів, які намагаються врахувати, якщо вхідна рядок відсилає шаблон назад нижче індексу, з якого він почався (можливо, якщо є обмеження на довжину рядка, я міг би спростити цей біт).

І в читаному вигляді:

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

Було б b=[-2 -1 1 2](a==[106 107 94 118])працювати? Працює в Октаві. Або навіть b=[-2 -1 1 2](a-94==[12 13 0 24])якщо ви хочете поголити ще один байт!
wchargin

@WChargin не працює в MATLAB. На жаль, поведінку ==зупинок, які працюють, а також у MATLAB ви не можете поставити ()після [].
Том Карпентер

Гм ... ви могли змінити мову на Октаву! :) (Octave також має +=, fwiw.)
wchargin

@WChargin Це обман = P Але я згоден, у Octave є багато ярликів, яких у Матлаба немає.
недолік

2

JavaScript (ES6), 140

Встановіть тест запуску фрагмента нижче в браузері, сумісному з EcmaScript 6 (протестовано на 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 байти

Цей вірно обчислює вихідні межі, щоб не створювалося зайвого пробілу. Ось моє рішення у шістнадцятковій формі

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

Невелике пояснення в порядку. На стеці у нас є введення користувача як масив кодів ascii. Програма запускається в рядковому буквальному з-за 05. Ось і ми.

  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 байти

У мене також є 24-байтне рішення, яке не вимагає великої уваги при обчисленні розміру виходу, і закінчується додатковим пробілом. Я вважаю за краще той, у якому пробіл зведений до мінімуму.

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

Кольоровий олівець , 13 байт (неконкурентний)

O"^ vj"\CynIq

Спробуйте в Інтернеті! Використовує справжні стрілки, бо чому б ні.

Без конкуренції, тому що Crayon набагато новіший, ніж ця проблема.

Як це працює

Crayon - це мова, що базується на стеках, розроблена для вбивства в ASCII-мистецтві. Він побудований навколо основи двовимірного вихідного "полотна" та "олівця", курсору, який об'їжджає це полотно. Все, що надсилається на вихід, намальовано на полотні в положенні олівця, а також у напрямку, спрямований олівцем. За замовчуванням олівець вказує на схід (праворуч).

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 байт

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

Використовує kі jзамість і .

Пара приміток:

  • Escape sequences that move the cursor such as \e[B are not allowed. You must produce the output using spaces and newlines.Я дотримуюся цього правила! pb використовує поняття "пензлик" для виведення символів. Кисть переміщається навколо «полотна» і може надрукувати персонаж безпосередньо під ним. Однак реальна реалізація друкує персонаж, використовуючи пробіли та нові рядки.
  • Я не збирався зациклюватися на цьому виклику, хоча я подумав, що це буде весело з pb, поки не побачив постанову про це You are allowed trailing spaces and/or empty lines. Це з кількох причин:
    • pb не може мати пробіли. Він завжди дає прямокутний вихід, при необхідності прокладки з пробілами.
    • Ця програма створює багато порожніх рядків. Він не знає, яким високим буде вихід, коли він починає робити його, тому для введення довжини nвін починається з Y=3n+1. The-1Тому , що вона йде вниз 3nвід Y=-1, і починаючи з Y=2n-1не виконується для входу всіх k.

Ви можете дивитися цю програму в дії на YouTube! Ця версія трохи модифікована тим, що вона лише зменшується n-1. Він працює для цього вводу, але не працює для інших. Однак це захоплює набагато приємніше.

З коментарями:

^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

Цейлон, 447 байт

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);}}

Або з розривами рядків для "читабельності": 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);}}

Це працює як з входом ▲ / ▼, так і з j / k (Якби нам довелося підтримувати лише один з них, програма була б на 8 байт коротше). Останній вихідний рядок порожній, коли початкове положення було на ньому (тобто перший вхід був або, ^і ми ніколи не опускалися нижче цього пізніше). Введення, яке не є одним із зазначених символів, буде просто надруковано як є, без перемикання рядка:

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

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

Ось відформатована версія (753 байти):

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);
    }
}

Це майже пряма "об'єктно-орієнтована" програма ... (локальний) клас L(буфер рядків) зберігає рядок тексту (в t), а також (нульові) вказівники на наступний ( n) та попередній ( p) рядок. Атрибути (не зведені до нуля) u(для вгору) і d(для вниз) ініціалізують ті, якщо потрібно (із зворотним вказівником на себе), і в цьому випадку також слідкують за першим і останнім рядком в цілому (у змінних fта lзмінних).

Метод a(append) додає символ до цього рядка, включаючи необхідні пробіли.

c- поточний рядок. Ми аналізуємо рядок введення (використовуючи readLineяк вхід повинен бути в одному рядку), використовуючи оператор перемикання, який оновлює поточний рядок, а потім викликає метод додавання.

Після того, як буде проаналізовано, ми повторюємо рядки від першого до останнього, друкуючи кожен з них. (Це знищуєf вказівник, якщо він був необхідний після цього, ми повинні були використовувати для цього окрему змінну.)

Деякі використовувані трюки для гольфу:

  • Деякі речі, які в інших мовах будуть ключовими словами, насправді є лише ідентифікаторами в ceylon.languageпакеті і можуть бути перейменовані за допомогою імпорту псевдоніму - ми використовували це для анотацій shared(використано 5 ×) та variable(використано 6 ×), а також для об'єкта null(використано 4 ×):

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

    (Загальні відомості: Форматор у Цейлонському IDE формує деякі вбудовані мовні примітки між ними variableтаshared , розміщуючи їх у тому ж рядку, що і примітка з примітками, протиставляється звичайним анотаціям, які розміщуються в окремому рядку над декларацією. Це робить форматовану версію програми для гольфу нечитабельною, тому я змінив псевдонім-імпорт для цієї версії.)

    this, void, case, elseФактичні ключові слова і не можуть бути перейменовані таким чином, і Integer, Stringі Characterз'являються тільки один раз, так що немає нічого , щоб бути досягнуто за рахунок імпорту.

  • Спочатку у мене також був окремий клас ScreenBuffer (який відслідковував пов'язаний список буферних рядків, поточний індекс тощо), але оскільки в ньому був лише один об'єкт, він був оптимізований.

  • Цей клас Screenbuffer також мав upі downметоди, які викликалися з аналізатора (і щойно зробили currentLine = currentLine.upвідповідно currentLine = currentLine.down). Це показало, що безпосередньо робити це в комутаторі парсера коротше. Це також дозволяло писати currentLine = currentLine.up.up(що згодом стало c = c.u.u) замість currentLine = currentLine.up;currentLine = currentLine.up.

  • Спочатку ми передавали поточний індекс як аргумент методу додавання (і навіть до аналізатора з циклу) - маючи його змінну у функції, що містить, коротше.

  • Спочатку мій метод printAll використовував поточний покажчик і переміщував його спочатку вгору, поки поточний рядок не порожній, а потім вниз під час друку кожного рядка. Це зламалося при використанні ▲ та ▼ для переходу через рядки, тому нам довелося напроти додати щось до цих стрибків. Відстеження першого / останнього рядка виявилося простішим (хоча для цього було необхідним використання двох операцій друку, оскільки в Цейлоні немає циклу "do-while").

  • Спочатку у мене було щось подібне:

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

    process.readLineповертається, nullякщо немає рядка, який можна прочитати (тому що вхід закритий), і компілятор Цейлону вимагає від мене перевірити це перед тим, як отримати доступ input. Оскільки в цьому випадку я не хочу нічого робити, я можу рівномірно використовувати elseоператор, який повертає свій перший аргумент, якщо не нульовий, інакше його другий аргумент, зберігаючи змінну та оператор if. (Це також дозволить нам закодувати введення за замовчуванням для тестування: for (x in process.readLine() else "^^▲^v▼▲^^v") {)


0

JavaScript (ES6), 228 байт

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,'')

Ну ось ось (досить тривалий) рекурсивний варіант, який проходить усі наведені тестові випадки. Це був приємний виклик. При цьому використовується kі jзамість і .

Тест-фрагмент

Незважаючи на те, що подання само по собі може обробляти лише k,jнаступний фрагмент, може працювати і з k,jі ▼,▲.

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>

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.