Spirale triangolare di Ulam


21

Abbiamo avuto un paio di sfide sulla spirale di Ulam. Ma questo non è abbastanza.

In questa sfida tracciamo una spirale triangolare di Ulam (al contrario della solita spirale quadrata di Ulam). Ecco uno schizzo di come appare la spirale.

inserisci qui la descrizione dell'immagine

Come sappiamo, la spirale di Ulam dispone tutti i numeri naturali in una spirale esterna e segna solo quelli che sono primi. Quindi nello schizzo sopra sarebbero mostrati solo i numeri che appaiono in nero (i numeri primi).

La sfida

Accetta un numero N come input e visualizza la spirale triangolare Ulam fino a quel numero.

  • L'input può essere stdin o argomento della funzione.
  • La spirale dovrebbe girare nella direzione positiva (cioè in senso antiorario), come nella figura sopra.
  • Qualsiasi giro di 120 gradi della figura sopra sarebbe valido e il giro potrebbe essere diverso per ingressi diversi. Ma il lato più basso dei triangoli impliciti dovrebbe essere orizzontale, poiché le uniche svolte consentite sono (multipli di) 120 gradi.
  • Il codice dovrebbe essere eseguito teoricamente (con tempo e memoria sufficienti) per qualsiasi N fino a quanto consentito da qualsiasi calcolo intermedio che si esegue con il tipo di dati predefinito. doubleè abbastanza; non sono necessari tipi interi di grandi dimensioni.
  • Sono ammesse tutte le funzioni integrate.
  • Non accetterò la mia risposta (non che penso che sarebbe la più breve comunque ...).

Formati di output

Scegli una delle seguenti opzioni.

  1. Visualizza un grafico con un marcatore (punto, cerchio, croce, qualunque cosa tu preferisca) ai numeri primi e nulla ai numeri non primi. La scala non deve necessariamente essere la stessa per i due assi. Cioè, i triangoli impliciti non devono essere equilateri. Gli assi, le linee della griglia e le etichette degli assi sono opzionali. Sono richiesti solo i marcatori ai numeri primi.

    Un esempio di output per N = 12 sarebbe il seguente (confronta con lo schizzo sopra). Il secondo diagramma è un esempio più interessante, corrispondente a N = 10000.

inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine

  1. Produci un file di immagine con quanto sopra, in qualsiasi formato di immagine ben noto (come png, tiff, bmp).
  2. Mostra la spirale come arte ASCII , usando un singolo carattere a tua scelta per i numeri primi e uno spazio vuoto per i non primi, con uno spazio vuoto per separare le posizioni numeriche nella stessa riga. Sono consentiti spazi iniziali o finali o newline. Ad esempio, il caso N = 12 usando ocome carattere sarebbe

                 o
                · ·
               · o ·
                o · ·
               · o · o
    

    dove ovviamente osarebbe effettivamente visualizzato solo il segno ai numeri primi. Il ·non-primes è mostrato qui solo come riferimento.

Criterio vincente

La vera ricompensa è vedere da soli quei fantastici schemi di Code golf, il codice più corto vince.


2
In futuro, consiglierei di scegliere solo uno di [output grafico] e [ascii-art] in quanto rende le comparazioni meno comparabili. Ma bella sfida comunque. :)
Alex A.

@AlexA. Grazie! Lo terrò in considerazione. Quindi ... ci sarà una risposta di Julia? ;-)
Luis Mendo,

Wow, grazie per la generosità, ma dovresti accettare la tua risposta. Si è la più breve. :)
Martin Ender,

È meritato! Per quanto riguarda l'accettazione di una risposta, una delle regole della sfida era "Non accetterò la mia risposta". Quando ho pensato a questa sfida, avevo inevitabilmente in mente MATL, con i suoi numeri complessi e le sue funzioni grafiche, quindi era un po 'come imbrogliare :-)
Luis Mendo,

Risposte:


13

CJam, 49 42 byte

Lri{)mp0S?}%{1$,)/(a@Wf%z+\L*}h;eeSff*W%N*

Immettere come singolo numero intero in STDIN. Uscita come griglia ASCII con 0per i numeri primi. La rotazione della spirale non è coerente: il numero più grande della spirale sarà sempre nella riga inferiore.

Provalo qui.

Spiegazione

L'idea di base è quella di rappresentare il triangolo come un array 2D irregolare mentre si esegue il calcolo. Ottieni questo array invertendo le linee e allineando tutte le righe a sinistra:

   4
  5 3
 6 1 2
7 8 9 A

Sarebbe rappresentato come

[[7 8 9 A]
 [6 1 2]
 [5 3]
 [4]]

