Где конь может быть в N ходов?

21

Это лунка -3 с осеннего турнира APL CodeGolf . Я являюсь первоначальным автором этой проблемы, и поэтому мне разрешено повторно публиковать ее здесь.


Данный:

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

  2. список одной или нескольких начальных позиций (в любой форме, например, 0 или 1 индексированные координаты или 64 последовательных числа / символа или A1 – H8 - состояние, которое), на шахматной доске 8 на 8,

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

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

  • Рыцарь может двигаться только в позиции, отмеченные X, относительно его текущей позиции, отмеченной ♞:
    куда рыцарь может двигаться

Примеры (1-индексированные координаты)

1перейти от [[1,1]]: [[2,3],[3,2]]

2движется от [[1,1]]: [[1,1],[1,3],[1,5],[2,4],[3,1],[3,5],[4,2],[4,4],[5,1],[5,3]]

1перейти от [[1,1],[5,7]]: [[2,3],[3,2],[3,6],[3,8],[4,5],[6,5],[7,6],[7,8]]

2движется от [[1,1],[5,7]]: [[1,1],[1,3],[1,5],[1,7],[2,4],[2,6],[2,8],[3,1],[3,3],[3,5],[3,7],[4,2],[4,4],[4,6],[4,8],[5,1],[5,3],[5,5],[5,7],[6,4],[6,6],[6,8],[7,3],[7,7],[8,4],[8,6],[8,8]]

0движется от [[3,4]]: [[3,4]]

Адам
источник
Можно ли вводить и выводить шахматные пространства нумерацией 0-63 вместо [rank, file]?
Дейв
@ Дэйв Конечно, почему бы и нет? Просто будьте последовательны с I / O.
Адам
8
Клянусь, я читаю этот HNQ как «Куда движется рыцарь в Ни»
Сидни
3
Пун предупреждение: обозначение для рыцаря - N.
Иисус Навин
Можем ли мы использовать индексирование на основе 1 по количеству шагов? Например[[1,1]], 2 -> [[2,3],[3,2]]
Згарб

Ответы:

11

Wolfram Language (Mathematica) , 45 байт

Поскольку другое решение неверно (см. Комментарий Мартина ниже), поэтому я решил опубликовать свое решение:

8~KnightTourGraph~8~AdjacencyList~#&~Nest~##&

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

Конечная нотация инфикса ...

Принимает 2 входа, первый список номеров в диапазоне [1,64] описывающих начальные позиции коня, второе - количество шагов.

Это решение основано на исключительном удобстве встроенных функций Mathematica:

  • AdjacencyListМожет взять список вершин на правой стороне и вернуть список вершин, смежных с любой из них, уже удаленных дубликатов и отсортированных .
  • KnightTourGraphявляется встроенным Не удивительно.
  • Nestпринимает аргументы в порядке Nest[f, expr, n], который мы можем разделить на ##его правой стороне какNest[f, ##] .
  • И, наконец, Mathematica разобрать a~b~c~d~eкак (a~b~c)~d~e, так что квадратная скобка не нужна. Без инфиксной нотации и сглаживания ##это было бы Nest[AdjacencyList[KnightTourGraph[8, 8], #] &, #, #2]&.
user202729
источник
1
Я не думаю, что есть что-то не так с перевесом существующего решения.
Адам
1
Работает ли это с несколькими стартовыми позициями?
Адам
Удивительно! Теперь мне нужно выяснить, как я это читаю ...
Дейв
Вероятно, это будет 17 байт в гипотетическом языке игры Mthmca.
Майкл Стерн
7

JavaScript (ES7), 99 байт

Формат ввода / вывода: квадратные индексы в [0 ... 63] .

f=(a,n)=>n--?f([...Array(64).keys()].filter(p=>!a.every(P=>(p%8-P%8)**2^((p>>3)-(P>>3))**2^5)),n):a

Контрольные примеры

Этот фрагмент содержит две вспомогательные функции для перевода из и в формат, предоставленный OP.

Как?

Переход от (x, y) к (X, Y) является допустимым ходом коня, если мы имеем:

  • | хЙ | = 1 и | yY | = 2 или
  • | хЙ | = 2 и | yY | = 1

