Spirale d'Ulam triangulaire


21

Nous avons eu deux des défis sur la spirale d' Ulam. Mais cela ne suffit pas.

Dans ce défi, nous allons tracer une spirale Ulam triangulaire (par opposition à la spirale Ulam carrée habituelle). Voici un croquis de ce à quoi ressemble la spirale.

entrez la description de l'image ici

Comme nous le savons, la spirale Ulam organise tous les nombres naturels dans une spirale extérieure et ne marque que ceux qui sont premiers. Ainsi, dans l'esquisse ci-dessus, seuls les nombres qui apparaissent en noir (les nombres premiers) seraient affichés.

Le défi

Acceptez un nombre N en entrée et affichez la spirale triangulaire d'Ulam jusqu'à ce nombre.

  • L'entrée peut être stdin ou un argument de fonction.
  • La spirale doit tourner dans le sens positif (c'est-à-dire dans le sens antihoraire), comme dans la figure ci-dessus.
  • N'importe lequel des virages à 120 degrés de la figure ci-dessus serait valide, et le virage peut être différent pour différentes entrées. Mais le côté le plus bas des triangles implicites doit être horizontal, car les seuls virages autorisés sont (multiples de) 120 degrés.
  • Le code doit s'exécuter théoriquement (avec suffisamment de temps et de mémoire) pour tout N jusqu'à ce qui est autorisé par les calculs intermédiaires que vous effectuez avec votre type de données par défaut. doubleest assez; pas besoin de grands types entiers.
  • Toutes les fonctions intégrées sont autorisées.
  • Je n'accepterai pas ma propre réponse (pas que je pense que ce serait la plus courte de toute façon ...).

Formats de sortie

Choisissez l'une des options suivantes.

  1. Affichez un graphique avec un marqueur (point, cercle, croix, tout ce que vous préférez) aux nombres premiers, et rien aux nombres non premiers. Il n'est pas nécessaire que l'échelle soit la même pour les deux axes. Autrement dit, les triangles implicites n'ont pas besoin d'être équilatéraux. Les axes, les lignes de grille et les étiquettes d'axe sont facultatifs. Seuls les marqueurs aux nombres premiers sont requis.

    Un exemple de sortie pour N = 12 serait le suivant (comparer avec le croquis ci-dessus). Le deuxième graphique est un exemple plus intéressant, correspondant à N = 10000.

entrez la description de l'image ici

entrez la description de l'image ici

  1. Produisez un fichier image avec ce qui précède, dans n'importe quel format d'image bien connu (tel que png, tiff, bmp).
  2. Affichez la spirale en tant qu'art ASCII , en utilisant un seul caractère de votre choix pour les nombres premiers et un espace vide pour les non-nombres premiers, avec un espace vide pour séparer les positions numériques dans la même ligne. Les espaces de début ou de fin ou les nouvelles lignes sont autorisés. Par exemple, le cas N = 12 utilisant ocomme caractère serait

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

    où bien sûr, seule la omarque aux nombres premiers serait effectivement affichée. Le ·at non-prime est présenté ici à titre de référence uniquement.

Critère gagnant

La récompense réelle est de voir par vous-même ces modèles incroyables Code golf, le code le plus court gagne.


2
À l'avenir, je recommanderais de choisir un seul parmi [sortie graphique] et [ascii-art] car cela rend les soumissions moins comparables. Mais beau défi quand même. :)
Alex A.

@AlexA. Merci! Je vais en tenir compte. Alors ... y aura-t-il une réponse de Julia? ;-)
Luis Mendo

Wow, merci pour la prime, mais vous devriez accepter votre propre réponse. Il est le plus court. :)
Martin Ender

C'est bien mérité! Quant à l'acceptation d'une réponse, l'une des règles du défi était "Je n'accepterai pas ma propre réponse". Quand j'ai pensé à ce défi, j'avais inévitablement MATL en tête, avec son nombre complexe et ses fonctions graphiques, donc c'était un peu comme tricher :-)
Luis Mendo

