pssssssssssssst

31

Introducción

Este es uno es bastante sencillo. Dibujaremos una serpiente en ascii. Esto se inspiró en ese viejo juego de serpientes donde tienes que recolectar la fruta y crecer continuamente.

Definición

Dado un número entero positivo N que representa la longitud de la serpiente, dibuja una serpiente para que tenga un cuerpo de n más una cabeza y una cola.

Partes:

  • cabeza: <, >, ^, v
  • cola: @
  • vertical: |
  • horizontal -

Todas las esquinas deben estar satisfechas con a \o /respectivamente. A menos que la cabeza termine en una esquina, en cuyo caso la cabeza <, >, ^, vtiene prioridad en la dirección de la serpiente. es decir, para el ejemplo de longitud 1, se gira en sentido antihorario y, por lo tanto, la cabeza se gira de esa manera. Para una solución en el sentido de las agujas del reloj, estaría a la derecha >.

La serpiente debe comenzar en el medio con su cola, pero puede ir hacia afuera en cualquier dirección que elija, ya sea en sentido horario o antihorario. También debe envolverse firmemente alrededor de sí mismo a medida que se expande hacia afuera de manera circular.

Ejemplo

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

Donde @está la cola y la posición inicial. Como se ve arriba, la cola comienza en el medio, sube hacia la izquierda en una rotación hacia la izquierda.

Aquí la longitud es 19más una cola y una cabeza.

Como otro ejemplo, aquí está la longitud 1:

<\
 @

Victorioso

Este es el código de golf, por lo que la respuesta que se envía con el menor número de bytes gana, con tiempo para ser utilizado como desempate.

¡Que te diviertas!

jacksonecac
fuente
2
No está muy claro que no solo se me permita dibujar una serpiente recta como @---->. Probablemente intente condiciones más estrictas sobre la forma de la serpiente. También aclare cuánto espacio en blanco está permitido o no
Ton Hospel
1
"La serpiente debe comenzar en el medio con su cola, pero puede ir hacia afuera en la dirección que elija y en sentido horario o antihorario"
jacksonecac
1
Entonces digo que @es el medio (posible agregar algunos espacios para que sea así), declarar "a la derecha" como la dirección y hacer que la cabeza apunte hacia abajo y declarar eso en el sentido de las agujas del reloj. Sus términos pueden parecerle claros, pero en realidad son ambiguos. Me doy cuenta de que probablemente te refieres a una serpiente enrollada lo más apretada posible, pero debes dejar eso claro
Ton Hospel el
1
No te preocupes Ese es mucho más difícil debido a las compensaciones en ese desafío.
Martin Ender
2
¡Buen primer desafío! Bienvenido al sitio!
Luis Mendo

Respuestas:

10

MATL , 85 83 bytes

Y pensé que tener un spiralbuiltin sería un código corto ...

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

Pruébalo en línea!

Explicación

Deje N denotar la entrada. Crearemos un vector de longitud ceil(sqrt(N+2))^2, es decir, el cuadrado perfecto más pequeño que sea igual o superior a N +2. Este vector se rellenará con valores numéricos, se enrollará en espiral (es por eso que su longitud debe ser un cuadrado perfecto), y luego los valores numéricos serán reemplazados por caracteres.

Deje n denotar cada paso comenzando desde 1 en el centro de la espiral. Los pasos donde gira la serpiente están dados por n 2 +1 (es decir: 2, 5, 10, ...) para \símbolos yn 2 + n +1 (es decir: 3, 7, 13, ...) para /. Los pasos entre a \y a /deberían ser -, y aquellos entre a /y a \deberían ser |.

El vector se crea de tal manera que contiene 1en los puntos de giro (2,3,5,7,10,13 ...) y 0en el resto. La paridad de la suma acumulativa indica si cada entrada debe ser a -o a |. Sumando 1 a este resultado obtenemos un vector que contiene 1(para |) o 2(para -). Pero esto hace que los puntos de giro se conviertan 1o 2también. Entonces, los puntos de giro, cuyas posiciones sabemos, se sobrescriben: las posiciones n 2 +1 se llenan 3y las posiciones n 2 + n +1 se llenan 4. La cola y la cabeza también son casos especiales: el primer elemento del vector (cola) se establece en 5, y el elemento con índice N+2 (cabeza) se establece en 6. Finalmente, los elementos con índices que exceden N +2 se establecen en 0.

Tomando la entrada N = 19 como ejemplo, ahora tenemos un vector con longitud 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

Necesitamos rodar este vector en una espiral. Para esto, utilizamos una función integrada que genera una matriz en espiral, seguida de una reflexión y una transposición para producir:

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 

La indexación del vector con la matriz da

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

donde 0corresponde al espacio, 1corresponde a |, 2a -, 3a \, 4a /, 5a @y 6a la cabeza.

Para saber cuál de los cuatro caracteres ^, <, v, o >la cabeza debe tener, utilizamos la suma acumulada de los puntos de giro que hemos calculado previamente. Específicamente, el penúltimo valor de esta suma acumulativa (es decir, el valor N + 1-ésimo) módulo 4 nos dice qué carácter debe usarse para la cabeza. Tomamos el penúltimo valor de la suma acumulativa, no el último, debido a la exigencia "si los extremos de la cabeza en una esquina de la cabeza <, >, ^, vtiene prioridad en la dirección está curvado a la serpiente". Para el ejemplo N = 19, la cabeza es >.

