Трикутна спіраль Улама


21

У нас було кілька з проблем , про спіралі Улама. Але цього недостатньо.

У цьому виклику ми побудуємо трикутну спіраль Улама (на відміну від звичайної, квадратної спіралі Улама). Ось ескіз того, як виглядає спіраль.

введіть тут опис зображення

Як ми знаємо, спіраль Улама розташовує всі природні числа по зовнішній спіралі і позначає лише ті, які є простими. Тож у вищенаведеному ескізі будуть показані лише цифри, які відображаються чорним кольором (праймери).

Змагання

Прийміть число N як вхідне та покажіть трикутну спіраль Улама до цього числа.

  • Введенням може бути stdin або аргумент функції.
  • Спіраль повинна повертатися в позитивному напрямку (тобто проти годинникової стрілки), як на наведеному малюнку.
  • Будь-який із 120-градусних витків вищевказаної фігури був би дійсним, а поворот може бути різним для різних входів. Але найнижча сторона трикутників, що маються на увазі, повинна бути горизонтальною, оскільки єдині дозволені повороти становлять (кратні) 120 градусів.
  • Код повинен працювати теоретично (з урахуванням достатнього часу та пам’яті) для будь-яких N , дозволених будь-якими проміжними обчисленнями, які ви робите зі своїм типом даних за замовчуванням. doubleдостатньо; не потрібно великих цілих типів.
  • Дозволені всі вбудовані функції.
  • Я не прийму власної відповіді (не те, що я думаю, що це все-таки було б найкоротшим ...).

Вихідні формати

Виберіть будь-яке з наведеного нижче.

  1. Відображайте графік з маркером (крапкою, колом, хрестом, що б вам не було зручніше) за простими числами, а нічого не для простих чисел. Шкала не повинна бути однаковою для двох осей. Тобто маються на увазі трикутники не повинні бути рівносторонніми. Осі, лінії сітки та мітки осі необов’язкові. Потрібні лише маркери на простих номерах.

    Приклад виводу для N = 12 буде таким (порівняйте з наведеним ескізом). Другий сюжет - більш цікавий приклад, що відповідає N = 10000.

введіть тут опис зображення

введіть тут опис зображення

  1. Створіть файл зображень із вищевказаним у будь-якому добре відомому форматі зображення (наприклад, png, tiff, bmp).
  2. Відображайте спіраль як ASCII мистецтво , використовуючи один символ на ваш вибір для праймерів та порожній простір для не-простих, з порожнім пробілом для відокремлення позицій номерів у тому ж рядку. Доступні провідні або кінцеві пробіли або нові рядки. Наприклад, випадок N = 12, який використовується oяк символ, буде

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

    де, звичайно, відображатиметься лише oпозначка на прайме. Тут ·наведено лише для довідки.

Критерій виграшу

Фактична нагорода - це бачити для себе ті дивовижні моделі Code Golf, найкоротші виграші коду.


2
Надалі я рекомендую вибрати лише один із [графічного виводу] та [ascii-art], оскільки це робить менш менш порівняльними. Але приємний виклик все одно. :)
Олексій А.

@AlexA. Спасибі! Я це врахую. Отже ... чи буде відповідь Юлії? ;-)
Луїс Мендо

Вау, дякую за щедроту, але ви повинні прийняти власну відповідь. Це є найкоротшим. :)
Мартін Ендер

Це заслужено! Що стосується прийняття відповіді, одне з правил виклику було "Я не прийму власної відповіді". Коли я думав, що це завдання, я неминуче мав на увазі MATL, його складні числа та графічні функції, тож це було трохи схоже на обман :-)
Луїс Мендо

Відповіді:


13

CJam, 49 42 байт

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

Введіть як одне ціле число в STDIN. Виводиться як ASCII сітка з 0для простих ліній. Обертання спіралі не є послідовним: найбільша кількість спіралі завжди буде в нижньому ряду.

Перевірте це тут.

Пояснення

Основна ідея полягає в поданні трикутника у вигляді роздвоєного 2D масиву під час обчислення. Ви отримуєте цей масив, перевернувши рядки і вирівнявши всі рядки вліво:

   4
  5 3
 6 1 2
7 8 9 A

Буде представлено як

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

Оскільки ми віддзеркалювали лінію, ми хочемо згортати спіраль за годинниковою стрілкою . Це зручно, адже все, що нам потрібно зробити, це повернути трикутник проти годинникової стрілки і додати наступний підпис у порядку. Ми можемо обертати нерівний масив, перевернувши всі рядки та перемістивши його:

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

Так ось код. Однією деталлю, на яку я хотів би звернути увагу, є останній шматочок, який створює трикутне розташування. Я думаю, що це досить чудово. :)

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
Я знав, що ти будеш першим!
Луїс Мендо

@LuisMendo Я насправді збирався пропустити цей, бо вважав, що обчислення індексів сітки буде втомливим, але тоді я зрозумів, що можу просто повернути весь трикутник, додаючи рядки.
Мартін Ендер

1
Я завжди люблю ваші пояснення програм CJam, тому що я можу їх зрозуміти , і я вражений тим, наскільки складні, але короткі, ці програми можуть бути.
ETHproductions

10

MATL , 48 36 байт

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

Використовується поточний випуск (9.3.0) .

Спробуйте в Інтернеті! Не знаю, як онлайн-компілятору вдається перевести графічний вихід у ASCII, але це робить Це створює приблизний графік ASCII завдяки функції Octave яку підтримує онлайн-компілятор!

