Peregrinação de paridade primária

44

O objetivo deste desafio é representar graficamente uma caminhada no plano, onde a direção de cada etapa é determinada pela primalidade de pela paridade de sua expansão binária. Especificamente,kk

  • A direção inicial é fixa, digamos Norte.
  • Todas as etapas têm o mesmo comprimento .
  • A direção da etapa pode ser norte, oeste, sul ou leste e é determinada da seguinte maneira: k
    • Se não for primo, a direção não muda.k
    • Se for primo e a expansão binária de tiver um número par de unidades, vire à direita.kk
    • Se for primo e a expansão binária de tiver um número ímpar de unidades, vire à esquerda.kk

Como exemplo , assuma que a direção inicial é Norte. Os primeiros passos são:

  • k=1 não é primo. Então, avançamos um passo na direção atual, que é o norte.
  • k=2 é primo e sua expansão binária,, 10tem e número ímpar de unidades. Então, vire à esquerda e agora estamos de frente para o oeste. Nós damos um passo nessa direção.
  • k=3 é primo e sua expansão binária,, 11tem e número par de unidades. Então, viramos à direita e agora estamos voltados para o norte. Nós damos um passo nessa direção.
  • k=4 não é primo. Então, avançamos um passo na direção atual, que é o norte.

O desafio

Entrada : positivo inteiro .N

Saída : plotagem da caminhada step, conforme definido acima.N

Regras adicionais

  • A direcção inicial pode ser livremente escolhida (e não necessariamente do Norte), mas deve ser a mesma para todos os .N
  • A regra de giro pode ser oposta à descrita acima, ou seja, vire à direita para paridade ímpar e à esquerda para par; mas tem que ser o mesmo para todos os .N
  • A saída deve ser uma representação gráfica da caminhada. Por exemplo:
    • A caminhada pode ser desenhada com segmentos de linha.
    • Os pontos visitados podem ser mostrados com um marcador, como um ponto; com ou sem conectar segmentos de linha.
    • É possível fornecer uma imagem rasterizada de duas cores, uma cor correspondente aos pontos visitados e outra para os não visitados.
  • As escalas dos eixos horizontal e vertical não precisam ser as mesmas. Também etiquetas de eixo e elementos semelhantes são opcionais. Desde que a caminhada possa ser vista com clareza, o enredo é válido.
  • Observe que alguns pontos são visitados mais de uma vez. O enredo não é sensível a isso. Por exemplo, se os segmentos de linha são mostrados no gráfico, cada segmento de unidade é exibido da mesma forma, não importando quantas vezes ele foi percorrido.
  • O código deve funcionar para quaisquer Nrecursos ilimitados. É aceitável se, na prática, falhar bastante Ndevido a limitações de tempo, memória ou tipo de dados.
  • Entrada e saída são flexíveis, como de costume. Em particular, qualquer um dos meios padrão para a saída de imagens pode ser usado.
  • O código mais curto em bytes vence.

Casos de teste

Os seguintes gráficos usam o Norte como direção inicial; até a paridade vira à direita; e a caminhada é representada com segmentos de linha.

N = 7:

insira a descrição da imagem aqui

N = 3000:

insira a descrição da imagem aqui

N = 20000:

insira a descrição da imagem aqui

N = 159000:

insira a descrição da imagem aqui

N = 1200000:

insira a descrição da imagem aqui

N = 11000000:

insira a descrição da imagem aqui

Luis Mendo
fonte
1
Existe uma razão para apenas [graphical-output]é permitida? Alguma razão em particular para a saída ASCII não permitida, como a minha resposta agora excluída do carvão vegetal?
Kevin Cruijssen 24/06
2
@ Kevin Fui aconselhado uma vez a não misturar os dois no mesmo desafio ... O que os outros pensam?
Luis Mendo
1
Bem, eu posso entender o raciocínio por trás desse conselho, já que a saída como imagem / gráfico versus arte ASCII é completamente diferente em alguns idiomas. Então, novamente, eu vi saídas de gráficos recebendo muitos upvotes nos desafios da arte ASCII e vice-versa, então acho que nem todos concordam. Pessoalmente, acho que depende realmente do desafio. Nesse caso, pessoalmente, não vejo mal em permitir os dois no mesmo desafio, mas talvez eu seja parcial devido à minha resposta agora excluída. Então, eu vou fazer a mesma pergunta como você: " O que os outros pensam " @Arnauld Talvez você deve postar sua ASCII Taxi Driver depois de tudo;)
Kevin Cruijssen
1
Seria interessante ver essa execução em várias seqüências OEIS (é verdade, algumas apenas andam em linha reta ou em círculos, mas algumas podem ser algo bastante).
Draco18s 24/06
16
Em N = 11000000, parece estar se aproximando do mapa da Europa.
Digital Trauma

