To pytanie ma swoje wzloty i upadki

33

Dane wejściowe będą się składały z następujących znaków:

  • ^: Idź w górę
  • v: Zejdź jeden
  • lub k: Idź o dwa wyżej
  • lub j: Zejdź dwa

Na przykład następujące dane wejściowe:

^^▲^v▼▲^^v

dałoby następujące dane wyjściowe:

        ^
   ^   ^ v
  ▲ v ▲

 ^   ▼
^

Sekwencje specjalne, które poruszają kursorem, takie jak \e[B są niedozwolone. Musisz wygenerować wynik za pomocą spacji i znaków nowej linii.

Oto kilka innych przypadków testowych.

▲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
Absynt
źródło
1
Czy dozwolone jest końcowe miejsce? Puste linie?
xnor
2
Co z językami, które nie obsługują Unicode? Czy można stosować znaki alternatywne?
Klamka
1
@xnor Dozwolone są końcowe spacje i / lub puste linie.
absynt
2
@Doorknob Pozwolę jna dwa razy w dół i kna dwa razy w górę.
absynt
1
@xnor My bad: / Komentarz jest poprawny i źle zredagowałem reguły. Naprawię teraz.
absynt

Odpowiedzi:

9

Pyth, 27 bajtów

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

Wypróbuj online: pakiet demonstracyjny lub testowy

Używam ki jzamiast i . Istnieje wiele wiodących i końcowych pustych linii. Musisz znaleźć sporo, aby znaleźć obraz. Oto 34-bajtowa wersja, która usuwa wszystkie wiodące i końcowe puste linie.

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

Wypróbuj online: Demonstracja lubpakiet testowy

Wyjaśnienie:

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
źródło
16

Nieczytelny , 2199 2145 2134 2104 2087 2084 bajtów

Obsługuje zarówno k/ jjak i / składnię.

Zgodnie z dobrą Nieczytelną tradycją program jest sformatowany czcionką proporcjonalną, aby zaciemnić różnicę między apostrofami a podwójnymi cudzysłowami:

„” „” „” „” „„ ”„ „” „„ ”„ ”„ ”„ ”„ „” „„ ”„ ”„ ”„ ”„ ”„ ”„ ” „” „” „” „” „” „” „„ ”„ ”„ ”„ ”„ „” „„ ”„ „” „” „” „” „” „” „” „” „” „” „” „” „” „” „„ ”„ ”„ ”„ ”„ „” „„ ”„ ”„ ”„ ”„ ”„ ”„ ”„” „„ ”„ ”„ „” „” „„ ”„ „” „” „” „” „„ ”„ „” „” „” „” „” „” „” „” „” „” „” „” „” „„ ”„ ”„ ”„ „” „„ ”„ „” „” „” „” „” „” „” „” „” „” „” „„ ”„ ”„ ”„ „” „” „” „” „„ ”„ ”„ ”„ ”„ ”„ ”„ ”„ ”„” „” „” „” „„ ”„ ”„ ”„ ”„ ”„ ”„ ”„ „” „„ ”„ ”„ ”„ ”„ ”„ ”„ ”„ ” „” „” „” „” „„ ”„ ”„ ”„ ”„ ”„ „” „” „” „„ ”„ ”„ ”„ ”„ ”„ ”„ ” „” „” „” „” „„ ”„ ”„ ”„ „” „” „” „” „„ ”„ „” „” „” „” „” „”„” „” „” „” „„ ”„ ”„ ”„ ”„ ”„ ”„ ”„ „” „„ ”„ ”„ ”„ „” „” „” „” „” „” „” „” „” „„ ”„ ”„ ”„ ”„ ”„ ”„ ”„ ”„ ”„ „” „” „” „” „” „” „” „” „” „” „” „„ ”„ ”„ ”„ ”„ ”„ ”„ ”„ „” „„ ”„ ”„ ”„ ”„ ”„ ”„” „” „” „” „” „” „” „” „” „” „” „„ ”„ „” „” „” „” „” „” „” „” „” „” „” „„ ”„ ”„ ”„ ”„ ”„ ”„ ”„ ”„ „” „„ ”„ ”„ ”„ ”„ ”„ ”„ ” „” „” „” „” „„ ”„ ”„ ”„ ”„ ”„ ”„ „” „„ ”„ „” „” „” „” „” „”„” „” „” „” „„ ”„ ”„ „” „„ ”„ ”„ ”„ „” „„ ”„ ”„ ”„ ”„ ”„ ”„ ” „” „” „” „” „” „„ ”„ ”„ ”„ ”„ ”„ ”„ „” „„ ”„ ”„ ”„ ”„ ”„ ”„ ” „” „” „” „” „„ ”„ ”„ ”„ „” „” „” „„ ”„ „” „„ ”„ ”„ ”„ ”„ ”„ ”„” „” „” „” „„ ”„ „” „” „” „” „” „„ ”„ „” „„ ”„ „” „” „” „” „” „” „” „” „„ ”„ ”„ ”„ ”„ ”„ ”„ „” „„ ”„ „” „” „” „” „” „” „” „” „” „” „” „„ ”„ ”„ „” „” „” „” „” „” „„ ”„ ”„ ”„ ”„ ”„ ”„ ”„” „” „” „” „” „” „„ ”„ ”„ ”„ ”„ ”„ „” „„ ”„ „” „” „” „” „” „” „” „” „” „„ ”„ ”„ „” „„ ”„ ”„ ”„ ”„ „” „„ ”„ „” „” „” „” „” „” „” „” „” „” „„ ”„ „” „” „” „” „„ ”„ „” „„ ”„ ”„ ”„ ”„ ”„ ”„ ”„” „” „” „” „„ ”„ ”„ „” „” „” „„ ”„ „” „„ ”„ ”„ ”„ ”„ ”„ ”„ ” „” „” „” „” „” „” „„ ”„ „” „” „” „” „„ ”„ „” „” „” „” „” „” „” „” „” „” „” „„ ”„ ”„ ”„ ”„ ”„ ”„ ”„ „” „„ ”„ „” „” „” „” „”„” „” „” „” „„ ”„ ”„ „” „” „” „„ ”„ „” „„ ”„ „” „„ ”„ ”„ ”„ ” „” „” „” „” „” „” „” „„ ”„ ”„ ”„ ”„ ”„ „” „” „” „” „” „” „” „” „” „” „” „” „” „” „” „„ ”„ ”„ ”„ ”„ „” „„ ”„ ”„ ”„ ”„ ”„ ”„” „” „” „” „” „” „„ ”„ ”„ ”„ ”„ ”„ ”„ „” „„ ”„ ”„ ”„ ”„ ”„ ”„ ” „” „” „” „” „„ ”„ ”„ ”„ ”„ ”„ ”„ ”„ „” „„ ”„ ”„ ”„ ”„ ”„ ”„ ”„ ” „” „” „” „” „„ ”„ „” „” „” „” „” „” „” „„ ”„ ”„ ”„ ”„ ”„ ”„” „” „” „” „” „” „„ ”„ „” „” „” „„ ”„ „” „” „” „” „” „” „” „” „” „” „” „” „” „” „„ ”„ ”„ ”„ „” „„ ”„ „” „„ ”„ „” „” „” „” „” „” „” „” „„ ”„ ”„ ”„ ”„ ”„ ”„ ”„ „” „„ ”„ ”„ ”„ „” „” „” „”„” „” „” „” „„ ”„ ”„ „” „” „” „„ ”„ ”„ „” „„ ”„ ”„ ”„ ”„ ”„ ”„ ” „” „” „” „” „„ ”„ ”„ „” „” „” „„ ”„ „” „„ ”„ ”„ ”„ ”„ ”„ ”„ ”„ ” „” „” „” „” „” „” „„ ”„ ”„ ”„ ”„ „” „„ ”„ „” „” „„ ”„ ”„ ”„ ”„” „” „” „” „” „” „” „„ ”„ ”„ ”„ „” „„ ”„ „” „„ ”„ ”„ ”„ ” „” „” „” „” „” „” „” „” „” „„ ”„ „” „„ ”„ „” „” „” „” „” „” „” „” „” „” „” „„ ”„ ”„ ”„ „” „” „” „” „” „„ ”„ ”„ ”„ ”„ ”„ ”„ ”„” „„ ”„ ”„ ”„ ”

To było niesamowite wyzwanie. Dziękujemy za wysłanie wiadomości!

Wyjaśnienie

Aby poczuć, co Nieczytelne może, a czego nie może zrobić, wyobraź sobie, że Brainfuck ma nieskończoną taśmę w obu kierunkach, ale zamiast wskaźnika pamięci przesuwającego się o jedną komórkę na raz, możesz uzyskać dostęp do dowolnej komórki pamięci, usuwając odwołanie ze wskaźnika. Jest to bardzo przydatne w tym rozwiązaniu, chociaż inne operacje arytmetyczne - w tym modulo - muszą być wykonywane ręcznie.

Oto program jako pseudokod z komentarzem reżysera:

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

Tyle o logice programu. Teraz musimy przetłumaczyć to na Nieczytelne i zastosować kilka ciekawszych sztuczek golfowych.

Zmienne są zawsze dereferencyjne numerycznie w Nieczytelne (np. Stają a = 1się czymś podobnym *(1) = 1). Niektóre literalne liczby są dłuższe niż inne; najkrótsza to 1, następnie 2 itd. Aby pokazać, o ile dłuższe są liczby ujemne, oto liczby od -1 do 7:

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

Oczywiście chcemy przypisać zmienną nr 1 do tej, która występuje najczęściej w kodzie. W pierwszej pętli while jest to zdecydowanie mod5, co pojawia się 10 razy. Ale nie potrzebujemy mod5już po pierwszej pętli while, więc możemy ponownie przydzielić tę samą lokalizację pamięci do innych zmiennych, których będziemy używać później. To są ptr2i ptr3. Teraz zmienna odnosi się w sumie 21 razy. (Jeśli próbujesz samodzielnie policzyć liczbę wystąpień, pamiętaj o policzeniu czegoś takiego jak a++dwa razy, raz dla uzyskania wartości i raz dla jej ustawienia).

Jest tylko jedna zmienna, której możemy użyć ponownie; po obliczeniu wartości modulo chnie jest już potrzebne. upi dnpojawiają się tyle samo razy, więc albo jedno jest w porządku. Połączmy się chz up.

To pozostawia w sumie 8 unikalnych zmiennych. Możemy przypisać zmienne od 0 do 7, a następnie uruchomić blok pamięci (zawierający znaki i numery wierszy) na 8. Ale! Ponieważ 7 ma taką samą długość w kodzie jak -1, równie dobrze możemy użyć zmiennych od -1 do 6 i rozpocząć blok pamięci od 7. W ten sposób każde odniesienie do początkowej pozycji bloku pamięci jest nieco krótsze! To pozostawia nam następujące zadania:

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

Teraz to wyjaśnia inicjalizacji na samej górze: to 5 bo to 7 (początek bloku pamięci) minus 2 (obowiązkowy przyrost pierwszy podczas stanu). To samo dotyczy pozostałych dwóch wystąpień 5 w ostatniej pętli.

Zauważ, że ponieważ 0 i 4 mają taką samą długość w kodzie ptri minLinemogą być przydzielane w obie strony. ... Czy mogliby?

Co powiesz na tajemniczą 2 w pętli while last-last? Czy nie powinno to być 6? Chcemy tylko zmniejszać liczby w bloku danych, prawda? Gdy osiągniemy 6, jesteśmy poza blokiem danych i powinniśmy przestać! Byłaby to luka bezpieczeństwa związana z błędem błędu przepełnienia bufora!

Zastanów się, co się stanie, jeśli nie przestaniemy. Zmniejszamy zmienne 6 i 4. Zmienna 6 to mod4. Jest to używane tylko w pierwszej pętli while i nie jest już tutaj potrzebne, więc nie wyrządzisz żadnej szkody. Co ze zmienną 4? Jak myślisz, ptrjaka powinna być zmienna 4, czy powinna być minLine? Zgadza się, minLinew tym momencie nie jest już używany! Zatem zmienna nr 4 jest minLinei możemy ją bezpiecznie zmniejszać i nie wyrządzać żadnych szkód!

AKTUALIZACJA 1! Golfed od 2199 do 2145 bajtów przez świadomość, że dnmogą również zostać połączone z mod5, choć mod5nadal jest używana do obliczania wartości dla dn! Nowe przypisanie zmiennych to teraz:

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

AKTUALIZACJA 2! Gra w golfa od 2145 do 2134 bajtów, zdając sobie sprawę, że ponieważ mod5jest teraz w tej samej zmiennej co dn, która jest liczona do 0 w pętli while, mod5nie musi już być jawnie inicjowana na 0.

AKTUALIZACJA 3! Grał w golfa od 2134 do 2104 bajtów, realizując dwie rzeczy. Po pierwsze, mimo że „negatywne modulo” Chodziło o to, warto na mod5, to samo rozumowanie nie dotyczy mod4, bo nigdy Test przeciwko mod4+2etc. Dlatego zmienia mod4 ? mod4+1 : -3się mod4 ? mod4-1 : 3przenosi nas do 2110 bajtów. Po drugie, ponieważ mod4zawsze wynosi 0 lub 2, możemy zainicjować mod4na 2 zamiast 0 i odwrócić dwie trójki ( mod4 ? 3 : 1zamiast mod4 ? 1 : 3).

AKTUALIZACJA 4! Gra w golfa od 2104 do 2087 bajtów, zdając sobie sprawę, że pętla while, która oblicza wartości modulo, zawsze działa co najmniej raz, aw takim przypadku Nieczytelny pozwala ponownie użyć wartości ostatniej instrukcji w innym wyrażeniu. Zatem zamiast tego while --ch: [...]; up = (mod5 ? mod5+1 ? [...]mamy teraz up = ((while --ch: [...]) ? mod5+1 ? [...](a wewnątrz tej pętli while obliczamy mod4najpierw, więc mod5jest to ostatnia instrukcja).

AKTUALIZACJA 5! Grał w golfa od 2087 do 2084 bajtów, zdając sobie sprawę, że zamiast zapisywać stałe 32i 10(spację i nową linię ), mogę zapisać liczbę 10 w (teraz nieużywanej) zmiennej nr 2 (nazwijmy to ten). Zamiast ptr3 = 5pisać ten = (ptr3 = 5) + 5, 32staje się ten+22i print 10staje print ten.

Timwi
źródło
To jest ... okropne ... +1
kirbyfan64sos
6

CJam, 37 bajtów

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

Wyświetla puste linie przed i po żądanym wyjściu, na co zezwolił OP .

Wypróbuj online w interpretatorze CJam .

Jak to działa

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
źródło
Myślę, że byłoby uczciwe jedynie jednoznacznie stwierdzić, że twoje rozwiązanie generuje mnóstwo dodatkowych linii przed i po pożądanym wyniku ...
Timwi
Dodany. (Nie sądziłem, że było to konieczne, ponieważ PO wyraźnie zezwalał na puste linie.)
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

Drukuje linia po linii.

Pętla przechodzi przez znaki na wejściu i śledzi bieżącą wysokość. Wysokość jest aktualizowana przez jeden z +2, +1, -1, -2obliczonych przez 'kv_^j'.find(c)-2. Prawdopodobnie istnieje krótszy łańcuch modów

Gdy bieżąca wysokość jest równa numerowi linii (która może być ujemna), dodajemy bieżący znak do linii, a w przeciwnym razie dodajemy spację. Następnie drukujemy linię. W rzeczywistości krócej jest rozpocząć wysokość od bieżącego numeru linii i odjąć zmiany wysokości, dodając znak, gdy wartość osiągnie wartość0 .

Numery linii obejmują wystarczająco duży zakres, że sekwencja dwóch w górę lub w dół dwóch pozostanie w nim. W rzeczywistości istnieje spora nadwyżka. Gdybyśmy mieli górną granicę długości wejściowej, powiedzmy, że pisanie byłoby krótsze j=999.

Co zaskakujące, i and' 'or cbył krótszy niż zwykle [' ',c][i==0]. Zauważ, że imoże być negatywne, co eliminuje niektóre zwykłe sztuczki.

xnor
źródło
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

To poczatek. jI ksprawiają, że ból w szyi, jak nie mogę znaleźć sposób matematycznie Mapa od j^vkdo [-2 -1 1 2]i z MATLAB nie uznając widocznie Unicode (zarówno w górę iw dół mają wartość 26 w MATLAB. Domyśl!), Istnieje wiele bajtów zmarnowało się podczas mapowania.

Czerpiąc inspirację z rozwiązania @xnors, można zmniejszyć kod o kolejne 14 znaków, odwzorowując znak kontrolny wewnątrz pętli for.

Istnieje również wiele bajtów zmarnowanych na próbę uwzględnienia, czy ciąg wejściowy odsyła wzorzec z powrotem poniżej indeksu, przy którym się zaczął (być może, jeśli istnieje ograniczenie długości łańcucha, mógłbym uprościć ten bit).

I w czytelnej formie:

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
źródło
Czy b=[-2 -1 1 2](a==[106 107 94 118])zadziała? Działa w Octave. A nawet b=[-2 -1 1 2](a-94==[12 13 0 24])jeśli chcesz zgolić jeszcze jeden bajt!
wchargin
@WChargin nie działa w MATLAB. Niestety zachowanie ==przystanków, które działają, a także w MATLAB nie można umieścić ()po [].
Tom Carpenter,
Hmm…you could change the language to Octave! :) (Octave also has +=, fwiw.)
wchargin
@WChargin That is cheating=P But I agree, Octave has a lot of shortcuts that Matlab does not have.
flawr
2

JavaScript (ES6), 140

Test running the snippet below in a EcmaScript 6 compliant browser (tested on 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
źródło
1

GS2, 34 bytes

This one correctly calculates the output bounds so no excess whitespace is produced. Here's my solution in hex

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

A little explanation is in order. On the stack we have user input as an array of ascii codes. The program starts in a string literal because of the 05. Here we go.

  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

I also have a 24 byte solution that doesn't take as much care calculating output size, and ends up with extra whitespace. I prefer the one with the whitespace kept to a minimum though.

5e 20 76 6a 05 3e 26 ea 30 e0 6d d0 08 4d 42 d1
30 5e d1 5c 09 b1 9a 54
recursive
źródło
1

Crayon, 13 bytes (non-competing)

O"^ vj"\CynIq

Try it online! Uses the real arrows because why not.

Non-competing because Crayon is way newer than this challenge.

How it works

Crayon is a stack-based language designed to be killer at ASCII-art challenges. It is built around the basis of a 2-dimensional output "canvas", and a "crayon", a cursor that travels around this canvas. Anything that is sent to output is drawn on the canvas at the position of the crayon, and in the direction the crayon is facing. By default, the crayon points East (to the right).

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
źródło
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]^>}

Uses k and j instead of and .

A couple of notes:

  • Escape sequences that move the cursor such as \e[B are not allowed. You must produce the output using spaces and newlines. I do follow this rule! pb uses the concept of a "brush" to output characters. The brush moves around the "canvas" and can print a character immediately below it. However, the actual implementation prints the character using spaces and newlines.
  • I wasn't going to bother with this challenge even though I thought it would be fun with pb until I saw the ruling that You are allowed trailing spaces and/or empty lines. This is for a couple of reasons:
    • pb can't not have trailing spaces. It always produces rectangular output, padding with spaces if necessary.
    • This program produces a lot of empty lines. It doesn't know how tall the output is going to be when it starts making it, so for an input of length n it starts at Y=3n+1. The -1 is because it's going down 3n from Y=-1, and starting at Y=2n-1 fails for an input of all k.

You can watch this program in action on YouTube! This version is slightly modified in that it only goes down to n-1. It works for this input, but will fail for others. It does, however, capture a lot nicer.

With comments:

^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
źródło
0

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

Or with line breaks for "readability": 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);}}

