pssssssssssssst

31

Wprowadzenie

To jest bardzo proste. Będziemy rysować węża w ascii. Inspiracją była stara gra w węża, w której musisz zbierać owoce i stale się rozwijać.

Definicja

Biorąc pod uwagę dodatnią liczbę całkowitą N reprezentującą długość węża, narysuj węża tak, aby miał ciało n plus głowę i ogon.

Części:

  • głowa: <, >, ^, v
  • ogon: @
  • pionowy: |
  • horyzontalny: -

Wszystkie rogi powinny być spełnione odpowiednio \lub /. Chyba że głowa kończy się na rogu, w którym to przypadku głowa <, >, ^, vma priorytet w kierunku, w którym wąż jest zwinięty. tzn. dla przykładu o długości 1 jest on obracany przeciwnie do ruchu wskazówek zegara, a zatem głowica jest obracana w ten sposób. W przypadku rozwiązania zgodnego z ruchem wskazówek zegara byłoby to po prawej stronie >.

Wąż musi zaczynać ogonem od środka, ale może wychodzić na zewnątrz w dowolnym kierunku, zgodnie z ruchem wskazówek zegara lub przeciwnie do ruchu wskazówek zegara. Musi także ściśle przylegać do siebie, ponieważ rozszerza się na zewnątrz w kółko.

Przykład

/--\
|/\|
||@|
|\-/
\--->

Gdzie @jest ogon i pozycja początkowa. Jak widać powyżej, ogon zaczyna się w środku, idzie w górę w lewo w kierunku przeciwnym do ruchu wskazówek zegara na zewnątrz.

Tutaj długość 19plus ogon i głowa.

Jako kolejny przykład podajemy długość 1:

<\
 @

Zwycięski

To jest golf golfowy, więc wygrywa odpowiedź przesłana z najmniejszą liczbą bajtów, z czasem do wykorzystania jako remis.

Baw się dobrze!

jacksonecac
źródło
2
Nie jest jasne, czy nie wolno mi narysować prostego węża @---->. Prawdopodobnie zamierzasz zaostrzyć warunki dotyczące kształtu węża. Wyjaśnij również, ile białych znaków jest dozwolone, a które nie.
Ton Hospel
1
„Wąż musi zacząć od środka ogonem, ale może wychodzić na zewnątrz w dowolnym wybranym kierunku i zgodnie z ruchem wskazówek zegara lub przeciwnie do ruchu wskazówek zegara”
jacksonecac,
1
Mówię więc, że @jest środek (możliwe, aby dodać spacje, aby tak było), zadeklaruj „w prawo”, aby być kierunkiem i skieruj tylko głowę w dół i zadeklaruj zgodnie z ruchem wskazówek zegara. Twoje warunki mogą wydawać się jasne, ale w rzeczywistości są niejednoznaczne. Zdaję sobie sprawę, że prawdopodobnie chodzi ci o jak najściślej zwiniętego węża, ale powinieneś to wyjaśnić
Ton Hospel,
1
Nie martw się Ten jest o wiele trudniejszy ze względu na przesunięcia w tym wyzwaniu.
Martin Ender
2
Ładne pierwsze wyzwanie! Witamy na stronie!
Luis Mendo,

Odpowiedzi:

10

MATL , 85 83 bajtów

Pomyślałem, że posiadanie spiralwbudowanego kodu byłoby krótkim kodem ...

