Путь антилопы гну

23

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

Вдохновение: пойманный рыцарь и OEIS A316667 .

Изменить: эта последовательность в настоящее время на OEIS как A323763 .

Код может создавать местоположение , первые мест или генерировать последовательность без ввода.nthn

Не стесняйтесь указывать ее местоположение после (или до) прыжков вместо этого, но если это так, пожалуйста, четко сформулируйте это в своем ответе и убедитесь, что ввод дает (или, если необходимо).nn=01[1]

Это , поэтому цель состоит в том, чтобы создать рабочий код с минимальным количеством байтов на выбранном вами языке.

Примечание: антилопа гну попадает в ловушку (так же, как рыцарь делает это в своем местоположении в , квадрат , а верблюд - в своем , квадрат ) в своем расположение на площади . Поведение вашего кода может быть неопределенным для больше, чем это. (Спасибо Deadcode за код C ++, который нашел это!)2016th20843723rd708112899744968th12851850258n

подробность

Доска выглядит так, как показано ниже, и продолжается до бесконечности:

101 100  99  98  97  96  95  94  93  92  91
102  65  64  63  62  61  60  59  58  57  90
103  66  37  36  35  34  33  32  31  56  89
104  67  38  17  16  15  14  13  30  55  88
105  68  39  18   5   4   3  12  29  54  87
106  69  40  19   6   1   2  11  28  53  86
107  70  41  20   7   8   9  10  27  52  85
108  71  42  21  22  23  24  25  26  51  84
109  72  43  44  45  46  47  48  49  50  83
110  73  74  75  76  77  78  79  80  81  82
111 112 113 114 115 116 117 118 119 120 121

Гну является «ГНУ» фея шахматной фигуры - нестандартное шахматной фигуры , которые могут двигаться как в качестве рыцаря (а -leaper) и в качестве верблюда (а -leaper). Таким образом, она может переместиться в любое из этих мест из своего начального местоположения :(1,2)( 1 , 3 ) 1(1,3)
1

  .   .   .   .   .   .   .   .   .   .   .
  .   .   .   .  35   .  33   .   .   .   .
  .   .   .   .  16   .  14   .   .   .   .
  .   .  39  18   .   .   .  12  29   .   .
  .   .   .   .   .  (1)  .   .   .   .   .
  .   .  41  20   .   .   .  10  27   .   .
  .   .   .   .  22   .  24   .   .   .   .
  .   .   .   .  45   .  47   .   .   .   .
  .   .   .   .   .   .   .   .   .   .   .

Наименьшее из них - и она еще не посещала этот квадрат, поэтому - это второе слагаемое в последовательности.1010

Затем она может перейти с на любое из этих мест:10

  .   .   .   .   .   .   .   .   .   .   .
  .   .   .   .   .   .  14   .  30   .   .
  .   .   .   .   .   .   3   .  29   .   .
  .   .   .   .   6   1   .   .   .  53  86
  .   .   .   .   .   .   . (10)  .   .   .
  .   .   .   .  22  23   .   .   .  51  84
  .   .   .   .   .   .  47   .  49   .   .
  .   .   .   .   .   .  78   .  80   .   .
  .   .   .   .   .   .   .   .   .   .   .

Тем не менее, она уже посетила квадрат поэтому ее третье местоположение - квадрат , самый низкий, который она еще не посещала.13


Первые условий пути антилоп гну:100

1, 10, 3, 6, 9, 4, 7, 2, 5, 8, 11, 14, 18, 15, 12, 16, 19, 22, 41, 17, 33, 30, 34, 13, 27, 23, 20, 24, 44, 40, 21, 39, 36, 60, 31, 53, 26, 46, 25, 28, 32, 29, 51, 47, 75, 42, 45, 71, 74, 70, 38, 35, 59, 56, 86, 50, 78, 49, 52, 80, 83, 79, 115, 73, 107, 67, 64, 68, 37, 61, 93, 55, 58, 54, 84, 48, 76, 43, 69, 103, 63, 66, 62, 94, 57, 87, 125, 82, 118, 77, 113, 72, 106, 148, 65, 97, 137, 91, 129, 85

Первые прыжков - ход коня, поэтому первые членов совпадают с A316667 .1112

Джонатан Аллан
источник
Комментарии не для расширенного обсуждения; этот разговор был перенесен в чат .
Мего

Ответы:

21

JavaScript (Node.js) ,  191 ... 166  164 байта

Сохранено 2 байта благодаря @grimy .

Возвращает N й член.

n=>(g=(x,y)=>n--?g(Buffer('QPNP1O?O@242Q3C3').map(m=c=>g[i=4*((x+=c%6-2)*x>(y+=c%7-2)*y?x:y)**2,i-=(x>y||-1)*(i**.5+x+y)]|i>m||(H=x,V=y,m=i))&&H,V,g[m]=1):m+1)(1,2)