Ahora podemos construir una cadena que contiene todos los caracteres de serpientes, incluyendo el carácter apropiado para la cabeza en la sexta posición: '|-\/@> '. Luego indexamos esta cadena con la matriz anterior (la indexación se basa en 1 y es modular, por lo que el espacio es el último), lo que da

/--\ 
|/\| 
||@| 
|\-/ 
\--->
Luis Mendo
fuente
1
¡trabajo asombroso! ¡Gracias por participar!
jacksonecac
8

Python 2, 250 233 191 bytes

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)
  • Guardado 39 bytes gracias a @JonathanAllan

repl.it

Dibuje la serpiente girando la serpiente entera 90º en sentido horario y agregando el segmento inferior, de esta manera la serpiente siempre estará en sentido antihorario.
El nuevo segmento siempre comenzará \y tendrá -cuerpo para los lados pares y / -los lados impares. Los tamaños de los segmentos (sin esquinas) son 0, 1, 1, 2, 2, 3... que es floor(side/2).
Si el segmento es el último, elimina el exceso de caracteres, agrega la cabeza y completa con espacios.

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)
Barra
fuente
¡Buen trabajo! tienes el ganador del desempate. Veamos qué más se le ocurre a la gente.
jacksonecac
2
Seguramente este es el lenguaje ideal para resolver este desafío.
Neil
+1. La única falla es que cuando la cabeza está en una esquina, debe apuntar en línea recta, no a la vuelta de la esquina.
Jonathan Allan
1
Guardar 16 bytes de indexación en las cadenas de este modo: '\/'[m], '-|'[m]y'>v'[m]
Jonathan Allan
1
Ahorre 1 más eliminando el espacio entre printy''.join
Jonathan Allan
7

JavaScript (ES6), 193 201 203 215 220 224

Editar 4 bytes guardados thx @Arnauld
Edit2 cambió la lógica, no almacenando los incrementos actuales para x e y, solo
consíguelos desde la dirección actual Edit3 habiendo guardado algunos bytes, decidí usarlos para una mejor gestión del espacio en blanco
Edit4 8 bytes guardados que no siguen exactamente los ejemplos sobre la dirección de la cabeza, como otras respuestas

La versión actual funciona con Chrome, Firefox y MS Edge

Esta respuesta da un poco de espacio inicial y final (y líneas en blanco).

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

Ligeramente menos golfizado

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
fuente
Puede guardar algunos bytes reemplazando (' ')con ` ` y ('@')con`@`
Arnauld
@Arnauld Array (2) .fill`` ==> [ Array[1], Array[1] ], while Array(2).fill(' ')==>[' ',' ']
usandfriends
@usandfriends - Cierto. Pero eso no debería hacer ninguna diferencia una vez unido.
Arnauld
@Arnauld al principio estuve de acuerdo con nosotros y amigos, pero de hecho funciona Gracias
edc65
@TravisJ No funciona en Chrome, pero Firefox parece funcionar.
Adnan
3

JavaScript (ES7), 200 bytes

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

Versión ES6 para facilitar las pruebas:

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
fuente
Interesante implementación. No había pensado en hacer eso. ¡Gracias por contribuir y buen trabajo!
jacksonecac
3

Perl, 111 110 bytes

Incluye +1 para -p

Dar tamaño en STDIN

snake.pl:

#!/usr/bin/perl -p
s%> %->%+s%\^ %/>%||s/
/  
/g+s%.%!s/.$//mg<//&&join"",//g,$/%seg+s/ /^/+y%/\\|>-%\\/\-|%for($\="/
\@
")x$_}{
Ton Hospel
fuente
¡Increíble! ¡Buen trabajo! ¡Gracias por contribuir!
jacksonecac
0

Lote, 563 bytes

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

Explicación: Los casos especiales 1 como el resto del código requieren un ancho de serpiente de al menos dos. Luego, calcula el cuarto de cuadrado más grande (ya sea un cuadrado exacto o un rectángulo 1 más ancho que alto) cuya área es menor que la longitud de la serpiente. La serpiente se enrollará en este rectángulo comenzando en la esquina inferior izquierda y terminando con la cola en el medio, y la longitud restante se ejecutará debajo de la parte inferior del rectángulo. El rectángulo se genera realmente a partir de reemplazos de cadena simples; La mayoría de las veces cada línea se genera a partir de la línea anterior moviendo las diagonales 1 paso, pero obviamente la cola también tiene que ser tratada, y existen pequeñas diferencias dependiendo de si la altura del rectángulo es par o impar.

Neil
fuente
¡Increíble! ¡Gracias por contribuir!
jacksonecac
-1

Python 2.7, A WHOPPING 1230 bytes

Soy nuevo en Python y Code Golf, pero sentí que tenía que responder a mi propia pregunta y enfurruñarme de vergüenza después del hecho. Sin embargo, ¡es muy divertido trabajar en ello!

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
fuente
55
Esto se puede reducir masivamente simplemente eliminando espacios innecesarios, líneas nuevas, comentarios, funciones, etc.
Addison Crump