Oli2+XH:UQXItH:+XJh(YsXKoQ3I(4J(5l(H:)0HX^XkU(6H(3M1YL3X!P)'|-\/@' '<v>^'KHq))h0hw)

Wypróbuj online!

Wyjaśnienie

Niech N oznacza wejście. Stworzymy wektor długości ceil(sqrt(N+2))^2, czyli najmniejszy idealny kwadrat, który jest równy lub przekracza N + 2. Ten wektor zostanie wypełniony wartościami liczbowymi, zwinięty w spiralę (dlatego jego długość musi być idealnym kwadratem), a następnie wartości liczbowe zostaną zastąpione znakami.

Niech n oznacza każdy krok, zaczynając od 1 w środku spirali. Kroki, w których wąż się obraca, są podane przez n 2 +1 (to znaczy: 2, 5, 10, ...) dla \symboli oraz n 2 + n +1 (to znaczy: 3, 7, 13, ...) dla /. Kroki między a \i a /powinny być -, a te między /a a \powinny być |.

Wektor jest tworzony w taki sposób, że zawiera 1punkty zwrotne (2,3,5,7,10,13 ...) i 0resztę. Parzystość skumulowanej sumy mówi, czy każdy wpis powinien być a -czy |. Dodając 1 do tego wyniku, otrzymujemy wektor zawierający 1(for |) lub 2(for -). Ale to sprawia, że ​​same punkty zwrotne stają się 1lub 2też. Punkty zwrotne, których pozycje znamy, są nadpisywane: pozycje n 2 +1 są wypełnione, 3a pozycje n 2 + n +1 są wypełnione 4. Ogon i głowa są również szczególnymi przypadkami: pierwszy element wektora (ogon) jest ustawiony na 5, a element o indeksie N+2 (głowa) jest ustawione na 6. Wreszcie, elementy o indeksach przekraczających N +2 są ustawione na 0.

Przyjmując przykładowo N = 19, mamy teraz wektor o długości 25:

5 3 4 1 3 2 4 1 1 3 2 2 4 1 1 1 3 2 2 2 6 0 0 0 0

Musimy zwinąć ten wektor w spiralę. W tym celu używamy wbudowanej funkcji, która generuje macierz spiralną, po której następuje odbicie i transpozycja w celu uzyskania:

13 12 11 10 25
14  3  2  9 24
15  4  1  8 23
16  5  6  7 22
17 18 19 20 21 

Indeksowanie wektora za pomocą macierzy daje

4 2 2 3 0
1 4 3 1 0
1 1 5 1 0
1 3 2 4 0
3 2 2 2 6

gdzie 0odpowiada przestrzeni, 1odpowiada |, 2do -, 3do \, 4do /, 5do @, i 6do głowy.

Aby dowiedzieć się, który z czterech znaków ^, <, v, lub >głowa powinna mieć używamy skumulowaną sumę punktów zwrotnych, które poprzednio obliczonego. W szczególności, ostatnia ostatnia wartość tej skumulowanej sumy (tj. N + 1-ta wartość) modulo 4 mówi nam, jaki znak należy zastosować dla głowy. Bierzemy wartość przedostatnią skumulowanego sumy, nie ostatni, ze względu na wymóg „jeśli końce głowę na rogu głową <, >, ^, vma pierwszeństwo w kierunku wąż jest zakręcony”. Dla przykładu N = 19 głową jest >.

Teraz możemy zbudować ciąg zawierający wszystkie znaki wąż, w tym odpowiedniego znaku na głowie na szóstej pozycji: '|-\/@> '. Następnie indeksujemy ten ciąg za pomocą powyższej macierzy (indeksowanie jest oparte na 1 i modułowe, więc miejsce zajmuje ostatnie miejsce), co daje

/--\ 
|/\| 
||@| 
|\-/ 
\--->
Luis Mendo
źródło
1
wspaniała praca! dzięki za udział!
jacksonecac
8

Python 2, 250 233 191 bajtów

n=input()
l=[''],
a=x=0
b='@'
while a<=n:x+=1;l+=b,;l=zip(*l[::-1]);m=x%2;b='\/'[m]+x/2*'-|'[m];k=len(b);a+=k
l+=b[:n-a]+'>v'[m]+' '*(k-n+a-1),
if m:l=zip(*l[::-1])
for i in l:print''.join(i)
  • Zaoszczędź 39 bajtów dzięki @JonathanAllan

repl.it

Narysuj węża, obracając całego węża o 90º w kierunku zgodnym z ruchem wskazówek zegara i dodając dolny segment, w ten sposób wąż będzie zawsze w kierunku przeciwnym do ruchu wskazówek zegara.
Nowy segment zawsze zacznie się od \i będzie miał -ciało równe i / -nieparzyste. Segmenty rozmiary (bez rogów) są 0, 1, 1, 2, 2, 3... co jest floor(side/2).
Jeśli segment jest ostatni, usuwa nadmiar znaków, dodaje głowę i uzupełnia spacjami.

desired_size=input()
snake=[['']]
snake_size=side=0
new_segment='@'
while snake_size<=desired_size:
    side+=1
    snake+=[new_segment]
    snake=zip(*snake[::-1])
    odd_side=side%2
    new_segment='\/'[odd_side]+side/2*'-|'[odd_side]
    snake_size+=len(new_segment)
diff=desired_size-snake_size
snake+=[new_segment[:diff]+'>v'[odd_side]+' '*(len(new_segment)-diff-1)]
if odd_side:
    snake=zip(*snake[::-1])

for line in snake:print ''.join(line)
Pręt
źródło
Dobra robota! wygrałeś remis. Zobaczmy, co jeszcze wymyślą ludzie.
jacksonecac
2
Z pewnością jest to idealny język do rozwiązania tego wyzwania.
Neil
+1. Jedyną wadą jest to, że gdy głowa znajduje się na rogu, ma ona wskazywać prosto, a nie za rogiem.
Jonathan Allan
1
Zapisz 16 bajtów przez indeksowania na ciągi tak: '\/'[m], '-|'[m]i'>v'[m]
Jonathan Allan
1
Oszczędź jeszcze 1, usuwając spację między printi''.join
Jonathan Allan
7

JavaScript (ES6), 193 201 203 215 220 224

Edycja zapisany 4 bajty thx @Arnauld
Edit2 zmienił logika, a nie przechowywania bieżące przyrosty dla X i Y, po prostu je z obecnego kierunku
Edit3 uratowanie kilka bajtów, postanowiłam wykorzystać je do lepszego zarządzania pustego miejsca
Edit4 8 zapisane bajty nie podążają dokładnie za przykładami dotyczącymi kierunku głowy - podobnie jak inne odpowiedzi

Obecna wersja działa z Chrome, Firefox i MS Edge

Ta odpowiedź daje spację końcową i wiodącą (i puste linie).

n=>(t=>{for(x=y=-~Math.sqrt(++n)>>1,g=[i=t];(g[y]=g[y]||Array(x).fill` `)[x]='^<v>|-/\\@'[t?n?i-t?4+t%2:x-y?7:6:t%4:8],n--;i=i>1?i-2:++t)d=t&2,t&1?x+=d-1:y+=d-1})(0)||g.map(x=>x.join``).join`
`

Nieco mniej golfa

n=>
{
  g = [],
  // to save a few bytes, change line below (adds a lot of spaces)
  // w = ++n,
  w = -~Math.sqrt(++n)
  x = y = w>>1,
  s=c=>(g[y] = g[y] || Array(x).fill(' '))[x] = c, // function to set char in position
  s('@'); // place tail
  for (
     i = t = 0; // t increases at each turn, t%4 is the current direction
     n--;
     i = i > 0 ? i - 2 : t++ // side length increases every 2 turns
  )
     d = t & 2,
     t & 1 ? x += d-1: y += d-1
     s(!n ? '^<v>' [t % 4] // head
          : '|-/\\' [i > 0 ? t % 2 : x-y ? 3 : 2]) // body
  return g.map(x=>x.join``).join`\n`
}

f=
n=>(t=>{for(x=y=-~Math.sqrt(++n)>>1,g=[i=t];(g[y]=g[y]||Array(x).fill` `)[x]='^<v>|-/\\@'[t?n?i-t?4+t%2:x-y?7:6:t%4:8],n--;i=i>1?i-2:++t)d=t&2,t&1?x+=d-1:y+=d-1})(0)||g.map(x=>x.join``).join`
`

function update() {
  O.textContent=f(+I.value);
}

update()
<input type=number id=I value=19 oninput='update()' 
 onkeyup='update() /* stupid MS browser, no oninput for up/down keys */'>
<pre id=O>

edc65
źródło
Można zaoszczędzić kilka bajtów zastępując (' ')ze ` ` i ('@')ze`@`
Arnauld
@ Arnauld Array (2) .fill` `==> [ Array[1], Array[1] ] , while Array(2).fill(' ')==>[' ',' ']
usandfriends
@usandfriends - Prawda. Ale to nie powinno mieć znaczenia po dołączeniu.
Arnauld
@Arnauld na początku zgodziłem się z nami i przyjaciółmi, ale rzeczywiście działa. Dzięki
edc65,
@TravisJ To nie działa w Chrome, ale Firefox wydaje się działać.
Adnan
3

JavaScript (ES7), 200 bajtów

(n,s=(n*4+1)**.5|0,i=+`1201`[s%4],d=i=>`-`.repeat(i))=>[...Array(s-2>>2)].reduce(s=>`/-${d(i)}\\
${s.replace(/^|$/gm,`|`)}
|\\${d(i,i+=2)}/`,[`/\\
|@`,`/-\\
|@/`,`@`,`/@`][s%4])+`
\\${d(n-(s*s>>2))}>`

Wersja ES6 dla łatwości testowania:

f=(n,s=Math.sqrt((n*4+1))|0,i=+`1201`[s%4],d=i=>`-`.repeat(i))=>[...Array(s-2>>2)].reduce(s=>`/-${d(i)}\\
${s.replace(/^|$/gm,`|`)}
|\\${d(i,i+=2)}/`,[`/\\
|@`,`/-\\
|@/`,`@`,`/@`][s%4])+`
\\${d(n-(s*s>>2))}>`;
<input type=number min=1 oninput=o.textContent=f(this.value)><pre id=o>

Neil
źródło
Ciekawe wdrożenie. Nie myślałem o tym. Dzięki za wkład i dobrą pracę !!
jacksonecac
3

Perl, 111 110 bajtów

Obejmuje +1 dla -p

Podaj rozmiar na STDIN

snake.pl:

#!/usr/bin/perl -p
s%> %->%+s%\^ %/>%||s/
/  
/g+s%.%!s/.$//mg<//&&join"",//g,$/%seg+s/ /^/+y%/\\|>-%\\/\-|%for($\="/
\@
")x$_}{
Ton Hospel
źródło
Niesamowite! Dobra robota! Dziękujemy za pomoc!
jacksonecac
0

Partia, 563 bajty

@echo off
if %1==1 echo /@&echo v&exit/b
set w=1
:l
set/ah=w,a=w*w+w
if %a% gtr %1 goto g
set/aw+=1,a=w*w
if %a% leq %1 goto l
:g
call:d
set r=/%r%\
set/ae=h%%2,w=%1-h*w+2
for /l %%i in (1,1,%h%)do call:r
call:d
echo \%r%^>
exit/b
:d
set r=
for /l %%i in (3,1,%w%)do call set r=%%r%%-
exit/b
:r
echo %r:!=^|%
if %e%==0 set r=%r:@!=\/%
set r=%r:@/=\/%
set r=%r:!\=\-%
set r=%r:/@=\/%
set r=%r:/!=-/%
set r=%r:@!=\/%
set r=%r:/\=!@%
set r=%r:/-=!/%
if %e%==1 set r=%r:/\=@!%
set r=%r:/\=@/%
set r=%r:-\=\!%
if %e%==1 set r=%r:/\=/@%

Objaśnienie: Przypadki specjalne 1, ponieważ reszta kodu wymaga szerokości węża co najmniej dwóch. Następnie oblicza największą ćwiartkę kwadratu (dokładny kwadrat lub prostokąt 1 szerszy niż jest wysoki), którego powierzchnia jest mniejsza niż długość węża. Wąż zostanie zwinięty w ten prostokąt, zaczynając od lewego dolnego rogu i kończąc ogonem w środku, a pozostała długość będzie przebiegać pod dolną częścią prostokąta. Prostokąt jest faktycznie generowany z prostych zamian ciągów; przez większość czasu każda linia jest generowana z poprzedniej linii przez przesunięcie przekątnych o 1 krok, ale oczywiście trzeba również poradzić sobie z ogonem i istnieją niewielkie różnice w zależności od tego, czy wysokość prostokąta jest parzysta czy nieparzysta.

Neil
źródło
Niesamowite! Dziękujemy za pomoc!
jacksonecac,
-1

Python 2.7, A WIĘCEJ 1230 bajtów

Jestem nowy w Pythonie i golfie golfowym, ale czułem, że muszę odpowiedzieć na własne pytanie i dążyć ze wstydem po tym fakcie. Dużo zabawy przy tym!

def s(n):
x = []
l = 0
if n % 2 == 1:
    l = n
else:
    l = n + 1
if l < 3:
    l = 3
y = []
matrix = [[' ' for x in range(l)] for y in range(l)] 
slash = '\\'
newx = l/2
newy = l/2
matrix[l/2][l/2] = '@'
newx = newx-1
matrix[newx][newy] = slash
#newx = newx-1
dir = 'West'

for i in range(0, n-1):    
    newx = xloc(newx, dir)
    newy = yloc(newy, dir)
    sdir = dir
    dir = cd(matrix, newx, newy, dir)
    edir = dir

    if (sdir == 'West' or sdir == 'East') and sdir != edir:
        matrix[newx][newy] = '/'
    else:
        if (sdir == 'North' or sdir == 'South') and sdir != edir:
            matrix[newx][newy] = '\\'
        else:
            if dir == 'East' or dir == 'West':
                matrix[newx][newy] = '-'
            else:
                matrix[newx][newy] = '|'
newx = xloc(newx, dir)
newy = yloc(newy, dir)
sdir = dir
dir = cd(matrix, newx, newy, dir)
edir = dir
print 'eDir: ' + dir
if dir == 'North':
    matrix[newx][newy] = '^'
if dir == 'South':
     matrix[newx][newy] = 'v'
if dir == 'East':
     matrix[newx][newy] = '>'
if dir == 'West':
     matrix[newx][newy] = '<'    


p(matrix, l)

def cd(matrix, x, y, dir):    
if dir == 'North':
    if matrix[x][y-1] == ' ':
        return 'West'
if dir == 'West':
    if matrix[x+1][y] == ' ':
        return 'South'
if dir == 'South':
    if matrix[x][y+1] == ' ':    
        return 'East'
if dir == 'East':
    if matrix[x-1][y] == ' ':        
        return 'North'
return dir

def p(a, n):
for i in range(0, n):
    for k in range(0, n):
        print a[i][k],
    print ' '

def xloc(x, dir):
if dir == 'North':
    return x -1
if dir == 'West':
    return x
if dir == 'East':
    return x 
if dir == 'South':
    return x + 1
 def yloc(y, dir):
if dir == 'North':
    return y
if dir == 'West':
    return y - 1
if dir == 'East':
    return y + 1
if dir == 'South':
    return y

s(25)

https://repl.it/Dpoy

jacksonecac
źródło
5
Można to znacznie zmniejszyć, usuwając niepotrzebne spacje, znaki nowej linii, komentarze, funkcje itp.
Addison Crump,