Попробуйте онлайн! или посмотрите форматированную версию

Как?

Спиральные индексы

Чтобы преобразовать координаты (x,y) в спиральный индекс I , мы сначала вычисляем слой L с помощью:

L=max(|x|,|y|)

Который дает:

3210+1+2+333333333232222231321112303210123+13211123+23222223+33333333

Затем мы вычисляем позицию в слое с помощью:P

P={2L+x+yif x>y(2L+x+y)if xy

Который дает:

3210+1+2+330123456210123471210125803210369+143234710+254567811+36789101112

Окончательный индекс определяется как:I

I=4L2P

Примечание: приведенная выше формула дает 0-индексированную спираль.

В коде JS мы фактически вычисляем сразу с помощью:4L2

i = 4 * (x * x > y * y ? x : y) ** 2

И затем вычтите с помощью:P

i -= (x > y || -1) * (i ** 0.5 + x + y)

Ходы гну

Учитывая текущую позицию , 16 возможных целевых квадратов антилопы гну проверяются в следующем порядке:(x,y)

321x+1+2+3391128101761213y+1541415+220+331

Мы пройдемся по ним, применяя 16 пар значений со . Каждая пара кодируется как один символ ASCII.(dx,dy)

 ID | char. | ASCII code | c%6-2 | c%7-2 | cumulated
----+-------+------------+-------+-------+-----------
  0 |  'Q'  |     81     |   +1  |   +2  |  (+1,+2)
  1 |  'P'  |     80     |    0  |   +1  |  (+1,+3)
  2 |  'N'  |     78     |   -2  |   -1  |  (-1,+2)
  3 |  'P'  |     80     |    0  |   +1  |  (-1,+3)
  4 |  '1'  |     49     |   -1  |   -2  |  (-2,+1)
  5 |  'O'  |     79     |   -1  |    0  |  (-3,+1)
  6 |  '?'  |     63     |   +1  |   -2  |  (-2,-1)
  7 |  'O'  |     79     |   -1  |    0  |  (-3,-1)
  8 |  '@'  |     64     |   +2  |   -1  |  (-1,-2)
  9 |  '2'  |     50     |    0  |   -1  |  (-1,-3)
 10 |  '4'  |     52     |   +2  |   +1  |  (+1,-2)
 11 |  '2'  |     50     |    0  |   -1  |  (+1,-3)
 12 |  'Q'  |     81     |   +1  |   +2  |  (+2,-1)
 13 |  '3'  |     51     |   +1  |    0  |  (+3,-1)
 14 |  'C'  |     67     |   -1  |   +2  |  (+2,+1)
 15 |  '3'  |     51     |   +1  |    0  |  (+3,+1)

Мы отслеживаем минимальное найденное значение в и координаты соответствующей ячейки в .m(H,V)

Как только лучший кандидат найден, мы помечаем его как посещенного, устанавливая флаг в объекте , который также является нашей основной рекурсивной функцией.g

На первой итерации мы начинаем с и . Это гарантирует, что первая выбранная ячейка будет и что первая ячейка будет помечена как посещенная.x=1y=2(0,0)

Arnauld
источник
3
Так много в гольфе, не могу дождаться изложения того, как работает вся магия!
Джонатан Аллан
Вам пришлось использовать, Bufferчтобы каждый символ интерпретировался как один байт?
Иона
1
@Jonah Хотя это устарело, Bufferконструктор все еще принимает строку. Так что, да, это довольно дешевый способ преобразования его в список байтов, в отличие от [..."string"].map(c=>do_something_with(c.charCodeAt())).
Арно
1
-2 байта в кодировке координат: TIO
Grimmy
@ Хорошо, молодец!
Арно
8

Кокос , 337 276 байт

import math
def g((x,y))=
 A=abs(abs(x)-abs(y))+abs(x)+abs(y)
 int(A**2+math.copysign(A+x-y,.5-x-y)+1)
def f():
 p=x,y=0,0;s={p};z=[2,3,1,1]*2
 while 1:yield g(p);p=x,y=min(((a+x,b+y)for a,b in zip((1,1,2,-2,-1,-1,3,-3)*2,z+[-v for v in z])if(a+x,b+y)not in s),key=g);s.add(p)

Возвращает генератор значений. Возможно, будет в гольф больше. (Особенно последовательность разностных кортежей.) Спиральный алгоритм взят из этого математического ответа .

Попробуйте онлайн!

Соломон Уцко
источник
1
for a,b in (-> for a,b in((может быть, вы можете сыграть в гольф и сам набор дельта-кортежей)
Джонатан Аллан
1
Нет необходимости, qи почтовый индекс короче для кортежей: 306 байтов могут все еще быть пригодными для игры в гольф, конечно
Джонатан Аллан
1
... как насчет этого для 284? РЕДАКТИРОВАТЬ ... это для 278
Джонатан Аллан
1
FWIW, что math.se ответ имеет й и у выгружена и как отрицательные по отношению к системе координат , в этой задаче (где положительные х права , а у вверх). Не то чтобы это имело значение из-за симметрии, но все же.
Deadcode
1
0.5-> .5для сохранения другого байта; A**2-> еще A*Aодин.
Джонатан Аллан
8

05AB1E , 77 65 58 57 52 байта

Xˆ0UF3D(Ÿ0KãʒÄ1¢}εX+}Dε·nàDtyÆ+yO·<.±*->}D¯KßDˆkèU}¯

