Де лицар може бути в 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]?
Дейв

@Dave Звичайно, чому б і ні? Просто відповідайте вводу-виводу.
Adám

8
Клянусь, я читав цей HNQ як "Куди переходить лицар у Ні",
Сідні

3
Попередження про каламбур: позначення для лицаря є Н.
Джошуа

Чи можемо ми використовувати індексацію на основі 1 за кількістю кроків? Напр.[[1,1]], 2 -> [[2,3],[3,2]]
Згарб

Відповіді:


11

Мова Вольфрама (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]&.

1
Я не думаю, що немає нічого поганого в тому, щоб перемогти існуюче рішення.
Adám

1
Чи працює це з кількома вихідними положеннями?
Adám

Дивовижний! Тепер мені потрібно розібратися, як ти це читав ...
Дейв

Це, мабуть, буде 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

Тестові кейси

Цей фрагмент включає дві допоміжні функції для перекладу з та у формат, передбачений ОП.

Як?

Перехід від (x, y) до (X, Y) є дійсним ходом лицаря, якщо у нас є:

  • | xX | = 1 і | yY | = 2 , або
  • | xX | = 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 разів.


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

5

Сітківка , 147 102 байти

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

Спробуйте в Інтернеті! Приймає дані як дошка 8х8 :з лицарями, позначеними 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)

1
0-індексований желе?
Adám

1
@ Adám Полегшує фільтрацію: P
HyperNeutrino

2
Я очікую, що Jelly зможе це зробити в 15 байтах, оскільки нинішній рекордсмен в APL робить це в 24 символи.
Адам

Коли у вас є> = 3 $, цілком ймовірно, що ви можете перейти на попереднє посилання та повернутися до Ç.
користувач202729

@ 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 Ах, це розумно, дякую!
Аднан

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 вважається відсутністю ходу.


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 байт збережено завдяки Невайю!
  • Повторно використали (X-x)²+(Y-y)²==5хитрість з відповіді на JavaScript Арнаульда
  • Ще 1 байт збережено завдяки Nevay в новому алгоритмі!
  • Ще 7 байтів збереглися завдяки Nevay знову, перейшовши 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;}
Невай

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 ;-)
Олів'є

2

Желе , 29 28 байт

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

Спробуйте в Інтернеті!

Кількість витків здійснюється через STDIN, а квадрати - аргумент.

Це пов'язує @ HyperNeutrino Jelly рішення, але з іншим підходом.

Тепер побийте @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

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.

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.


Здається, це не виходить у першому тестовому випадку (він повертає 4 координати замість 2).
Згарб

Дякую, що вказав на це Згарб, я думаю, що я
вирішив


або 148 байт, якщо ви [0...63]замість цього взяли його в нотації.
Джузеппе

1
134 байт , [1..64]для введення і виведення. +1, однак, це відмінна відповідь.
Джузеппе
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.