This works with both the ▲/▼ and the j/k input (If we had to support just one of them, the program would be 8 bytes shorter). The last output line is empty when the starting position was on it (i.e. the first input was a or ^ and we never got below that again later). Input which is not one of the specified characters will simply be printed as-is, without switching the line:

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

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

Here is a formatted version (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);
    }
}

This is an almost straight-forward "object-oriented" program ... the (local) class L (line buffer) stores a line of text (in t), as well as (nullable) pointers to the next (n) and previous (p) line. The (not nullable) attributes u (for up) and d (for down) initialize those if needed (with a reverse pointer to itself), and in this case also keep track of the first and last line overall (in the f and l variables).

The a (append) method appends a character to this line, including some spaces eventually necessary.

c is the current line. We parse the input string (using readLine as the input should be on one line) using a switch statement which updates the current line, and then calls the append method.

After parsing is done, we iterate over the lines from the first to the last, printing each of them. (This destroys the f pointer, if it were needed afterwards, we should have used a separate variable for this.)

Some used tricks for golfing:

  • Some stuff which in other languages would be keywords are actually just identifiers in the ceylon.language package, and can be renamed with an alias import – we used this for the annotations shared (used 5×) and variable (used 6×), as well as for the object null (used 4×):

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

    (Trivia: The Formatter in the Ceylon IDE formats some built-in language annotations, between them variable and shared, by putting them in the same line as the annotated declaration, contrasted to custom annotations, which are put on a separate line above the declaration. This makes the formatted version of the golfed program unreadable, therefore I changed the alias-imports back for this version.)

    this, void, case, else are actual keywords and cannot be renamed this way, and Integer, String and Character appear just once each, so there is nothing to be gained by importing.

  • Originally I also had a separate ScreenBuffer class (which kept track of the linked list of line buffers, the current index, and so on), but as there was only ever one object of it, it was optimized away.

  • That Screenbuffer class also had up and down methods, which were called from the parser (and just did currentLine = currentLine.up respectively currentLine = currentLine.down). It showed that directly doing this in the parser's switch is shorter. It also allowed to write currentLine = currentLine.up.up (which later became c = c.u.u) instead of currentLine = currentLine.up;currentLine = currentLine.up.

  • Originally we did pass the current index as an argument into the append method (and even to the parser from the loop) – having it a variable in the containing function is shorter.

  • Originally my printAll method used the current pointer and moved it first up until the current line was empty, and then down while printing each line. This broke when using ▲ and ▼ to jump over lines, so we had to explicitly append something in those jumped lines instead. Keeping track of first/last line proved easier (though it made it necessary to use two print statements, because there is no do-while-loop in Ceylon).

  • Originally I had something like this:

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

    process.readLine returns null if there is no line which can be read (because the input has been closed), and the Ceylon compiler requires me to checkfor that before I access input. As in this case I want to do nothing, I can equivalently use the else operator which returns its first argument if not null, and otherwise its second argument, saving the variable and the if-statement. (This also would allow us to encode a default input for testing: for (x in process.readLine() else "^^▲^v▼▲^^v") {)

Paŭlo Ebermann
źródło
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,'')

Well, here is a (rather long) recursive solution that passes all of the test cases given. It was a nice challenge. This uses k and j in place of and .

Test Snippet

Although the submission itself can only handle k,j, the following snippet can handle both k,j and ▼,▲.

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
źródło