pssssssssssssst

31

Introdução

Este é um é bem direto. Vamos desenhar uma cobra em ascii. Isso foi inspirado no antigo jogo de cobras, no qual você deve coletar as frutas e crescer continuamente.

Definição

Dado um número inteiro positivo N que representa o comprimento da cobra, desenhe uma cobra para que ela tenha um corpo de n mais uma cabeça e uma cauda.

Peças:

  • cabeça: <, >, ^, v
  • rabo: @
  • vertical: |
  • horizontal: -

Todos os cantos devem estar satisfeitos com um \ou /respectivamente. A menos que a cabeça termine em um canto, nesse caso, a cabeça <, >, ^, vtem prioridade na direção em que a cobra está enrolada. ou seja, no exemplo do comprimento 1, ele é girado no sentido anti-horário e, portanto, a cabeça é girada dessa maneira. Para uma solução no sentido horário, seria para a direita >.

A cobra deve começar no meio com a cauda, ​​mas pode sair em qualquer direção que você escolher no sentido horário ou anti-horário. Também deve envolver-se firmemente à sua volta, à medida que se expande para fora de forma circular.

Exemplo

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

Onde @está a cauda e a posição inicial. Como visto acima, a cauda começa no meio, sobe à esquerda em uma rotação anti-horária para fora.

Aqui o comprimento é 19mais uma cauda e uma cabeça.

Como outro exemplo, aqui está o comprimento 1:

<\
 @

Ganhando

Isso é código-golfe, então a resposta que é enviada com o menor número de bytes vence, com tempo para ser usado como desempate.

Diverta-se!

jacksonecac
fonte
2
Não está muito claro que não me seja permitido desenhar uma cobra reta @---->. Você provavelmente pretende condições mais estritas sobre o formato da cobra. Também deixam claro o quanto de espaço em branco é ou não é permitido
Ton Hospel
1
"A cobra deve começar no meio com a sua cauda, mas pode ir para fora em qualquer direção que você escolher e em sentido horário ou anti-horário"
jacksonecac
1
Então eu digo que @é o meio (é possível adicionar alguns espaços para fazê-lo), declare "à direita" como a direção e faça apenas a cabeça apontar para baixo e declarar no sentido horário. Seus termos podem parecer claros para você, mas são realmente ambíguos. Eu sei que você provavelmente significaria um tão firmemente quanto possível cobra enrolada, mas você deve deixar isso claro
Ton Hospel
1
Não se preocupe. Essa é muito mais difícil devido às compensações nesse desafio.
Martin Ender
2
Bom primeiro desafio! Bem vindo ao site!
Luis Mendo

Respostas:

10

MATL , 85 83 bytes

E eu pensei que ter um spiralbuiltin daria código curto ...

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

Experimente online!

Explicação

Deixe N denotar a entrada. Criaremos um vetor de comprimento ceil(sqrt(N+2))^2, ou seja, o menor quadrado perfeito igual ou superior a N +2. Esse vetor será preenchido com valores numéricos, rolados em espiral (é por isso que seu comprimento precisa ser um quadrado perfeito) e, em seguida, os valores numéricos serão substituídos por caracteres.

Vamos n denotam cada passo a partir de 1 no centro da espiral. As etapas em que a cobra gira são dadas por n 2 +1 (ou seja: 2, 5, 10, ...) para \símbolos en 2 + n +1 (ou seja: 3, 7, 13, ...) para /. Os passos entre a \e a /devem ser -e os entre a /e a \devem ser |.

O vetor é criado de forma que contenha 1nos pontos de virada (2,3,5,7,10,13 ...) e 0no restante. A paridade da soma acumulada informa se cada entrada deve ser a -ou a |. Adicionando 1 a este resultado, obtemos um vetor contendo 1(for |) ou 2(for -). Mas isso faz com que os pontos de virada se tornem 1ou 2também. Portanto, os pontos de virada, cujas posições conhecemos, são substituídos: as posições n 2 +1 são preenchidas 3e as posições n 2 + n +1 são preenchidas 4. A cauda e a cabeça também são casos especiais: o primeiro elemento do vetor (cauda) é definido como 5e o elemento com o índice N+2 (cabeça) está definido como 6. Por fim, os elementos com índices superiores a N +2 são definidos como 0.

Tomando a entrada N = 19 como exemplo, agora temos um vetor com comprimento 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

Precisamos rolar esse vetor em uma espiral. Para isso, usamos uma função interna que gera uma matriz espiral, seguida por uma reflexão e uma transposição para produzir:

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 

A indexação do vetor com a matriz fornece

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

onde 0corresponde ao espaço, 1corresponde a |, 2para -, 3para \, 4para /, 5para @e 6para a cabeça.