Используя квадрат вместо использования абсолютных значений, это можно выразить как:

  • (xX) ² = 1 и (yY) ² = 4 , или
  • (xX) ² = 4 и (yY) ² = 1

Поскольку 1 и 4 являются единственными идеальными квадратами, которые дают 5, когда XOR'ы вместе, у нас есть правильный ход коня, если:

(xX) ² XOR (yY) ² XOR 5 = 0

Мы применяем эту формулу к каждому квадрату p = 8y + x на доске и каждому квадрату рыцаря P = 8Y + X, чтобы вывести новые возможные квадраты цели рыцаря, и рекурсивно повторяем этот процесс n раз.

Arnauld
источник
5

Октава, 69 байт

function a=f(a,n,b=~a)for k=1:n;a=b&imdilate(a,de2bi(")0#0)"-31));end

Демо онлайн!

Вход / выход - это конфигурация платы в начале / конце в виде двоичной матрицы 8 * 8.

Объяснение:

Для nшагов повторите морфологическое расширение доски со следующей маской:

01010
10001
00100
10001
01010
rahnema1
источник
5

Сетчатка , 147 102 байта

.$
$*	
¶
 ¶
{s`((?<=N(....|.{11}|.{13})?.{7})|(?=.{8}(....|.{11}|.{13})?N))\S(?=.*	)
n
Ts`	Nn`_:N`.*¶	

Попробуйте онлайн! Вводит в виде доски 8x8 :s с конями, помеченными Ns, с цифрой для числа ходов на следующей строке (нет смысла иметь больше 9 ходов, но если вы настаиваете, я могу поддержать его для дополнительного байт). Обратите внимание, что вывод содержит дополнительный пробел. Редактировать: 45 байтов сохранено благодаря @MartinEnder. Объяснение: На первом этапе число витков преобразуется в унарный, но с использованием символов табуляции, чтобы впоследствии они не попали под случайное совпадение, а на втором этапе справа от поля добавляются пробелы, чтобы регулярные выражения не переносились через край. Третий этап заменяет все Ns и :s, которые являются ходом рыцаря от a Nсn то время как четвертый этап удаляет все оставшиеся Ns, изменяетns к Ns, и вычитает 1 из числа ходов. Это повторяется до тех пор, пока счетчик ходов не станет равным нулю.

Нил
источник
Это самое впечатляющее. Определенно не правильный инструмент для работы!
Адам
4

Желе , 29 байт

+þ1,2Œ!×þ1,-p`¤¤Ẏ¤Ẏ⁼%8$$ÐfQµ¡

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

0-индексированные координаты. Почти наверняка это неоптимально.

-1 байт благодаря пользователю 202729

объяснение

+þ1,2Œ!×þ1,-p`¤¤Ẏ¤Ẏ⁼%8$$ÐfQµ¡  Main Link
+þ                             Addition Table (all pairs using + as combining function) with
  1,2Œ!×þ1,-p`¤¤Ẏ¤             All knight moves:
  1,2                          [1, 2]
     Œ!                        All permutations ([1, 2], [2, 1])
       ×þ                      Product Table (all pairs using × as combining function) with
         1,-p`¤                [1, 1], [1, -1], [-1, 1], [-1, -1]
         1,-                   [1, -1]
            p`                 Cartestian Product with itself
               ¤               All knight moves (in a nested array) as a nilad
                Ẏ¤             Tighten (flatten once); all knight moves in a (semi-)flat array
                        Ðf     Keep elements where
                   ⁼%8$$       The element equals itself modulo 8 (discard all elements out of the range)
                          Q    Remove Duplicates
                           µ   Start new monadic chain (essentially, terminates previous chain)
                            ¡  Repeat n times; n is implicitly the second input (right argument)
HyperNeutrino
источник
1
0-индексированный желе?
Адам
1
@ Adám Упрощает фильтрацию: P
HyperNeutrino
2
Я ожидаю, что Jelly сможет сделать это менее чем в 15 байтах, потому что текущий рекордсмен в APL делает это в 24 символах.
Адам
Когда у вас есть> = 3 $, вполне вероятно, что вы можете переместить его на предыдущую ссылку и вернуться назад с помощью Ç.
user202729
@ user202729 О да, спасибо.
HyperNeutrino
3

05AB1E , 27 25 байтов

Благодаря Эмигне за сохранение 2 байта!

Использует 1-индексированные координаты.

Код:

F•eĆ•SÍü‚Dí«δ+€`Ùʒ{`9‹*0›

Использует кодировку 05AB1E . Попробуйте онлайн!

Объяснение:

F                          # Do the following <input_1> times..
 •eĆ•SÍ                    #   Push [-1, -2, 1, 2, -1]
       ü‚                  #   Pairwise pairing: [[-1, -2], [-2, 1], [1, 2], [2, -1]]
         D                 #   Duplicate the array
          í                #   Reverse each element
           «               #   Concatenate to the previous array

Это дает нам следующий массив:

[[-1, -2], [-2, 1], [1, 2], [2, -1], [-2, -1], [1, -2], [2, 1], [-1, 2]]

Какие дельты ходов рыцаря.

            δ+             #   Addition vectorized on both sides
              €`           #   Flatten each element
                Ù          #   Uniquify
                 ʒ         #   Keep elements which..
                  {`9‹     #     Has a maximum element smaller than 9
                      *0›  #     And a minimum element larger than 0
Аднан
источник
Вы можете использовать •eĆ•SÍü‚вместо того, Ƶ‡4в2ô<D(«чтобы сохранить 2 байта.
Emigna
@ Emigna Ааа, это умно, спасибо!
Аднан
2

Python 3, 105 байт

p=lambda g,i:i and list(set(p([x+y for x in g for y in[6,10,15,17,-6,-10,-15,-17]if 0<=x+y<64],i-1)))or g

Приходится использовать именованную лямбду для рекурсии. Не уверен, что это дисквалифицирует. Перейдите в стартовые позиции в виде списка 0-индексированных квадратных чисел. 0 считается как без ходов.

mypetlion
источник
2

Java (OpenJDK 8) , 124 байта

(m,p)->{for(;m-->0;)for(long a=p,i=p=0,j;i<64;i++)for(j=64;j-->0;)p|=(p=i%8-j%8)*p+(p=i/8-j/8)*p==5?(a>>i&1)<<j:0;return p;}

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

Формат ввода / вывода

Ввод / вывод представлен в виде битов в long(64 бита): установленные биты означают наличие лошади, неустановленные биты означают отсутствие лошади. Пример:

// [[0, 0]]
0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000001L

Пояснения

(m, p) -> {                          // Lambda. No currying because m and p are modified
 for(;m-->0;)                        // For each move
  for(long a=p,i=p=0,j;i<64;i++)     // Declare variables, move p to a, create a new p and loop on bits of a.
   for(j=64;j-->0;)                  // Loop on bits of p.
    p |=                             // Assign to p a value.
     (p=i%8-j%8)*p+(p=i/8-j/8)*p==5  // If i -> j is a valid horse move, see Arnauld's JavaScript answer for full explanations
      ? (a>>i&1)<<j                  // Assign the presence of the horse (i-th bit of a) to the resulting board (j-th bit of p).
      : 0;                           // Else it's not a valid horse move
 return p;
}

кредиты

  • 19 байтов сэкономлено благодаря Nevay!
  • Повторно использовал (X-x)²+(Y-y)²==5трюк из ответа Арнаулда на JavaScript
  • Еще 1 байт сохранен благодаря Nevay в новом алгоритме!
  • Благодаря Nevay снова удалось сэкономить еще 7 байтов, переключившись с int[]64-битного режима long.
Оливье Грегуар
источник
1
169 байт: (m,p)->{for(;m-->0;){int i=64,a[]=p,x,y,u[]={1,3,5,9,15,19,21,23};for(p=new int[i];i-->0;)for(int z:u)if((((x=i/8+z/5-2)|(y=i%8+z%5-2))&-8)==0)p[x*8+y]|=a[i];}return p;}
Nevay
1
-1 байт:(m,p)->{for(int i,j,a[],x;m-->0;)for(a=p,p=new int[i=64];i-->0;)for(j=64;j-->0;)p[j]|=(x=i%8-j%8)*x+(x=i/8-j/8)*x==5?a[i]:0;return p;}
Невай
Спасибо @Nevay! Добавление кода для удаления скобок / блоков всегда приятно! ;-)
Оливье Грегуар,
1
-7 байт, заменив int[]на long:(m,p)->{for(long i,j,a;m-->0;)for(a=p,p=i=0;i<64;i++)for(j=64;j-->0;)p|=(p=i%8-j%8)*p+(p=i/8-j/8)*p==5?(a>>i&1)<<j:0;return p;}
Nevay
Ура, я даже не думала делать это! Отличная работа, @Nevay ;-)
Оливье Грегуар,
2

Желе , 29 28 байт

8Rp`
“¦Ʋƈ2’D_2ṡ2+€µẎ
ÇƓ¡f1£Q

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

Количество ходов через STDIN, а квадраты - аргумент.

Это связывает решение Jelly от HyperNeutrino, но с другим подходом.

Теперь бьем @HyperNeutrino на 1 байт!

Любые предложения выбить некоторые байты нужны!

Ссылка 1 (Шахматная доска)

8Rp`
8R   = The list [1,2,3,4,5,6,7,8]
  p` = cartesian multiplied with itself (this results in the chessboard)

Ссылка 2 (Поколение движения)

“¦Ʋƈ2’D_2ṡ2+€µẎ
“¦Ʋƈ2’          = the number 103414301
      D         = converted into a list of digits
       _2       = subtract two from each element
         ṡ2     = overlapping pairs
           +€   = add to the list of squares
             µ  = Make sure the next part isn't treated as a right argument
              Ẏ = Tighten the list (Reducing the depth by one)

Ссылка 3 (проверка квадрата)

ÇƓ¡f1£Q
ÇƓ¡     = Repeat link #2 the requested amount of times
   f1£  = Remove everything not a member of link #1 (not on the chess board)
      Q = Make sure squares don't appear more than once
Zachary
источник
1

Шелуха , 18 байт

u!¡ṁö`fΠR2ḣ8=5ṁ□z-

Используется индексирование квадратов и шагов на основе 1. Попробуйте онлайн!

объяснение

u!¡ṁö`fΠR2ḣ8=5ṁ□z-  Implicit inputs, say P=[[1,1],[5,7]] and n=2
  ¡                 Iterate on P:
   ṁö               Map the following function, then concatenate:
                     Argument is a pair, say p=[5,7].
          ḣ8         The range [1,2,..,8]
       ΠR2           Repeat twice, take cartesian product: [[1,1],[1,2],..,[8,8]]
     `f              Filter with this predicate:
                      Argument is a pair, say q=[3,8].
                z-    Zip p and q with difference: [-2,1]
              ṁ□      Sum of squares: 5
            =5        Is it 5? Yes, so [3,8] is kept.
 !                  Take n'th step of the iteration.
u                   Remove duplicates, implicitly print.
Zgarb
источник
1

R , 145 183 134 байт

Это результат отличной игры в гольф Джузеппе с моим первоначальным алгоритмом не слишком для игры в гольф (см. Комментарий ниже)

function(x,n){x=x%/%8*24+x%%8
t=c(49,47,26,22)
t=c(t,-t)
for(i in 1:n)x=intersect(v<-outer(1:8,0:7*24,"+"),outer(x,t,"+"))
match(x,v)}

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

Вход и выход основаны на 1 ... 64. Занимает вектор положения с использованием нотации 1 ... 64. Сопоставляет его с нотацией 1: 576, которая представляет собой суперплату из девяти досок. В этой нотации на каждой итерации каждый рыцарь должен иметь возможность двигаться на +/- 22,26,47,49. Вернуть будущие позиции обратно в нотацию 1 ... 64, исключая те, которые падают с центральной доски. Пример TIO отображает результат с использованием матрицы 8x8.

NofP
источник
Похоже, что это не сработает в первом тестовом примере (он возвращает 4 координаты вместо 2).
Згарб
Спасибо за указание на это, Згарб, думаю, я исправил проблему сейчас
NofP
154 байта
Джузеппе
или 148 байт, если [0...63]вместо этого вы берете его в нотации.
Джузеппе
1
134 байта , [1..64]для ввода и вывода. +1, тем не менее, это отличный ответ.
Джузеппе