Этот вопрос имеет свои взлеты и падения


33

Ввод будет состоять из следующих символов:

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

Например, следующий вход:

^^▲^v▼▲^^v

будет производить следующий вывод:

        ^
   ^   ^ v
  ▲ v ▲

 ^   ▼
^

Escape-последовательности, которые перемещают курсор, например \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

Pyth, 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

Вот вам и логика программы. Теперь нам нужно перевести это на Unreadable и использовать еще несколько интересных трюков для игры в гольф.

Переменные всегда численно разыменовываются в Unreadable (например, 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 (обязательное приращение в первом условии while). То же самое касается двух других вхождений 5 в последнем цикле.

Обратите внимание, что, поскольку 0 и 4 имеют одинаковую длину в коде, ptr и minLineможет быть выделена либо наоборот. ... Или они могли?

Что насчет загадочных 2 во втором-последнем цикле while?Разве это не должно быть 6? Мы хотим только уменьшить числа в блоке данных, верно? Как только мы достигнем 6, мы за пределами блока данных, и мы должны остановиться! Это была бы уязвимость безопасности ошибки ошибки переполнения буфера!

Хорошо, подумай о том, что произойдет, если мы не остановимся. Уменьшаем переменные 6 и 4. Переменная 6 есть mod4. Это используется только в первом цикле while и больше здесь не нужно, так что никакого вреда. Как насчет переменной 4? Как вы думаете, должна ли переменная 4 быть ptrили должна быть minLine? Это верно, minLineбольше не используется в этой точке либо! Таким образом, переменная # 4 есть, minLineи мы можем безопасно уменьшить ее и не нанести ущерба!

ОБНОВЛЕНИЕ 1! Гольф от 2199 до 2145 байтов, понимая, что такжеdn может быть объединен с , хотя все еще используется в вычислении значения для ! Новое назначение переменной теперь:mod5mod5dn

 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 в цикле while, mod5больше не нужно явно инициализироваться равным 0.

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

ОБНОВЛЕНИЕ 4! Проигрывая от 2104 до 2087 байтов, осознав, что цикл while, который вычисляет значения по модулю, всегда выполняется по крайней мере один раз, и в таком случае Unreadable позволяет вам повторно использовать значение последнего оператора в другом выражении. Таким образом, вместо того, while --ch: [...]; up = (mod5 ? mod5+1 ? [...]чтобы теперь иметь up = ((while --ch: [...]) ? mod5+1 ? [...](и внутри этого цикла, мы 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*

Это печатает пустые строки до и после желаемого вывода, что было разрешено OP .

Попробуйте онлайн в интерпретаторе 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.

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

Добавлен. (Я не думал, что это было необходимо, поскольку ОП явно разрешало пустые строки.)
Деннис

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

Печатает построчно.

Прокручивает символы на входе и отслеживает текущую высоту. Высота обновляется одним из +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 (очевидно, что и MATLAB вверх и вниз имеют значение 26 в. много байтов тратится на отображение.

Черпая вдохновение из решения @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! :) (у Octave тоже есть +=, fwiw.)
wchargin

@WChargin Это обман = P Но я согласен, у Octave есть много ярлыков, которых нет у Matlab.
flawr

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

Crayon , 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 использует понятие «кисти» для вывода символов. Кисть перемещается вокруг «холста» и может печатать символ непосредственно под ним. Однако фактическая реализация печатает символ, используя пробелы и переводы строк.
  • Я не собирался беспокоиться об этом вызове, хотя я думал, что это будет весело с ПБ, пока я не понял, что это решение You are allowed trailing spaces and/or empty lines. Это по нескольким причинам:
    • PB не может не быть завершающие пробелы. Он всегда производит прямоугольный вывод, дополняя пробелами при необходимости.
    • Эта программа производит много пустых строк. Он не знает, какой будет длина вывода, когда он начнет его делать, поэтому для ввода длины nон начинается с Y=3n+1. -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 байт короче). Последняя выходная строка пуста, когда на ней была начальная позиция (т. Е. Первый вход был a или ^и мы никогда не опускались ниже этого позже). Ввод, который не является одним из указанных символов, будет просто напечатан как есть, без переключения строки:

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(строковый буфер) хранит строку текста (in t), а также (обнуляемые) указатели на next ( n) и previous ( p) линия. Атрибуты (не обнуляемые) u(для вверх) и d(для вниз) инициализируют их, если необходимо (с обратным указателем на себя), и в этом случае также отслеживают первую и последнюю строку в целом (в fиl переменных).

Метод a(append) добавляет символ к этой строке, включая некоторые пробелы, которые могут понадобиться.

cтекущая строка Мы анализируем входную строку (используя readLineв качестве входных данных должна быть одна строка), используя инструкцию switch, которая обновляет текущую строку, а затем вызывает метод append.

После разбора мы перебираем строки от первой до последней, печатая каждую из них. (Это уничтожает fуказатель, если бы он был нужен впоследствии, мы должны были бы использовать для этого отдельную переменную.)

Некоторые использовали трюки для игры в гольф:

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

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

    (Общая информация: Средство форматирования в IDE Ceylon форматирует некоторые встроенные аннотации на языке, между ними 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-loop).

  • Изначально у меня было что-то вроде этого:

      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.