Para saber qual dos quatro personagens ^, <, v, ou >a cabeça deve ter, usamos a soma cumulativa de pontos por sua vez que nós previamente calculado. Especificamente, o segundo último valor dessa soma acumulada (ou seja, o valor N + 1-ésimo) módulo 4 nos diz qual caractere deve ser usado para a cabeça. Tomamos o segundo último valor da soma cumulativa, não o último, devido à exigência de "se as extremidades da cabeça em um canto da cabeça <, >, ^, vtem prioridade na direção da cobra está enrolado". Para o exemplo N = 19, a cabeça é >.

Agora nós podemos construir uma string contendo todos os personagens de serpentes, incluindo o personagem apropriado para a cabeça na sexta posição: '|-\/@> '. Em seguida, indexamos essa string com a matriz acima (a indexação é baseada em 1 e modular, portanto, o espaço dura por último), o que fornece

/--\ 
|/\| 
||@| 
|\-/ 
\--->
Luis Mendo
fonte
1
trabalho incrível! obrigado 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 graças a @JonathanAllan

repl.it

Desenhe a cobra girando a cobra inteira 90º no sentido horário e adicionando o segmento inferior, desta forma a cobra sempre estará no sentido anti-horário.
O novo segmento sempre começará com \e terá -como corpo os lados pares e / -os lados ímpares. Os tamanhos de segmentos (sem cantos) são 0, 1, 1, 2, 2, 3... que é floor(side/2).
Se o segmento for o último, remova os caracteres em excesso, adicione a cabeça e complete com espaços.

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)
Cajado
fonte
Bom trabalho! você tem a vitória do desempate. Vamos ver o que mais as pessoas inventam.
jacksonecac
2
Certamente esta é a linguagem ideal para resolver este desafio.
Neil
+1. A única falha é que, quando a cabeça está em um canto, ela deve apontar reta, e não ao virar da esquina.
Jonathan Allan
1
Guardar 16 bytes por indexação de strings assim: '\/'[m], '-|'[m]e'>v'[m]
Jonathan Allan
1
Economize mais 1 removendo o espaço entre printe''.join
Jonathan Allan
7

JavaScript (ES6), 193 201 203 215 215 220 224

Editar salvou 4 bytes thx @Arnauld
Edit2 mudou a lógica, não armazena os incrementos atuais para xey, basta obtê-los da direção atual
Edit3 tendo salvado alguns bytes, decidi usá-los para um melhor gerenciamento do espaço em branco
Edit4 8 bytes salvos não seguindo exatamente os exemplos sobre a direção da cabeça - como outras respostas

A versão atual funciona com Chrome, Firefox e MS Edge

Esta resposta fornece algum espaço à direita e à esquerda (e linhas em branco).

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

Um pouco menos golfe

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
fonte
Você pode salvar alguns bytes substituindo (' ')por ` ` e ('@')por`@`
Arnauld 4/16
@Arnauld Array (2) .fill` `==> [ Array[1], Array[1] ], while Array(2).fill(' ')==>[' ',' ']
usandfriends
@usandfriends - Verdadeiro. Mas isso não deve fazer diferença uma vez ingressado.
Arnauld
@ Arnauld no começo eu concordei com nós e amigos, mas funciona de fato. Graças
edc65
@ TravisJ Ele não funciona no Chrome, mas o 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))}>`

Versão ES6 para facilitar o teste:

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
fonte
Implementação interessante. Eu não tinha pensado em fazer isso. Obrigado por contribuir e bom trabalho !!
22416 Jacksonecac
3

Perl, 111 110 bytes

Inclui +1 para -p

Dê tamanho ao STDIN

snake.pl:

#!/usr/bin/perl -p
s%> %->%+s%\^ %/>%||s/
/  
/g+s%.%!s/.$//mg<//&&join"",//g,$/%seg+s/ /^/+y%/\\|>-%\\/\-|%for($\="/
\@
")x$_}{
Ton Hospel
fonte
Impressionante! Bom trabalho! Obrigado por contribuir!
21416 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:/\=/@%

Explicação: Casos especiais 1, pois o restante do código requer uma largura de cobra de pelo menos dois. Em seguida, calcula o maior quarto quadrado (um quadrado exato ou um retângulo 1 mais largo do que alto) cuja área é menor que o comprimento da cobra. A cobra será enrolada neste retângulo começando no canto inferior esquerdo e terminando com a cauda no meio, e o comprimento restante será executado sob a parte inferior do retângulo. O retângulo é realmente gerado a partir de simples substituições de string; na maioria das vezes cada linha é gerada a partir da linha anterior movendo as diagonais 1 passo, mas obviamente a cauda também precisa ser tratada, e há pequenas diferenças dependendo se a altura do retângulo é par ou ímpar.

Neil
fonte
Impressionante! Obrigado por contribuir!
11136 jacksonecac
-1

Python 2.7, A WHOPPING 1230 bytes

Eu sou novo em python e código de golfe, mas senti que tinha que responder minha própria pergunta e ficar de mau humor depois do fato. Muita diversão trabalhando nisso!

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
fonte
5
Isso pode maciçamente ser reduzida apenas através da remoção de espaços desnecessários, novas linhas, comentários, funções, etc ..
Addison Crump