Втеча шахова дошка


23

Ви опиняєтесь на шаховій дошці, як це робиться. Ви можете побачити вихід, але він жахливо далеко, і ви краще не ходите всю дорогу. На щастя, деякі місцеві жителі запропонували вам покататися. Лицар, Грак, Єпископ та Король готові відвезти вас до місця призначення, але бачачи, як це шахова дошка, вони повинні дотримуватися правил шахів на шляху до місця призначення. Ви хочете якнайшвидше піти звідси, чию пропозицію ви приймаєте?

Завдання

Враховуючи шахову дошку довільної форми та розміру та дві точки на шаховій дошці, виведіть шахову фігуру, яка може переміщатися між двома місцями якомога рідше. Дошки необов'язково матимуть суцільне значення, що може виникнути прогалини між секціями дошки. Кожна з чотирьох фігур (Король, Ладья, Лицар та Єпископ) може рухатися згідно зі своїми стандартними правилами в шахах. Королева і пішаки пішаків навмисно залишилися від цього виклику.

I / O

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

Випробування

Квадрат позначає початкову точку, а коло - кінцеву точку.


Тест 1

Єпископ


Тест 2

Лицар


Тест 3

Король


Тест 4

Ладья


Тест 5

Король, лицар


Тест 6

Немає


Приємно. Мені це подобається, але чи не "шахова дошка довільної форми та розміру" є єдиним цілим? Я насправді не бачу, як приклади 2 і 6 вписуються в це, оскільки, схоже, це дві окремі дошки, між якими може стрибати тільки лицар. Може, я щось пропускаю?
ElPedro

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

Наприклад, 3, чи не повинен це бути "королем, королевою"?
Kritixi Lithos

Дякую @Wheat. Не впевнений, що це було зрозуміло з питання, але я зараз розумію.
ElPedro

2
@KritixiLithos Щоб цікаво не було, немає ні королеви, ні пішака.
Пшеничний майстер

Відповіді:


8

Haskell , 447 439 437 432 байт