-6 байт благодаря @Arnauld , используя порт его формулы.

n+1

Попробуйте онлайн ( ïнижний колонтитул удаляет, .0чтобы сделать вывод более компактным, но вы можете удалить его, чтобы увидеть реальный результат).

Объяснение кода:

Xˆ             # Put integer 1 in the global_array (global_array is empty by default)
0U             # Set variable `X` to 0 (`X` is 1 by default)
F              # Loop the (implicit) input amount of times:
 3D          #  Push the list in the range [-3,3]: [-3,-2,-1,0,1,2,3]
     0K        #  Remove the 0: [-3,-2,-1,1,2,3]
       ã       #  Cartesian product with itself, creating each possible pair: [[3,3],[3,2],[3,1],[3,-1],[3,-2],[3,-3],[2,3],[2,2],[2,1],[2,-1],[2,-2],[2,-3],[1,3],[1,2],[1,1],[1,-1],[1,-2],[1,-3],[-1,3],[-1,2],[-1,1],[-1,-1],[-1,-2],[-1,-3],[-2,3],[-2,2],[-2,1],[-2,-1],[-2,-2],[-2,-3],[-3,3],[-3,2],[-3,1],[-3,-1],[-3,-2],[-3,-3]]
        ʒ   }  #  Filter this list of pairs by:
         Ä     #   Where the absolute values of the pair
          1¢   #   Contains exactly one 1
               #  (We now have the following pairs left: [[3,1],[3,-1],[2,1],[2,-1],[1,3],[1,2],[1,-2],[1,-3],[-1,3],[-1,2],[-1,-2],[-1,-3],[-2,1],[-2,-1],[-3,1],[-3,-1]])
 εX+}          #  Add the variable `X` (previous coordinate) to each item in the list
 D             #  Duplicate this list of coordinates
  ε            #  Map each `x,y`-coordinate to:
   ·           #   Double both the `x` and `y` in the coordinate
    n          #   Then take the square of each
     à         #   And then pop and push the maximum of the two
   Dt          #   Duplicate this maximum, and take its square-root
     yÆ        #   Calculate `x-y`
       +       #   And add it to the square-root
   yO          #   Calculate `x+y`
     ·         #   Double it
      <        #   Decrease it by 1
             #   And pop and push its signum (-1 if < 0; 0 if 0; 1 if > 0)
   *           #   Multiply these two together
    -          #   And subtract it from the duplicated maximum
   >           #   And finally increase it by 1 to make it 1-based instead of 0-based
  }D           #  After the map: Duplicate that list with values
    ¯K         #  Remove all values that are already present in the global_array
      ß        #  Pop the list of (remaining) values and push the minimum
       Dˆ      #  Duplicate this minimum, and pop and add the copy to the global_array
         k     #  Then get its index in the complete list of values
          è    #  And use that index to get the corresponding coordinate
           U   #  Pop and store this coordinate in variable `X` for the next iteration
             # After the outer loop: push the global_array (which is output implicitly)

Общее объяснение:

global_array[1]
x,yX[0,0]

x,y

[[x+3,y+1], [x+3,y-1], [x+2,y+1], [x+2,y-1], [x+1,y+3], [x+1,y+2], [x+1,y-2], [x+1,y-3], [x-1,y+3], [x-1,y+2], [x-1,y-2], [x-1,y-3], [x-2,y+1], [x-2,y-1], [x-3,y+1], [x-3,y-1]]

x,yX

x,yx,y

T=max((2x)2,(2y)2)
R=T(xy+T)signum((x+y)21)+1

Это та же формула, которую @Arnauld использует в своем ответе , но написанная по-другому, чтобы использовать встроенные 05AB1E для double, square, -1, +1 и т. Д.

(Если вы хотите увидеть только эту спиральную часть кода в действии: попробуйте это онлайн .)

x,yglobal_array
global_arrayXx,y

После того, как мы зациклили inputколичество раз, программа выдаст это global_arrayкак результат.

Кевин Круйссен
источник
1
FWIW, вот порт моей собственной формулы для преобразования координат в спиральные индексы. Это на 5 байт короче, но дает плавания. (Я не знаю, является ли это проблемой или нет.)
Арно
yy
@Arnauld Спасибо, это экономит 5 дополнительных байтов. :) РЕДАКТИРОВАТЬ: Что вы уже упоминали в своем первом комментарии. ; p
Кевин Круйссен