pssssssssssssst


31

introduzione

Questo è abbastanza semplice. Disegneremo un serpente in ascii. Questo è stato ispirato da quel vecchio gioco del serpente in cui devi raccogliere i frutti e crescere continuamente.

Definizione

Dato un intero positivo N che rappresenta la lunghezza del serpente, disegna un serpente in modo che abbia un corpo di n più una testa e una coda.

Parti:

  • testa: <, >, ^, v
  • coda: @
  • verticale: |
  • horizonal: -

Tutti gli angoli dovrebbero essere soddisfatti con un \o /rispettivamente. A meno che la testa non finisca in un angolo, nel qual caso la testa <, >, ^, vha la priorità nella direzione in cui il serpente è arricciato. vale a dire per l'esempio della lunghezza 1, viene ruotato in senso antiorario e quindi la testa viene ruotata in quel modo. Per una soluzione in senso orario sarebbe a destra >.

Il serpente deve iniziare nel mezzo con la coda, ma può andare verso l'esterno in qualsiasi direzione scegliate in senso orario o antiorario. Deve anche avvolgersi strettamente su se stesso mentre si espande verso l'esterno in modo circolare.

Esempio

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

Dove @è la coda e la posizione di partenza. Come visto sopra la coda inizia nel mezzo, sale verso sinistra con una rotazione in senso antiorario verso l'esterno.

Qui la lunghezza è 19più una coda e una testa.

Come altro esempio, ecco la lunghezza 1:

<\
 @

vincente

Si tratta di code-golf, quindi vince la risposta che viene inviata con il minor numero di byte, con il tempo da utilizzare come pareggio.

Divertiti!


2
Non è molto chiaro che non mi è permesso solo disegnare un serpente dritto come @---->. Probabilmente intendi condizioni più rigide sulla forma del serpente. Inoltre chiarisci quanto spazio bianco è o non è permesso
Ton Hospel

1
"Il serpente deve iniziare nel mezzo con la coda ma può andare verso l'esterno in qualsiasi direzione scegliate e in senso orario o antiorario"
jacksonecac,

1
Quindi dico che @è il mezzo (è possibile aggiungere degli spazi per renderlo tale), dichiarare "a destra" come direzione e fare in modo che la testa sia rivolta verso il basso e dichiararla in senso orario. I termini possono sembrarti chiari, ma in realtà sono ambigui. Mi rendo conto che probabilmente intendi un serpente a spirale il più strettamente possibile, ma dovresti chiarirlo
Ton Hospel

1
Non ti preoccupare. Quello è molto più difficile a causa degli offset in quella sfida.
Martin Ender,

2
Bella prima sfida! Benvenuti nel sito!
Luis Mendo,

Risposte:


10

MATL , 85 83 byte

E ho pensato che avere un spiralbuiltin avrebbe comportato il codice funzione ...

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

Provalo online!

Spiegazione

Consenti a N di indicare l'input. Creeremo un vettore di lunghezza ceil(sqrt(N+2))^2, ovvero il quadrato perfetto più piccolo che è uguale o superiore a N +2. Questo vettore sarà riempito con valori numerici, arrotolato in una spirale (ecco perché la sua lunghezza deve essere un quadrato perfetto), quindi i valori numerici saranno sostituiti da caratteri.

Indichiamo n ogni passo a partire da 1 al centro della spirale. I passaggi in cui il serpente gira sono indicati da n 2 +1 (ovvero: 2, 5, 10, ...) per i \simboli e n 2 + n +1 (ovvero: 3, 7, 13, ...) per /. I passaggi tra a \e a /dovrebbero essere -e quelli tra a /e a \dovrebbero essere |.

Il vettore viene creato in modo tale da contenere 1nei punti di svolta (2,3,5,7,10,13 ...) e 0nel resto. La parità della somma cumulativa indica se ogni voce deve essere a -o a |. Aggiungendo 1 a questo risultato otteniamo un vettore contenente 1(per |) o 2(per -). Ma questo fa diventare 1o 2anche i punti di svolta stessi . Quindi i punti di svolta, di cui conosciamo le posizioni, vengono sovrascritti: vengono riempite le posizioni n 2 +1 3e le posizioni n 2 + n +1 4. Anche la coda e la testa sono casi speciali: il primo elemento del vettore (coda) è impostato su 5e l'elemento con indice N+2 (testa) è impostato su 6. Infine, gli elementi con indici superiori a N +2 sono impostati su 0.

Prendendo come esempio l' ingresso N = 19, ora abbiamo un vettore con lunghezza 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

Dobbiamo ruotare questo vettore in una spirale. Per questo utilizziamo una funzione integrata che genera una matrice a spirale, seguita da una riflessione e una trasposizione per produrre:

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 

Dà l'indicizzazione del vettore con la matrice

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

dove 0corrisponde allo spazio, 1corrisponde a |, 2a -, 3a \, 4a /, 5a @e 6alla testa.

Per sapere quale dei quattro personaggi ^, <, v, o >la testa deve avere, usiamo la somma cumulativa dei punti di svolta che abbiamo precedentemente calcolato. Nello specifico, il penultimo valore di questa somma cumulativa (ovvero il valore N + 1-esimo) modulo 4 ci dice quale personaggio dovrebbe essere usato per la testa. Prendiamo il penultimo valore della somma cumulativa, non ultimo, a causa del requisito "se le estremità di testa su un angolo della testa <, >, ^, vha la priorità nella direzione serpente è arricciato". Per l' esempio N = 19 la testa è >.