t=[1,2]
p=[(+),(-)]
f=filter
a=abs
(#)=elem
x?y=[min x y..max x y]
f&g=(\x->g x>>=f)
(b!1)(c,r)=f(#b)[(c!d,r#s)|(!)<-p,(#)<-p,d<-t,s<-t,d/=s]
(b!2)(c,r)=f(\(d,s)->(c==d&&all(#b)[(c,z)|z<-r?s])||r==s&&all(#b)[(z,r)|z<-c?d])b
(b!3)(c,r)=f(\(d,s)->a(c-d)==a(r-s)&&all(#b)(zip(c?d)$r?s))b
(b!4)(c,r)=f(\(d,s)->a(c-d)<2&&a(r-s)<2)b
(b%p)n s=[s]>>=foldr(&)(:[])(replicate n$b!p)
g b s e=head$f(not.null)[[p|p<-[1..4],e#(b%p)n s]|n<-[0..]]

Виклик з використанням g <board> <start> <end>де <board> :: [(Int, Int)], <start> :: (Int, Int)і <end> :: (Int, Int). Повертає список, що містить 1для лицаря, 2для Рука, 3для єпископа та 4для короля. Якщо рішення не знайдено, воно послідовно переповнює стек (що вважається помилкою, що кидає, правда?).

Натхнення береться з глав Ляха на Monads- (%)просто узагальнено і golfed inManyз (&)еквівалентним (Control.Monad.<=<). Все інше повинно бути більш-менш зрозумілим.

Це, напевно, може бути набагато більше в гольфі, але мені зараз досить весело.

Безголівки:

data Piece = Knight | Rook | Bishop | King deriving (Show)
type Place = (Int, Int)
type Board = [Place]

x `to` y = [min x y..max x y]

f <=< g = (\x -> g x >>= f)

moves
    :: Board    -- available spaces
    -> Piece    -- type of piece
    -> Place    -- starting place
    -> [Place]  -- places available in one move
moves b Knight (c,r) =
    filter (`elem` b) [(c!d, r#s) |
                       (!) <- [(+),(-)], (#) <- [(+),(-)],
                       d <- [1,2], s <- [1,2], d/=s]
moves b Rook   (c,r) =
    filter (\(d,s) -> (c == d && all (`elem` b) [(c,z) | z <- r `to` s])
                    || r == s && all (`elem` b) [(z,r) | z <- c `to` d]) b
moves b Bishop (c,r) =
    filter (\(d,s) -> abs(c-d) == abs(r-s)
                && all (`elem` b) (zip (c `to` d) (r `to` s))) b
moves b King   (c,r) =
    filter (\(d,s) -> abs(c-d) <= 1 && abs(r-s) <= 1) b

canGoIn
    :: Board    -- available spaces
    -> Piece    -- type of piece
    -> Int      -- number of moves
    -> Place    -- starting place
    -> [Place]  -- places available in the specified number of moves
canGoIn b p n s =
    return s >>= foldr (<=<) return (replicate n (moves b p))

quickestPieces
    :: Board    -- available spaces
    -> Place    -- starting place
    -> Place    -- ending place
    -> [Piece]  -- quickest pieces
quickestPieces b s e =
        head $ filter (not.null)
            [[p | p <- [Knight, Rook, Bishop, King], elem e (canGoIn b p n s)] |
                n<-[0..]]

Приємне використання функціонального програмування!
Пшеничний майстер

5

Математика, 326 325 байт

Дякуємо masterX224 за вказівку економії байтів!

f[g_,w_,x_]:=(c={{1,1},{-1,1}};s=c.c/2;e=#<->#2&@@@#&;j=Join;h=FindShortestPath;t=#~Tuples~2&;a@d_:=e@Select[t@g,#-#2&@@#==d&];y@k=j@@(a/@j[s,c]);y@n=j@@(a/@{{1,2},{2,1},{-2,1},{-1,2}});v=Flatten[e@t@#&/@ConnectedComponents@a@#&/@#]&;y@r=v@s;y@b=v@c;Pick[p={b,k,n,r},z=Length[h[y@#,w,x]/.h@__->0]&/@p,Min[z~Complement~{0}]]);

Визначає функцію, яка fбере три аргументи: gце список упорядкованих пар цілих чисел, що представляють дошку, wі xвпорядковані пари, що представляють початкові та кінцеві квадрати. Вихід - це підмножина {b, k, n, r}(що представляє собою єпископа, царя, лицаря та грака відповідно), які мають мінімальний хід шляху між двома квадратами. Наприклад, третій тестовий випадок викликається f[{{0, 0}, {1, 1}, {1, 2}, {0, 3}}, {0, 0}, {0, 3}]і повертається {k}; останні два тестові справи повертаються {k, n}і {}, відповідно.

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

Більш зручна версія коду:

 1  f[g_, w_, x_] := ( c = {{1, 1}, {-1, 1}}; s = c.c/2;
 2    e = # <-> #2 & @@@ # &; j = Join; h = FindShortestPath; t = #~Tuples~2 &; 
 3    a@d_ := e@Select[t@g, # - #2 & @@ # == d &]; 
 4    y@k = j @@ (a /@ j[s, c]); 
 5    y@n = j @@ (a /@ {{1, 2}, {2, 1}, {-2, 1}, {-1, 2}}); 
 6    v = Flatten[e@t@# & /@
 7         ConnectedComponents@a@# & /@ #] &;
 8    y@r = v@s; y@b = v@c; 
 9    Pick[p = {b, k, n, r}, 
10      z = Length[h[y@#, w, x] /. h@__ -> 0] & /@ p, 
11      Min[z~Complement~{0}]]
12  );

У рядку 3 Select[g~Tuples~2, # - #2 & @@ # == dзнаходять усі впорядковані пари вершин, різницею яких є вектор d; eпотім перетворює кожну таку впорядковану пару в непрямий край графіка. Так aце функція, яка створює ребра між усіма вершинами, які відрізняються зафіксованим вектором.

Цього достатньо , щоб визначити, в рядках 4 та 5, графік короля y@k(який займає об'єднання ребер , породжених векторами {1, 1}, {-1, 1}, {0, 1}, і {-1, 0}) і графік лицаряy@n (який робить те ж саме з {1, 2}, {2, 1}, {-2, 1}і {-1, 2}).

У рядку 7 ConnectedComponents@a@# бере один із цих сусідніх графіків і потім знаходить його з'єднані компоненти; це відповідає групуванню всіх відрізків ліній вершин у заданому напрямку (щоб грак чи єпископ не повинен рухатися по них одна за одною). Потім e@t@#у рядку 6 ставлять ребра між кожною парою вершин у тому ж з'єднаному компоненті, які потім Flattenредагуються в єдиний графік. Таким чином, рядки 6 - 8 визначають граф грака та графік y@rєпископа y@b.

Нарешті, рядки з 9 по 11 вибирають елементи, {b, k, n, r}які дають найкоротший шлях між двома цільовими вершинами. FindShortestPathприведе помилку і повернеться неоціненою, якщо цільова вершина не з’явиться у графіку (що станеться, якщо з неї не вийдуть ребра), тому ми використовуємо h@__ -> 0для повернення 0в цих випадках. А відсутність шляху між дійсними вершинами повертає список довжини 0, тому Min[z~Complement~{0}]обчислює довжину найменшого шляху, який існує насправді, ігноруючи погані випадки вище.


будь-яка причина подвійного f у назві функції? чи це межа математики?
masterX244

о, ха-ха, ні, це не ментальна межа з моєї сторони :) У мене на fцьому сеансі вже було, але я повинен був змінити його перед подачею!
Грег Мартін
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.