Respostas:

12

Marreta 0.4 , 22 20 bytes

⢂⡐⠥⡄⠡⢒⣩⣀⣼⡝⢄⡎⣛⠅⡉⣱⡆⢀⡠⣽

Descomprime nesta função da Wolfram Language:

ListPlot[AnglePath[Array[If[PrimeQ@#, ArcSin[(-1)^ThueMorse@#], 0] &, #]]]

Ungolfed

Primeiro, definimos uma função que retorna o ângulo para girar a cada passo:

If[PrimeQ[#],
    ArcSin[(-1)^ThueMorse@#],
    0
]&

ThueMorseé a paridade da soma dos dígitos binários. Usamos, -1^(...)e não 2*...-1por uma razão um pouco complicada: a Wolfram Language converte automaticamente expressões aritméticas na fonte em uma forma canônica, para que expressões como 2/xsejam armazenadas como Times[2, Power[x, -1]]. Isso faz com que a frequência seja Powermuito alta e, portanto, a comprime muito barato.

(A multiplicação Boole@PrimeQ@é um pouco mais longa e a Booleconversão implícita de booleanos não havia sido implementada no momento do desafio.)

A partir daqui, do Mathematica AnglePathe ListPlotfaça exatamente o que precisamos:

ListPlot[AnglePath[Array[%, #]]]&

No aplicativo interativo, a saída é um objeto gráfico vetorial escalável.

insira a descrição da imagem aqui

lirtosiast
fonte
Legal! Cheguei a 77 bytes combinando nossas soluções. Felicidades!
Roman
14

MATL , 25 24 21 bytes

Q:qJyZpbB!sEq*^YpYsXG

Experimente no MATL online

Obrigado a @LuisMendo por uma boa sessão de golfe no chat que finalmente levou a esta versão de 21 bytes, sugerindo Eq*^

Explicação

Q:q % Push 0:n
J   % Push 1i for later use.
y   % Duplicate 0:n from below
Zp  % Vector result of isprime()
b   % Bubble 0:n from bottom of stack
B!s % Sum of bits in binary representation
Eq  % Double minus one to get an odd number
*   % Multiply by isprime result to get either zero or aforementioned odd number
^   % Exponentiate 1i by an odd number or zero to get -i, 1 or i (corresponding to left turn, straight ahead, right turn).
Yp  % Cumulative product to get a vector of directions
Ys  % Cumulative sum to get vector of positions
XG  % Plot

Exemplo para : k=12345insira a descrição da imagem aqui

Sanchises
fonte
8

C (gcc) , 179 bytes

o;i;d;k;h;f(n,p)char*p;{h=2*n+1;memset(p,0,h*h);p+=h--*n+n;*p=1;for(d=k=0;k++<n;){for(i=1;k%++i%k;);for(o=k;o/2;o=o/2^o&1);i==k?d+=o*2+3:0;p+=(d%2*h+1)*((d&2)-1);*p=1;}return++h;}

Experimente online!

Uma função. O primeiro argumento é N, o segundo argumento é um buffer de tamanho alocado de pelo menos bytes. Uma imagem quadrada é gravada nesse buffer, seu comprimento lateral é retornado. Na imagem, é um pixel branco, é um pixel preto.4n2+4n+101

C (gcc) , 219 bytes

o;i;d;k;h;f(n,p)char*p;{h=2*n+1;p+=sprintf(p,"P1 %d %d ",h,h);memset(p,48,h*h);k=h--*n+n;*(p+2*k+1)=0;p+=k;*p=49;for(d=k=0;k++<n;){for(i=1;k%++i%k;);for(o=k;o/2;o=o/2^o&1);i==k?d+=o*2+3:0;p+=(d%2*h+1)*((d&2)-1);*p=49;}}

Experimente online!

Uma função. O primeiro argumento é N, o segundo argumento é um buffer de tamanho alocado pelo menos bytes. Uma imagem quadrada no formato PBM é gravada no buffer.4n2+4n+2×log10(2n+1)+9

Produção cortada para 20000:

produção cortada para 20000

Ambas as versões começam com o oeste e vire à direita no ímpar, à esquerda no par.

Tentei os casos de teste maiores com nenhum deles, já que a saída com 20000 era de ~ 1,5 GB e 150000 teria sido de ~ 90 GB. Tudo isso é armazenado na memória enquanto o programa é executado.

Explicação da parte superior:

o;         /* Temporary variable for calculating parity */
i;         /* Temporary variable for primality test */
d;         /* d % 4 = direction */
k;         /* Step */
h;         /* height/width of image */
f(n,p)char*p;{ /* Function taking int and char pointer */
  h=2*n+1;     /* Image sidelength = 2 * N + 1, so N in each direction */
  memset(p,0,h*h); /* Reset buffer */
  p+=h--*n+n;  /* Position p at image center; decrement h */
  *p=1;        /* Put a dot at center */
  for(d=k=0;   /* Set direction and step to 0 */
    k++<n;){   /* Loop over [1..N] */
    for(i=1;k%++i%k;); /* Primality test */
    for(o=k;o/2;o=o/2^o&1); /* Parity test */
    i==k?d+=o*2+3:0; /* Change direction if necessary */
    p+=(d%2*h+1)*((d&2)-1); /* Move according to direction */
    *p=1; /* Set pixel to black */
  }
  return++h; /* Add 1 back to h and return */
}
wastl
fonte
1
Eu não acho que exigir que um buffer alocado seja fornecido como argumento é permitido - por meta-política , qualquer entrada extra deve estar vazia (o que eu interpretaria como 0ponteiro médio ou nulo no caso de C).
Maçaneta
3
Estou interpretando isso como dizendo que posso esperar que seja alocado. Esse também é um padrão usado em muitas funções padrão da biblioteca, como sprintf.
wastl 24/06
Ah, ok, você está certo, isso faz sentido.
Maçaneta
162 bytes
ceilingcat
8

Wolfram Language (Mathematica) , 98 96 91 77 76 63 bytes

ListPlot@AnglePath@Array[Pi/2If[PrimeQ@#,2ThueMorse@#-1,0]&,#]&

-14 bytes: obrigado a @lirtosiast por me mostrar como usarAnglePath ...

-13 bytes: ... e ThueMorse!

exemplo de uso:

%[20000]

insira a descrição da imagem aqui

Explicação passo a passo:

  • If[PrimeQ@#, 2 ThueMorse@# - 1, 0] &é uma função que pega o índice da etapa e retorna 0 para não primos, -1 para primos binários pares e +1 para primos binários ímpares. ThueMorse@#substitui a solução anterior Total[#~IntegerDigits~2](que é a mesma, módulo 2).

  • Array[Pi/2*%,#]faz uma lista dessa função com o índice passando de 1 para o argumento da função (20000 no exemplo) e multiplica cada elemento por π / 2 para transformá-lo em um ângulo de mudança de direção (radianos). Agora temos 0 para não primos, -π / 2 para primos binários pares e + π / 2 para primos binários ímpares.

  • AnglePath[%]converte esta lista de ângulos de mudança de direção em um caminho. Esta instrução substitui o uso duplo da solução anterior Accumulate.

  • ListPlot[%]converte a lista de posições em um gráfico de pontos XY. Se uma linha for preferida, use ListLinePlot. Essas funções de plotagem têm muitas opções para melhorar a aparência das plotagens.

romano
fonte
1
Obrigado @lirtosiast! É como aprender uma língua estrangeira: novo vocabulário todos os dias.
Roman
7

MATL, 31 30 28 26 bytes

J4:^0i:Zpl_G:B!s^*hYs)YsXG

3 bytes salvos graças a @LuisMendo

2 bytes economizados graças a @Sanchises

Experimente no MATL Online

Explicação

Esta solução usa números complexos para representar os componentes X e Y do plano 2D

J      % Push the literal complex number 0 + 1j to the stack
4:     % Create the array [1, 2, 3, 4]
^      % Raise 0 + 1j to each power in the array, [1, 2, 3, 4]

Neste ponto, temos quatro pontos ( (0, 1), (-1, 0), (0, -1), (1, 0)) em uma matriz representada por números complexos. Estas são as quatro direções cardeais. Agora queremos usá-los para "andar".

Essencialmente, a maneira como isso funciona é que começamos a dirigir na direção zero (o elemento 0 da matriz que é (-1, 0)). Para cada etapa, precisamos determinar a alteração nesse cabeçalho. Usaremos números inteiros para rastrear essa alteração. Se queremos virar "para a direita", incrementamos esse número inteiro em 1 (referenciando o próximo elemento na matriz de 4 pontos) e, se queremos ir para a "esquerda", decrementamos esse número inteiro em 1 (referenciando o elemento anterior no Matriz de 4 pontos). Se queremos continuar em nosso caminho, mantemos o valor inteiro constante (referenciando o mesmo elemento na matriz de 4 pontos).

Esta parte do código cria uma matriz de todos aqueles 0, -1e 1valores.

0      % Push a literal 0 to the stack (the starting point)
i      % Explicitly grab the input (N)
:      % Create an array from 1...N
Zp     % Determine if each element is a prime (1) or not (0)
l_     % Push the literal -1 to the stack
G      % Explicitly grab the input again (N)
:      % Create an array from 1...N
B      % Convert to binary representation (each row is the binary representation of
       % each element in the vector)
!      % Transpose
s      % Sum down the columns to count number of 1's
^      % Raise the -1 to each element. For odd number of 1's in the
       % binary expansion this yields -1, and even yields 1

*      % Multiply this -1 or 1 by the result of the prime check (element-wise). 
       % For non-primes this yields a 0, for primes with an even number of 1's in 
       % the binary representation this is a 1, and for primes 
       % with an odd number of 1's in

h      % Horizontally concatenate with the initial 0

Agora, temos uma matriz de diferenças entre números inteiros sucessivos, para que possamos calcular a soma acumulada dessas para obter os índices que podemos usar para procurar a direção em cada etapa da matriz original de 4 elementos.

Convenientemente, o MATL possui uma indexação abrangente, de modo que o índice se 5aproxima do início de uma matriz de 4 elementos. Podemos usar isso para nossa vantagem, para que possamos incrementar e decrementar esse número inteiro sem nos preocupar com o fato de que a matriz de direção de referência é de apenas 4 elementos.

Ys     % Compute the cumulative sum
)      % Use this to modularly index into the original array of four points

Agora temos uma variedade de direções de etapas, para que possamos calcular a soma cumulativa dessas instruções para traçar o caminho que foi seguido.

Ys     % Compute the cumulative sum
XG     % Plot as a 2D plot
Suever
fonte
5

Perl 6 , 213181 bytes

{my @p = [\ +] [\ *] ({{. is-prime ??. base (2) .comb (~ 1)% 2 ?? i !! - i !! 1 + 0i} (+ + $)} ... *) [^ $ _]; {"<svg viewBox = '{. min xx 2, .elems xx 2}' >>. & {" L {.re} {.im} " }} 'fill =' none 'stroke =' black '/> "} (minmax | @p» .reals)}

{{"<svg viewBox='{{.min,.min,+$_,+$_}(.minmax)}'><path d='{"L"X~$_}' fill='none' stroke='red'/></svg>"}(([\+] [\*]({-{.is-prime*.base(2).comb(~1)R**-1||i}(++$)i}...*)[^$_])».reals)}

Experimente online!

(Realmente conseguiu reduzir este aqui!)

Esta função gera no formato SVG.

  • { -{ .is-prime * .base(2).comb(~1) R** -1 || i }(++$)i } ... *é uma sequência infinita de mudanças de direção para cada etapa, na forma de números complexos, em que 1significa "continue na mesma direção", isignifica "vire à esquerda" e -isignifica "vire à direita".
  • [^$_] limita essa sequência ao número de etapas fornecidas como argumento da função.
  • [\*] digitaliza essa sequência com multiplicação (complexa), transformando a lista de mudanças de direção relativa em uma lista de direções absolutas.
  • [\+]varre essa sequência com adição (complexa), produzindo uma lista das coordenadas visitadas.
  • ».reals converte essa lista de números complexos em listas de dois elementos de suas partes reais e imaginárias.

A imagem SVG é apenas um único pathelemento.

Saída (convertida em PNG) para N = 20000:

caminho para N = 20000

Sean
fonte
4

C, 321 bytes

a,b,A,B,k,p,e,i,t,r;g(n,c,d,x,y,X,Y){x=y=Y=r=0;X=1;for(k=0;k++<=n;){r|=x==c&y==d;a=x<a?x:a;A=x>A?x:A;b=y<b?y:b;B=y>B?y:B;for(p=1,i=k;--i;p=p*i*i%k);for(e=1,i=k;i;e=-e)i&=i-1;if(p)t=X,X=-e*Y,Y=e*t;x+=X;y+=Y;}}f(n,x,y){A=a=B=b=0;g(n);printf("P1%d %d ",A-a+1,B-b+1);for(y=b;y<=B;++y)for(x=a;x<=A;++x)g(n,x,y),putchar(48+r);}

Experimente online!

Comecei a trabalhar nisso antes que a outra resposta C fosse publicada, mas achei que também poderia postar a minha. Essa é muito mais longa, mas também recorta a imagem de saída nas dimensões do resultado automaticamente.

A função é chamada como f(n)e a saída é stdout no formato netpbm.

Exemplo de saída para n = 1000:

a,b,A,B,          // used to store x range [a,A] and y range [b,B]
k,p,e,i,t,        // temp variables used in g
r;g(n,c,d,        // takes n + coordinates, sets r to whether (c,d) is visited
x,y,X,Y){         // temp variables - position (x,y) and velocity (X,Y)
x=y=Y=r=0;X=1;    // initialization
for(k=0;k++<=n;){ // loops k over the step number
r|=x==c&y==d;     // set r to 1 if current coordinate is the requested one
a=x<a?x:a;A=x>A?x:A;b=y<b?y:b;B=y>B?y:B;    // update bounds
for(p=1,i=k;--i;p=p*i*i%k);                 // prime test
for(e=1,i=k;i;e=-e)i&=i-1;                  // parity test
if(p)t=X,X=-e*Y,Y=e*t;                      // if prime, turn accordingly
x+=X;y+=Y;}}      // move position in direction of velocity
f(n,x,y){         // main function; x and y are temp variables
A=a=B=b=0;g(n);   // obtain accurate bounds
printf("P1 %d %d\n",A-a+1,B-b+1);           // output netpbm header
for(y=b;y<=B;++y)for(x=a;x<=A;++x)          // loop through all coordinates
g(n,x,y),putchar(48+r);}                    // output 1 if visited, 0 otherwise

O teste principal é essencialmente o usado na resposta de Lynn para um desafio diferente , que se baseia no teorema de Wilson .

O teste de paridade usa uma adaptação do método de contagem de bits de Kernighan .

Como o teste principal é muito lento, e o algoritmo executa novamente toda a função de geração de caminho para cada pixel desenhado, qualquer entrada muito superior a 1000 vezes no TIO.

Maçaneta da porta
fonte
308 bytes
ceilingcat 28/06
4

LOGO, 177 171 bytes

to d:c
if :c%2[rt 180
make"c:c-1]if:c<1[stop]d:c/2
end
to p
if:c>1[make"f 2
repeat:c-2[if:c%:f<1[stop]make"f:f+1]rt 90
d:c]end
to g:n
make"c 1
repeat:n[p
fw 2
make"c:c+1]end

Para usar, fazer algo parecido com isso :

reset
pu
fw 100
pd
g 3000

Desculpe, mas não consegui capturar saída de amostra. Explicação:

to d:c
if :c%2[rt 180
make"c:c-1]if:c<1[stop]d:c/2
end

Este é um procedimento recursivo que gira 180 ° para cada bit definido em seu parâmetro, que efetivamente calcula a paridade de sua expansão binária.

to p
if:c>1[make"f 2
repeat:c-2[if:c%:f<1[stop]make"f:f+1]rt 90
d:c]end

Este é um teste de primalidade muito básico. Após o revestimento especial 1, o procedimento retornará antecipadamente se um fator for encontrado. Se, no entanto, o valor atual for considerado primo, ele vira à direita e, em seguida, usa o procedimento acima para transformar isso em uma curva à esquerda, conforme apropriado.

to g:n
make"c 1
repeat:n[p
fw 2
make"c:c+1]end

Este é apenas um loop simples para testar todos os números até a nprimalidade e mover dois pixels após cada um.

Neil
fonte
4

Geléia , 41 bytes

B§ḂḤ’×ıµ1Ẓ?€×\ÄŻÆiZ_Ṃ$€Z‘ḞŒṬµẈḢ⁾P1,;Lṭ@FK

Experimente online!

N

N=3000

Saída para N = 3000

N=300

0000000000000000000000111110000000000
0000000000000000000000100010000000000
0000001110000000000000100010000000000
0000001010000000000000100010000000000
0000001010000000000000100010000000000
0000001010000000000000100010000000000
0000001010000000111111111010000000000
0000001010000000100000101010000000000
0000001111111110100000101010000000000
0000000000100010100000101010000000000
0000000000111111100000101010001111111
0000000000000010000000101010001000001
0000000000000011100010101010001000001
0000000000000000100010101010001000001
0000111111100000100011111111111111111
0100100000100000100010001010001000001
0110100000111111100011111111111000111
0010100000000000000010101010000000101
1111100000000000000010101110000000101
1010000000000000000010100000000000101
1010000000000000000011111111111011101
1010000000000000000000100000001010101
1110000000000000000000111111101111101
0000000000000000000000000000100010101
0000000000000000000000000000100010101
0000000000000000000000000000100010101
0000000000000000000000000000111111111
0000000000000000000000000000000010100
0000000000000000000000000000000010100
0000000000000000000000000000000010100
0000000000000000000000000000000011100
Nick Kennedy
fonte
4

JavaScript - 675 668 660 632 556 534 Bytes

A primeira vez aqui no CodeGolf, começou inicialmente com ~ 1500 Bytes Code. Golfeou para menos da metade, quase mais de um terço. Sinta-se livre para continuar jogando golfe. Bytes contados com: esta ferramenta

Princípio:
Desenha em uma tela de tamanho fixo com N e comprimento de traçado variável como entrada.

Editar% s:

-07 Bytes - remove if
-08 bytes perdidos - mude para if / else
-28 Bytes - altere para tenary if / else
-76 Bytes - teste principal mais curto (tempo de execução / 3)
-22 Bytes - use esta função principal (tempo de execução * 4)

Código de golfe:

function f(e,r){for(var t=0,n=0,i=950,f=450,o=document.getElementById("d").getContext("2d"),a=1;a<=e;a++){n=iP(a)?iO(a)?1:2:0;var u=i,c=f;t==0?(t=0==n?(c=f-r,0):1==n?(u=i-r,1):(u=i+r,3)):t==1?(t=0==n?(u=i-r,1):1==n?(c=f+r,2):(c=f-r,0)):t==2?(t=0==n?(c=f+r,2):1==n?(u=i+r,3):(u=i-r,1)):(t=0==n?(u=i+r,3):1==n?(c=f-r,0):(c=f+r,2));o.beginPath(),o.moveTo(i,f),o.lineTo(u,c),o.stroke(),i=u,f=c}}function iP(h){for(i=n=h;n%--i;);return(1==i)}function iO(e){for(var r=(e>>>0).toString(2),t=0,n=0;n<r.length;n++)"1"==r[n]&&t++;return t%2!=0}

Código ungolfed com espaços em branco:

function f(e,r){
    for(var t=0,n=0,i=950,f=450,o=document.getElementById("d").getContext("2d"),a=1;a<=e;a++){

        // prime and odd/even check
        n=iP(a)?iO(a)?1:2:0;

        var u=i,c=f;

        t==0?(t=0==n?(c=f-r,0):1==n?(u=i-r,1):(u=i+r,3)):t==1?(t=0==n?(u=i-r,1):1==n?(c=f+r,2):(c=f-r,0)):t==2?(t=0==n?(c=f+r,2):1==n?(u=i+r,3):(u=i-r,1)):(t=0==n?(u=i+r,3):1==n?(c=f-r,0):(c=f+r,2));

        o.beginPath(),o.moveTo(i,f),o.lineTo(u,c),o.stroke(),
        i=u,f=c // renew old cords
    }
}

// check prime
function iP(h){
    for(i=n=h;n%--i;);
    return(1==i)
}

// check binary expression even/odd
function iO(e){
    for(var r=(e>>>0).toString(2),t=0,n=0;n<r.length;n++)
        "1"==r[n]&&t++;
    return t%2!=0
}

Exemplos:

N = 7 - Comprimento = 60

f(7, 60);
function f(e,r){for(var t=0,n=0,i=950,f=450,o=document.getElementById("d").getContext("2d"),a=1;a<=e;a++){n=iP(a)?iO(a)?1:2:0;var u=i,c=f;t==0?(t=0==n?(c=f-r,0):1==n?(u=i-r,1):(u=i+r,3)):t==1?(t=0==n?(u=i-r,1):1==n?(c=f+r,2):(c=f-r,0)):t==2?(t=0==n?(c=f+r,2):1==n?(u=i+r,3):(u=i-r,1)):(t=0==n?(u=i+r,3):1==n?(c=f-r,0):(c=f+r,2));o.beginPath(),o.moveTo(i,f),o.lineTo(u,c),o.stroke(),i=u,f=c}}function iP(h){for(i=n=h;n%--i;);return(1==i)}function iO(e){for(var r=(e>>>0).toString(2),t=0,n=0;n<r.length;n++)"1"==r[n]&&t++;return t%2!=0}
<canvas id="d" width="1900" height="900"/> 

N = 3000 - Comprimento = 4

f(3000, 4);
function f(e,r){for(var t=0,n=0,i=950,f=450,o=document.getElementById("d").getContext("2d"),a=1;a<=e;a++){n=iP(a)?iO(a)?1:2:0;var u=i,c=f;t==0?(t=0==n?(c=f-r,0):1==n?(u=i-r,1):(u=i+r,3)):t==1?(t=0==n?(u=i-r,1):1==n?(c=f+r,2):(c=f-r,0)):t==2?(t=0==n?(c=f+r,2):1==n?(u=i+r,3):(u=i-r,1)):(t=0==n?(u=i+r,3):1==n?(c=f-r,0):(c=f+r,2));o.beginPath(),o.moveTo(i,f),o.lineTo(u,c),o.stroke(),i=u,f=c}}function iP(h){for(i=n=h;n%--i;);return(1==i)}function iO(e){for(var r=(e>>>0).toString(2),t=0,n=0;n<r.length;n++)"1"==r[n]&&t++;return t%2!=0}
<canvas id="d" width="1900" height="900"/> 

N = 20000 - Comprimento = 2

f(20000, 2);
function f(e,r){for(var t=0,n=0,i=950,f=450,o=document.getElementById("d").getContext("2d"),a=1;a<=e;a++){n=iP(a)?iO(a)?1:2:0;var u=i,c=f;t==0?(t=0==n?(c=f-r,0):1==n?(u=i-r,1):(u=i+r,3)):t==1?(t=0==n?(u=i-r,1):1==n?(c=f+r,2):(c=f-r,0)):t==2?(t=0==n?(c=f+r,2):1==n?(u=i+r,3):(u=i-r,1)):(t=0==n?(u=i+r,3):1==n?(c=f-r,0):(c=f+r,2));o.beginPath(),o.moveTo(i,f),o.lineTo(u,c),o.stroke(),i=u,f=c}}function iP(h){for(i=n=h;n%--i;);return(1==i)}function iO(e){for(var r=(e>>>0).toString(2),t=0,n=0;n<r.length;n++)"1"==r[n]&&t++;return t%2!=0}
<canvas id="d" width="1900" height="900"/> 

N = 159000 - Comprimento = 1

f(159000, 1);
function f(e,r){for(var t=0,n=0,i=950,f=450,o=document.getElementById("d").getContext("2d"),a=1;a<=e;a++){n=iP(a)?iO(a)?1:2:0;var u=i,c=f;t==0?(t=0==n?(c=f-r,0):1==n?(u=i-r,1):(u=i+r,3)):t==1?(t=0==n?(u=i-r,1):1==n?(c=f+r,2):(c=f-r,0)):t==2?(t=0==n?(c=f+r,2):1==n?(u=i+r,3):(u=i-r,1)):(t=0==n?(u=i+r,3):1==n?(c=f-r,0):(c=f+r,2));o.beginPath(),o.moveTo(i,f),o.lineTo(u,c),o.stroke(),i=u,f=c}}function iP(h){for(i=n=h;n%--i;);return(1==i)}function iO(e){for(var r=(e>>>0).toString(2),t=0,n=0;n<r.length;n++)"1"==r[n]&&t++;return t%2!=0}
<canvas id="d" width="1900" height="900"/> 

pixma140
fonte
A cor depende da quantidade de linhas sobrepostas? Legal!
val
Não mudei o estilo do traçado, esse deve ser o preto padrão, sem padrão ou transparência. Encontrado aqui . Por que pode ocorrer uma mudança de cor pode estar relacionada à largura do traço que eu defini no segundo parâmetro que minha função está usando @val. Desculpe por talvez decepcioná-lo.
pixma140 25/06
3

Vermelho , 515 480 471 bytes

-1 byte graças a Kevin Cruijssen!

func[n][a: 270 x: t: u: v: w: 0 y: 1
b: copy[line 0x0 0x1]repeat i n - 1[p: on
j: i + 1 repeat k i / 2[if j%(k + 1)= 0[p: off]]if p[s: 0
until[if j% 2 = 1[s: s + 1](j: j / 2)< 1]a: a + pick[-90 90]s% 2 + 1]append b 'line 
append b as-pair x y x: x + cosine a y: y - sine a append b as-pair x y t: min x t
u: max x u v: min y v w: max y w]c: 500 /(max u - t w - v)view[base white 502x500
draw collect[foreach k b[keep either pair? k[as-pair k/1 - t * c k/2 - v * c][k]]]]]

Uma parte significativa do código (~ 160 bytes) lida com a normalização das coordenadas, para que os gráficos caibam inteiramente na tela, independentemente do tamanho da entrada.

Direção inicial: sul.

Aqui está o resultado para n = 3000

3000 iterações

n = 20000

20000

Galen Ivanov
fonte
1
Por curiosidade, por que não existem quaisquer espaços necessários para os modulos em if j%(k + 1)e if j% 2 = 1, mas há espaços necessários para a maioria dos outros operadores ( +, /, etc.). O espaço também pode ser removido no módulo de pick[-90 90]s% 2? Na verdade, por que também não há espaços necessários as-pair k/1 - t * c k/2 - v * cpara o /?
Kevin Cruijssen
1
@KevinCruijssen Sim, o espaço pode ser removido s% 2, obrigado! Não sei por que, mas o módulo %é o único operador para o qual o espaço à sua frente pode ser descartado, se precedido por uma palavra (variável). Nas as-pair k/1 - t * c k/2 - v * cbarras /servem a propósitos completamente diferentes - eles são paths. ké um paire k/1é o primeiro elemento (também pode ser selecionado por k/x, ou pick k 1). Espaços são necessários em quase todos os lugares, as exceções existem ()[]{}, porque não há ambiguidade.
Galen Ivanov
@KevinCruijssen A maioria dos símbolos pode ser usada em wordnomes ( Rednão tem variables, tudo é um wordvalor ou (ou algum bloco de sintaxe como [...]ou (...)).) Então: a*4: 45-> uma palavra a*4recebe um valor 45. %é usado como marcador para o file!tipo de dados e talvez seja por isso que não pode ser usado em wordnomes, mas pode violar as regras dos outros operadores aritméticos
Galen Ivanov
1
Ah, ok, isso faz sentido que eles /tenham um propósito diferente lá e os símbolos possam ser usados ​​sem espaços nas variáveis ​​(ou wordscomo aparentemente são chamados de Red). Obrigada pelo esclarecimento. :) E feliz por poder (principalmente acidentalmente) salvar um byte para o arquivo s% 2. :)
Kevin Cruijssen 25/06
1

Processando, mais de 140 bytes

void f(int N){for(int x,y,i,l,d,k=d=y=x=0;k++<N;d+=i<l?0:Integer.bitCount(k)%2*2-1,d&=3,point(x-=~-d%2,y+=(d-2)%2))for(i=1,l=k;0<l%++i%l;);}

Pode não cumprir claramente visto

caminhar

PrincePolka
fonte