Dato che abbiamo rispecchiato la linea, vogliamo arrotolare la spirale in senso orario . È conveniente, perché tutto ciò che dobbiamo fare è ruotare il triangolo in senso antiorario e anteporre il prossimo elenco secondario in ordine. Possiamo ruotare l'array sfilacciato invertendo tutte le linee e trasponendolo:

                                                           [[B C D E F]
[[7 8 9 A]         [[A 9 8 7]           [[A 2 3 4]          [A 2 3 4]
 [6 1 2]   reverse  [2 1 6]   transpose  [9 1 5]   prepend  [9 1 5]
 [5 3]      ---->   [3 5]      ------>   [8 6]      ---->   [8 6]
 [4]]               [4]]                 [7]]               [7]]

Quindi ecco il codice. Un dettaglio a cui vorrei attirare l'attenzione è l'ultimo bit che crea il layout triangolare. Penso che sia piuttosto elegante. :)

L     e# Push an empty array. This will become the spiral.
ri    e# Read input and convert to integer N.
{     e# Map this block over 0 to N-1...
  )   e#   Increment to get 1 to N.
  mp  e#   Test for primality.
  0S? e#   Select 0 or a space correspondingly.
}%
{     e# While the list we just created is not empty yet...
  1$  e#   Copy the spiral so far.
  ,)  e#   Get the number of lines and increment.
  /   e#   Split the list into chunks of that size.
  (a@ e#   Pull off the first chunk, wrap it in an array, pull up the spiral.
  Wf% e#   Reverse the lines of the spiral.
  z   e#   Transpose the spiral.
  +   e#   Prepend the new line.
  \L* e#   Swap with the remaining chunks and join them back together into a single list.
}h
;     e# Discard the empty list that's left on the stack.
ee    e# Enumerate the spiral. This turns each line into a pair of 0-based index
      e# and the line itself.
Sff*  e# Multiply each element of each pair with a space. For the enumeration index i,
      e# this produces a string of i spaces - the required indentation (keeping in
      e# mind that our spiral is still upside down). For the line itself, this
      e# riffles the cells with spaces, creating the required gaps between the cells.
      e# All of this works because we always end the spiral on the bottom edge.
      e# This ensures that the left edge is always complete, so we don't need
      e# different indentation such as in the N=12 example in the challenge.
W%    e# Reverse the lines to make the spiral point upwards.
N*    e# Join the lines with linefeeds.

1
Sapevo che saresti stato il primo!
Luis Mendo,

@LuisMendo In realtà stavo per saltare questo, perché pensavo che il calcolo degli indici della griglia sarebbe stato noioso, ma poi mi sono reso conto che avrei potuto solo ruotare l'intero triangolo mentre aggiungevo le linee.
Martin Ender,

1
Adoro sempre le tue spiegazioni sui programmi di CJam perché riesco a capirli e sono stupito di quanto possano essere complessi, ma brevi.
ETHproductions

10

MATL , 48 36 byte

