Треугольная спираль Улама


21

У нас было несколько из проблем , о спирали Улама. Но этого недостаточно.

В этом задании мы построим треугольную спираль Улама (в отличие от обычной квадратной спирали Улама). Вот эскиз того, как выглядит спираль.

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

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

Соревнование

Примите число N в качестве ввода и покажите треугольную спираль Улама до этого числа.

  • Ввод может быть стандартным аргументом или аргументом функции.
  • Спираль должна повернуться в положительном направлении (то есть против часовой стрелки), как показано на рисунке выше.
  • Любой из поворотов на 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
В будущем я бы порекомендовал выбрать только один из [graphic-output] и [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 '.'

Что OO мне нужно, чтобы прочитать это дальше
Brain Guider

Попробовать онлайн поддержка графического вывода для 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).

Еще одна оговорка: из-за максимального размера стека TeX может обрабатываться только чуть меньше 5000. Первое изображение для n = 4000. Видимо можно увеличить размер стека , я не пробовал.

Использует PGF isprime().

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

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

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
Вау. Мне никогда бы в голову не пришло сделать это в LaTeX
Луис Мендо

Использование lualatexили другой динамически размещаемый компилятор должен позволить вам обойти размер стека, если я правильно понимаю ваш соответствующий комментарий. Так что это не ограничение вашего ответа, просто большинство реализаций, где вы его запускаете.
Андрас Дик

Извините, я проверил, и ограничение размера входного стека не связано с распределением памяти, о котором я говорил в своем предыдущем комментарии :(
Andras Deak

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

@CamilStaps спасибо, я нашел другие подобные посты, но я их тоже не пробовал. Во всяком случае, я принимаю посты Кристиана Фойерсингера в качестве канона :)
Андрас Дик

2

Mathematica, 94 байта

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

Результат

%[10000]

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


2

Python, 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 байт

Используются только встроенные функции, даже для простых чисел. Учитывая векторизованный подход вместо итеративного, он быстрый, но не может обрабатывать огромные числа.

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
}

Пример:

g(10000)

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


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

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