Редагувати (4 квітня 2016 р.): Функцію Y[було перейменовано наk випуск 13.0.0. Посилання на онлайн-компілятор включає цю зміну, щоб код можна було перевірити.

Приклад

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

створює графічний вихід (показана версія MATLAB):

введіть тут опис зображення

Пояснення

Код використовує складні числа для відстеження шляху, за яким йде спіраль. Як видно з першої фігури виклику, кожна пряма нога спіралі являє собою відрізок із збільшенням довжини 1, 2, 3, 4 ... і циклічно зростаючою орієнтацією на 120 градусів, 240 градусів, 0 пониження, 120 поглиблень. ..

Код спочатку генерує окремі складні переміщення від кожного цілого числа до наступного. Ці складні переміщення мають величину 1 і кут 2*pi/3, 4*pi/3або0 (в радіанах). Таким чином, вони можуть бути легко породжені як уявні експоненти. Для цього спочатку використовується ціла послідовність 0,1,2,2,3,3,3,4,4,4,4 ...

Ця ціла послідовність майже подібна послідовності "n з'являється n разів" ( OEIS A002024 ), і її можна отримати як floor(sqrt(2*n)+.5)де n0,1,2,3, .... Помноження на 2j*pi/3, де jє уявна одиниця, створює бажані складні переміщення.

Зсуви акумулюються для обчислення позицій, відповідних цілим числам у спіралі. Перше ціле число в спіралі, яке є 1, довільно розташоване в положенні 1в складній площині.

Нарешті, позиції, що відповідають непростим числам, відкидаються, а решта розміщуються у складній площині.

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

Що мені потрібно прочитати далі
Мозковий керівник»

Спробуйте це в Інтернеті! підтримка графічного виводу для MATL?
Олексій А.

Я думав, TIO не підтримує графічний вихід? Якщо це так, я легко можу MATL автоматично скидати зображення у .pngфайл, який відображатиметься веб-сторінкою @AlexA
Луїс Мендо

Гей! Я зробив простий тест ( plot(1:5)), і він дає текстовий графічний вихід !! matl.tryitonline.net/#code=NTpYRw&input= @AlexA. Як це ??
Луїс Мендо

4
ХТО! Це круто!
Олексій А.

8

Малювання слід робити за допомогою

LaTeX / PGF, 527 594 байт

\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 байт - це повний документ, як зазначено вище, тобто включаючи преамбулу та параметр (тут 4000, тому ~ 523 без параметра). Створює PDF-файл.

Основна ідея: ну просто намалюй. Використовує матричне перетворення для трикутної сітки. Проблема полягає лише в тому, що на перетворення також впливають (і розтягуються) крапки. Тому я вибираю маркери еліпса :) що я маю на увазі під цим зрозумілим на другому зображенні (n = 250, 5pt).

Ще одне застереження: може працювати лише до трохи менше 5000 через максимальний розмір стека TeX. Перше зображення для n = 4000. Мабуть, можливо збільшити розмір стека , я цього не пробував.

Використовує PGF isprime().

введіть тут опис зображення

введіть тут опис зображення

Безголівки:

\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
Ого. Мені б ніколи не прийшло в голову робити це в LaTeX
Луїс Мендо,

Використання lualatexчи інший компілятор, що динамічно розподіляє, повинен дозволяти вам обійти розмір стека, якщо я правильно зрозумів ваш відповідний коментар. Тож це не обмеження вашої відповіді, а лише більшість реалізацій, де ви б її запустили.
Андрас Дік

Вибачте, я перевірив, і обмеження розміру вхідного стека не пов'язане з розподілом пам'яті, про яке я звертався в своєму попередньому коментарі :(
Andras Deak

@AndrasDeak це нормально, дякую, що подивився. Я знайшов метод, який, очевидно, збільшує розмір стека, але не спробував сам (поки).

@CamilStaps дякую, я знайшов інші подібні публікації, але я також не пробував їх. У будь-якому разі, я приймаю пости Крістіана Феуерсангера як канон :)
Andras Deak

2

Математика, 94 байти

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

Результат

%[10000]

введіть тут опис зображення


2

Пітон, 263 байти

Будучи новим у Python, напевно є місце для вдосконалення :)

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

Приклад:

f(100000)

введіть тут опис зображення


Можна скоротити s=[];X=[];Y=[];i=1;x=0;y=0доs=X=Y=[];i=1;x=y=0;
rp.beltran

Ігноруйте цю зайву крапку з комою в кінці. Це повинно економити 8 байт.
rp.beltran

@ rp.beltran. Це не працює. Я думаю, що це пов'язано з тим, що об'єкти мають однакові значення. Можна було лише додати x=y=0.
lambruscoAcido

Моє погано, ти маєш рацію. Я забув, що Python передає списки за посиланням. Числа незмінні, і це безпечно робити з цілими числами.
rp.beltran

1

R, 137 байт

Використовує лише вбудовані функції, навіть для простих чисел. Враховуючи свій векторний підхід замість ітеративного, він швидкий, але не може впоратися з величезною кількістю.

Гольф:

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

Безголівки:

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
}

Приклад:

g(10000)

введіть тут опис зображення


Чи можете ви додати приклад результату?
Луїс Мендо

@LuisMendo. Звичайно. Мені довелося лише придумати, як додати сюжет.
lambruscoAcido
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.