:1-H*X^.5+Y[2j3/*YP*ZeYsG:Zp)'.'2$XG

Utilizza la versione corrente (9.3.0) .

Provalo online! Non ho idea di come il compilatore online riesca a tradurre l'output grafico in ASCII, ma lo fa Questo produce un diagramma ASCII approssimativo grazie a una funzione Octave supportata dal compilatore online!

Modifica (4 aprile 2016): la funzione Y[è stata rinominata kdalla versione 13.0.0. Il collegamento al compilatore online incorpora questa modifica, in modo che il codice possa essere testato.

Esempio

>> matl
 > :1-H*X^.5+Y[2j3/*YP*ZeYsG:Zp)'.'2$XG
 > 
> 20000

produce l'output grafico (versione MATLAB mostrata):

inserisci qui la descrizione dell'immagine

Spiegazione

Il codice utilizza numeri complessi per tracciare il percorso seguito dalla spirale. Come si può vedere dalla prima figura della sfida, ogni gamba dritta della spirale è un segmento con lunghezza crescente 1, 2, 3, 4 ... e ciclicamente crescente orientamento 120 gradi, 240 gradi, 0 gradi, 120 gradi. ..

Il codice genera innanzitutto i singoli spostamenti complessi da ciascun numero intero al successivo. Questi spostamenti complessi hanno magnitudine 1 e angolo 2*pi/3, 4*pi/3o 0(in radianti). Quindi possono essere facilmente generati come esponenziali immaginari. Per questo, viene utilizzata per prima la sequenza intera 0,1,2,2,3,3,3,4,4,4,4 ...

Questa sequenza intera è quasi come la sequenza "n appare n volte" ( OEIS A002024 ) e può essere ottenuta come floor(sqrt(2*n)+.5)dove nè 0,1,2,3, .... Moltiplicando per 2j*pi/3, dove si jtrova l'unità immaginaria, si producono gli spostamenti complessi desiderati.

Gli spostamenti vengono accumulati per calcolare le posizioni corrispondenti ai numeri interi nella spirale. Il primo numero intero nella spirale, che è 1, si trova arbitrariamente in posizione 1nel piano complesso.

Infine, le posizioni corrispondenti ai numeri non primi vengono scartate e il resto viene tracciato sul piano complesso.

:1-H*X^.5+Y[     % floor(sqrt(2*n)+.5) for n from 0 to N-1, where N is implicit input
2j3/*YP*Ze       % exp(2j*pi/3* ... )
Ys               % cumulative sum. Produces complex positions
G:               % vector 1,2...,N, where N is previous input
Zp               % logical index to select only prime numbers
)                % use that index to keep only complex positions of primes
'.'2$XG          % plot using marker '.'

Cosa devo leggere ancora di più
Brain Guider,

Lo prova online! supportare l'output grafico per MATL?
Alex A.

Pensavo che TIO non supportasse l'output grafico? In tal caso, posso facilmente avere MATL che scarica automaticamente le immagini in un .pngfile per essere mostrato dalla pagina web @AlexA
Luis Mendo,

Hey! Ho fatto test semplice ( plot(1:5)) e produce output di testo grafico !! matl.tryitonline.net/#code=NTpYRw&input= @AlexA. Com'è questo??
Luis Mendo,

4
Whoa! È fantastico!
Alex A.

8

Il disegno dovrebbe essere fatto con

LaTeX / PGF, 527 594 byte

\documentclass{standalone}\usepackage{pgf}\let\z\let\z\e\advance\z\f\ifnum\z\h\the\z\a\newcount\a\i\a\j\a\l\a\x\a\y\a\p\a\q\a\n\i=1\l=1\p=-1\q=1\def\m#1{\e\i by1\e\j by1\e\x by\h\p\e\y by\h\q\pgfmathparse{isprime(\h\i)}\f\pgfmathresult=1\pgfpathcircle{\pgfpoint{\h\x cm}{\h\y cm}}3pt\fi\f\j=\l\e\l by1\j=0\f\p=1\p=-1\q=1\else\f\p=-1\p=0\q=-1\else\p=1\q=0\fi\fi\fi\f#1>0\e#1by-1\m#1\fi}\begin{document}\begin{pgfpicture}\pgftransformcm10{cos(60)}{sin(60)}\pgfpointorigin\n=4000\m\n\pgfusepath{fill}\end{pgfpicture}\end{document}

527 byte è il documento completo come sopra, cioè includendo il preambolo e il parametro (qui 4000, quindi ~ 523 senza parametro). Produce un file PDF.

Idea di base: beh, basta disegnare. Utilizza una trasformazione matrice per una griglia triangolare. L'unico problema è che anche i punti sono influenzati (e allungati) dalla trasformazione. Quindi scelgo per i marcatori di ellisse :) cosa intendo con ciò è chiaro nella seconda immagine (n = 250, 5pt).

Un altro avvertimento: può gestire solo un po 'meno di 5000 a causa della dimensione massima dello stack di TeX. La prima immagine è per n = 4000. Apparentemente è possibile aumentare le dimensioni dello stack , non l'ho provato.

Utilizza PGF isprime().

inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine

Ungolfed:

\documentclass[border=10cm]{standalone}

\usepackage{pgf}

\newcount\ulami
\newcount\ulamj
\newcount\ulamlen

\newcount\ulamx
\newcount\ulamy
\newcount\ulamdx
\newcount\ulamdy

\ulami=1 %
\ulamj=0 %
\ulamlen=1 %
\ulamdx=-1 %
\ulamdy=1 %
\ulamx=0 %
\ulamy=0 %

\def\ulamplot#1{%
  \advance\ulami by 1 %
  \advance\ulamj by 1 %

  \advance\ulamx by \the\ulamdx %
  \advance\ulamy by \the\ulamdy %

  \pgfpathmoveto{\pgfpoint{\the\ulamx cm}{\the\ulamy cm}}

  \pgfmathparse{isprime(\the\ulami)}
  \let\r=\pgfmathresult
  \ifnum\r=1
    \pgfpathcircle{\pgfpoint{\the\ulamx cm}{\the\ulamy cm}}{5pt}
  \fi

  \ifnum\ulamj=\the\ulamlen %
    \advance\ulamlen by 1 %
    \ulamj=0 %
    \ifnum\ulamdx=1 %
      \ulamdx=-1 %
      \ulamdy=1 %
    \else%
      \ifnum\ulamdx=-1 %
        \ulamdx=0 %
        \ulamdy=-1 %
      \else%
        \ulamdx=1 %
        \ulamdy=0 %
      \fi
    \fi
  \fi

  \ifnum#1>0 %
    \advance#1 by -1 %
    \ulamplot{#1}%
  \fi
}

\begin{document}

\begin{pgfpicture}
  \pgfmathsetmacro{\x}{cos(60)}
  \pgfmathsetmacro{\y}{sin(60)}
  \pgftransformcm{1}{0}{\x}{\y}{\pgfpointorigin}

  \pgfpathmoveto{\pgfpointorigin}
  \color{blue}
  \newcount\ulamn
  \ulamn=400
  \ulamplot{\ulamn}
  \pgfusepath{stroke,fill}
\end{pgfpicture}

\end{document}

1
Wow. Non mi sarebbe mai venuto in mente di farlo in LaTeX
Luis Mendo il

L'uso di lualatexun altro compilatore con allocazione dinamica dovrebbe consentire di ignorare la dimensione dello stack, se capisco correttamente il commento corrispondente. Quindi non è una limitazione della tua risposta, ma solo della maggior parte delle implementazioni in cui l'avresti eseguita.
Andras Deak,

Siamo spiacenti, ho controllato e il limite delle dimensioni dello stack di input non è correlato all'allocazione di memoria che ho affrontato nel mio commento precedente :(
Andras Deak,

@AndrasDeak va bene, grazie per averlo cercato. Ho trovato un metodo che apparentemente aumenta la dimensione dello stack, ma non l'ho provato da solo (ancora).

@CamilStaps grazie, ho trovato altri post simili, ma non li ho nemmeno provati. Ad ogni modo, prendo i post di Christian Feuersänger come canone :)
Andras Deak,

2

Mathematica, 94 byte

ListPlot@Accumulate[Join@@Table[ReIm@Exp[2i Pi/3I],{i,2#^.5},{i}]][[Prime@Range@PrimePi@#-1]]&

Risultato

%[10000]

inserisci qui la descrizione dell'immagine


2

Python, 263 byte

Essendo nuovo in Python, c'è sicuramente spazio per miglioramenti :)

from matplotlib.pyplot import*
from math import*
def f(m):
 s=[];X=[];Y=[];i=x=y=0
 while len(s)<m:i+=1;s+=[i%3*pi*2/3]*i
 for i in range(m):
  x+=cos(s[i]);y+=sin(s[i]);j=i+2
  if all(map(lambda a:j%a>=1,range(2,int(j**.5+1)))):X+=[x];Y+=[y]
 scatter(X,Y);show()

Esempio:

f(100000)

inserisci qui la descrizione dell'immagine


Puoi accorciare s=[];X=[];Y=[];i=1;x=0;y=0as=X=Y=[];i=1;x=y=0;
rp.beltran il

Ignora quel punto e virgola extra alla fine. Dovrebbe risparmiare 8 byte.
rp.beltran,

@ rp.beltran. Questo non funziona. Penso che sia legato al fatto che gli oggetti condividono gli stessi valori. Potrebbe solo aggiungere x=y=0.
lambruscoAcido

Mio male, hai ragione. Ho dimenticato che Python passa gli elenchi per riferimento. I numeri sono immutabili e quindi è sicuro avere a che fare con i numeri interi.
rp.beltran,

1

R, 137 byte

Utilizza solo funzioni integrate, anche per i numeri primi. Dato il suo approccio vettorializzato anziché iterativo, è veloce, ma non può gestire numeri enormi.

golfed:

g=function(m){M=1:m;s=rep(M,M)[M]%%3*pi*2/3;k=cumsum;j=sapply(seq(s)+1,function(n)n<4|all(n%%2:n^.5>=1));plot(k(cos(s))[j],k(sin(s))[j])}

Ungolfed:

g=function(m) {
  M = 1:m
  s = rep(M,M)[M] %% 3 * pi * 2/3
  k=cumsum
  j=sapply(seq(s)+1,function(n)n<4|all(n%%2:n^.5>=1)) # primes
  plot(k(cos(s))[j],k(sin(s))[j])    # cumulated coordinates
}

Esempio:

g(10000)

inserisci qui la descrizione dell'immagine


Puoi aggiungere un risultato di esempio?
Luis Mendo,

@LuisMendo. Sicuro. Ho solo dovuto capire come aggiungere una trama.
lambruscoAcido
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.