Réponses:


13

CJam, 49 42 octets

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

Entrez comme un entier unique dans STDIN. Sortie sous forme de grille ASCII avec 0des nombres premiers. La rotation de la spirale n'est pas cohérente: le plus grand nombre de la spirale sera toujours sur la rangée inférieure.

Testez-le ici.

Explication

L'idée de base est de représenter le triangle comme un tableau 2D irrégulier lors du calcul. Vous obtenez ce tableau en inversant les lignes et en alignant toutes les lignes vers la gauche:

   4
  5 3
 6 1 2
7 8 9 A

Serait représenté comme

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

Puisque nous avons mis en miroir la ligne, nous voulons enrouler la spirale dans le sens horaire . C'est pratique, car tout ce que nous devons faire est de faire pivoter le triangle dans le sens inverse des aiguilles d'une montre et d'ajouter la prochaine sous-liste dans l'ordre. Nous pouvons faire pivoter le tableau irrégulier en inversant toutes les lignes et en le transposant:

                                                           [[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]]

Voici donc le code. Un détail sur lequel je voudrais attirer l'attention est le dernier morceau qui crée la disposition triangulaire. Je pense que c'est plutôt chouette. :)

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
Je savais que tu serais le premier!
Luis Mendo

@LuisMendo J'allais en fait sauter celui-ci, car je pensais que le calcul des indices de la grille serait fastidieux, mais j'ai réalisé que je pouvais simplement faire pivoter tout le triangle tout en ajoutant des lignes.
Martin Ender

1
J'adore toujours vos explications sur les programmes CJam parce que je peux les comprendre et je suis étonné de la complexité et de la brièveté de ces programmes.
ETHproductions

10

MATL , 48 36 octets

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

Utilise la version actuelle (9.3.0) .

Essayez-le en ligne! Aucune idée de la façon dont le compilateur en ligne parvient à traduire la sortie graphique en ASCII, mais il le fait. Cela produit un tracé ASCII approximatif grâce à une fonction Octave prise en charge par le compilateur en ligne!

Edit (4 avril 2016): la fonction Y[a été renommée kdepuis la version 13.0.0. Le lien vers le compilateur en ligne intègre cette modification, afin que le code puisse être testé.

Exemple

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

produit la sortie graphique (version MATLAB montrée):

entrez la description de l'image ici

Explication

Le code utilise des nombres complexes pour tracer le chemin suivi par la spirale. Comme le montre la première figure du défi, chaque jambe droite de la spirale est un segment de longueur croissante 1, 2, 3, 4 ... et d'orientation cycliquement croissante de 120 degrés, 240 degrés, 0 dégressif, 120 dégressifs. ..

Le code génère d'abord les déplacements complexes individuels de chaque nombre entier au suivant. Ces déplacements complexes ont une magnitude 1 et un angle 2*pi/3, 4*pi/3ou 0(en radians). Ainsi, ils peuvent être facilement générés sous forme d'exponentielles imaginaires. Pour cela, la séquence entière 0,1,2,2,3,3,3,4,4,4,4 ... est utilisée en premier.

Cette séquence entière est presque comme la séquence "n apparaît n fois" ( OEIS A002024 ), et peut être obtenue comme floor(sqrt(2*n)+.5)nest 0,1,2,3, .... La multiplication par 2j*pi/3, où jest l'unité imaginaire, produit les déplacements complexes souhaités.

Les déplacements sont cumulés pour calculer les positions correspondant aux nombres entiers dans la spirale. Le premier nombre entier dans la spirale, qui est 1, est situé arbitrairement à une position 1dans le plan complexe.

Enfin, les positions correspondant aux nombres non premiers sont rejetées et les autres sont tracées dans le plan complexe.

: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 '.'

Ce que j'ai besoin de lire plus loin
Brain Guider

L'essaye-t-il en ligne! supporte la sortie graphique pour MATL?
Alex A.

Je pensais que TIO ne supportait pas la sortie graphique? Si c'est le cas, je peux facilement demander à MATL de vider automatiquement les images dans un .pngfichier qui sera montré par la page Web @AlexA
Luis Mendo

Hey! J'ai fait un simple test ( plot(1:5)) et cela produit une sortie texte-graphique !! matl.tryitonline.net/#code=NTpYRw&input= @AlexA. Comment c'est??
Luis Mendo

4
WHOA! C'est génial!
Alex A.

8

Le dessin doit être fait avec

LaTeX / PGF, 527 594 octets

\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 octets est le document complet comme ci-dessus, c'est-à-dire incluant le préambule et le paramètre (ici 4000, donc ~ 523 sans paramètre). Produit un fichier PDF.

Idée de base: eh bien, dessinez. Utilise une transformation matricielle pour une grille triangulaire. Le seul problème est que les points sont également affectés (et étirés) par la transformation. J'ai donc choisi des marqueurs d'ellipse :) ce que je veux dire par là est clair dans la deuxième image (n = 250, 5pt).