Ora siamo in grado di costruire una stringa che contiene tutti i caratteri di serpenti, tra cui il carattere appropriato per la testa alla sesta posizione: '|-\/@> '. Quindi indicizziamo questa stringa con la matrice sopra (l'indicizzazione è basata su 1 e modulare, quindi lo spazio va per ultimo), il che dà

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

1
lavoro fantastico! grazie per aver partecipato!
jacksonecac,

8

Python 2, 250 233 191 byte

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)
  • 39 byte salvati grazie a @JonathanAllan

repl.it

Disegna il serpente ruotando l'intero serpente di 90º in senso orario e aggiungendo il segmento inferiore, in questo modo il serpente sarà sempre in senso antiorario.
Il nuovo segmento inizierà sempre con \e avrà -come corpo per i lati pari e / -per i lati dispari. Le dimensioni segmenti (senza angoli) sono 0, 1, 1, 2, 2, 3... che è floor(side/2).
Se il segmento è l'ultimo, rimuove i caratteri in eccesso, aggiunge la testa e completa di spazi.

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)

Bel lavoro! hai vinto il tiebreaker. Vediamo cos'altro viene in mente.
jacksonecac,

2
Sicuramente questo è il linguaggio ideale per risolvere questa sfida.
Neil,

+1. L'unico inconveniente è che quando la testa è su un angolo, è destinata a puntare dritto, non dietro l'angolo.
Jonathan Allan,

1
Salva 16 byte di indicizzazione in stringhe in questo modo: '\/'[m], '-|'[m]e'>v'[m]
Jonathan Allan

1
Risparmia 1 altro rimuovendo lo spazio tra printe''.join
Jonathan Allan,

7

JavaScript (ES6), 193 201 203 215 220 224

Modifica salvati 4 byte thx @Arnauld
Edit2 ha cambiato la logica, non memorizzando gli incrementi correnti per xey, prendendoli dalla direzione corrente
Modifica3 dopo aver salvato alcuni byte, ho deciso di usarli per una migliore gestione dello spazio vuoto
Modifica4 8 byte salvati non seguendo esattamente gli esempi sulla direzione della testa - come altre risposte

La versione corrente funziona con Chrome, Firefox e MS Edge

Questa risposta fornisce uno spazio di trascinamento e iniziale (e righe vuote).

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

Leggermente meno golfato

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>


È possibile salvare alcuni byte sostituendo (' ')con ` ` e ('@')con`@`
Arnauld il

@Arnauld Array (2) .fill`` ==> [ Array[1], Array[1] ], mentre Array(2).fill(' ')==>[' ',' ']
usandfriends

@usandfriends - True. Ma ciò non dovrebbe fare alcuna differenza dopo l'adesione.
Arnauld,

@Arnauld all'inizio ho concordato con noi amici, ma funziona davvero. Grazie
edc65,

@TravisJ Non funziona in Chrome, ma Firefox sembra funzionare.
Adnan,

3

JavaScript (ES7), 200 byte

(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))}>`

Versione ES6 per facilità di test:

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>


Implementazione interessante. Non avevo pensato di farlo. Grazie per il contributo e bel lavoro !!
jacksonecac,

3

Perl, 111 110 byte

Include +1 per -p

Dare dimensioni su STDIN

snake.pl:

#!/usr/bin/perl -p
s%> %->%+s%\^ %/>%||s/
/  
/g+s%.%!s/.$//mg<//&&join"",//g,$/%seg+s/ /^/+y%/\\|>-%\\/\-|%for($\="/
\@
")x$_}{

Eccezionale! Bel lavoro! Grazie per aver contribuito!
jacksonecac,

0

Lotto, 563 byte

@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:/\=/@%

Spiegazione: Casi speciali 1 in quanto il resto del codice richiede una larghezza del serpente di almeno due. Successivamente, calcola il quarto quadrato più grande (un quadrato esatto o un rettangolo 1 più largo di quello alto) la cui area è inferiore alla lunghezza del serpente. Il serpente verrà arrotolato in questo rettangolo iniziando dall'angolo in basso a sinistra e terminando con la coda al centro, e la lunghezza rimanente scorrerà sotto il fondo del rettangolo. Il rettangolo è in realtà generato da semplici sostituzioni di stringhe; il più delle volte ogni riga viene generata dalla riga precedente spostando le diagonali di 1 passo, ma ovviamente anche la coda deve essere affrontata e ci sono lievi differenze a seconda che l'altezza del rettangolo sia pari o dispari.


Eccezionale! Grazie per aver contribuito!
jacksonecac

-1

Python 2.7, A WHOPPING 1230 byte

Sono nuovo di Python e code golf, ma sentivo di dover rispondere alla mia domanda e tenere il broncio dopo la vergogna. Molto divertente lavorarci su!

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


5
Questo può essere enormemente ridotto semplicemente rimuovendo spazi non necessari, nuove righe, commenti, funzioni, ecc.
Addison Crump
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.