Autre mise en garde: ne peut gérer qu'un peu moins de 5000 en raison de la taille de pile maximale de TeX. La première image est pour n = 4000. Apparemment, il est possible d'augmenter la taille de la pile , je ne l'ai pas essayé.

Utilise les PGF isprime().

entrez la description de l'image ici

entrez la description de l'image ici

Non golfé:

\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
Sensationnel. Je n'aurais jamais pensé à faire ça dans LaTeX
Luis Mendo

L'utilisation lualatexou un autre compilateur à allocation dynamique devrait vous permettre de contourner la taille de la pile, si je comprends bien votre commentaire correspondant. Ce n'est donc pas une limitation de votre réponse, juste de la plupart des implémentations où vous l'exécuteriez.
Andras Deak du

Désolé, j'ai vérifié et la limite de taille de la pile d'entrée n'est pas liée à l'allocation de mémoire que j'ai abordée dans mon commentaire précédent :(
Andras Deak

@AndrasDeak c'est bon, merci de l'avoir recherché. J'ai trouvé une méthode qui augmente apparemment la taille de la pile, mais je ne l'ai pas essayée moi-même (encore).

@CamilStaps merci, j'ai trouvé d'autres articles similaires, mais je ne les ai pas non plus essayés. Quoi qu'il en soit, je prends les messages de Christian Feuersänger en tant que canon :)
Andras Deak

2

Mathematica, 94 octets

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

Résultat

%[10000]

entrez la description de l'image ici


2

Python, 263 octets

Étant nouveau sur Python, il y a sûrement matière à amélioration :)

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

Exemple:

f(100000)

entrez la description de l'image ici


Vous pouvez raccourcir s=[];X=[];Y=[];i=1;x=0;y=0às=X=Y=[];i=1;x=y=0;
rp.beltran

Ignorez ce point-virgule supplémentaire à la fin. Il devrait vous épargner 8 octets.
rp.beltran

@ rp.beltran. Cela ne fonctionne pas. Je pense que cela est lié au fait que les objets partagent les mêmes valeurs. Pourrait seulement ajouter x=y=0.
lambruscoAcido

Mon mauvais, tu as raison. J'ai oublié que Python transmet les listes par référence. Les nombres sont immuables et il est donc sûr de le faire avec des entiers.
rp.beltran

1

R, 137 octets

Utilise uniquement les fonctions intégrées, même pour les nombres premiers. Compte tenu de son approche vectorisée au lieu d'itérative, il est rapide, mais ne peut pas gérer de grands nombres.

Golfé:

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])}

Non golfé:

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
}

Exemple:

g(10000)

entrez la description de l'image ici


Pouvez-vous ajouter un exemple de résultat?
Luis Mendo

@LuisMendo. Sûr. Je n'avais qu'à trouver comment ajouter un complot.
lambruscoAcido du
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.