หลบหนีกระดานหมากรุก


23

คุณพบว่าตัวเองอยู่บนกระดานหมากรุกอย่างที่คิด คุณสามารถเห็นทางออก แต่มันอยู่ไกลมากและคุณจะไม่เดินไปตลอดทาง โชคดีที่ชาวบ้านบางคนเสนอให้คุณนั่ง อัศวินผู้โกงนักบวชและราชาต่างก็เต็มใจที่จะพาคุณไปยังจุดหมายปลายทางของคุณ แต่เมื่อเห็นว่านี่เป็นกระดานหมากรุกที่พวกเขาต้องปฏิบัติตามกฎของหมากรุกระหว่างทางไปยังปลายทางของคุณ คุณต้องการออกจากที่นี่โดยเร็วที่สุดคุณยอมรับข้อเสนอของใคร

งาน

ให้กระดานหมากรุกที่มีรูปร่างและขนาดโดยพลการและมีสองจุดบนกระดานหมากรุกให้นำเอาชิ้นส่วนหมากรุกที่สามารถเคลื่อนที่ระหว่างสองตำแหน่งในเวลาไม่กี่วินาที บอร์ดจะไม่จำเป็นต้องมีความหมายอย่างต่อเนื่องซึ่งอาจมีช่องว่างระหว่างส่วนของกระดาน แต่ละสี่ชิ้น (ราชาโกงอัศวินและบิชอป) สามารถย้ายตามกฎมาตรฐานในหมากรุก ชิ้นส่วนของราชินีและจำนำได้ถูกทิ้งไว้โดยไม่เจตนาจากความท้าทายนี้

I / O

คุณสามารถป้อนข้อมูลในรูปแบบที่เหมาะสมและคุณอาจส่งออกในรูปแบบใดก็ได้ที่คุณเลือกเช่นกัน อินพุตและเอาต์พุตของคุณต้องสอดคล้องกัน หากหลายชิ้นสามารถไปถึงปลายทางในจำนวนการเคลื่อนไหวเท่ากันคุณจะต้องส่งออกชิ้นส่วนทั้งหมดที่สามารถไปถึงได้ในเวลาขั้นต่ำ หากไม่มีสี่ชิ้นใดที่สามารถทำให้จบคุณสามารถเอาท์พุทอะไรก็ได้ตราบใดที่มันแตกต่างจากผลลัพธ์อื่น ๆ ที่เป็นไปได้ทั้งหมด ซึ่งอาจรวมถึงการแสดงผลอะไรหรือโยนข้อผิดพลาด

กรณีทดสอบ

สี่เหลี่ยมหมายถึงจุดเริ่มต้นและวงกลมแสดงถึงจุดสิ้นสุด


ทดสอบ 1

โคน


ทดสอบ 2

อัศวิน


ทดสอบ 3

กษัตริย์


ทดสอบ 4

โกง


ทดสอบ 5

ราชาอัศวิน


ทดสอบ 6

ไม่มี


ดี ฉันชอบสิ่งนี้ แต่ไม่ใช่ "กระดานหมากรุกที่มีรูปร่างและขนาดที่กำหนดเอง" เป็นเอนทิตีเดียวใช่ไหม ฉันไม่เห็นจริง ๆ ว่าตัวอย่างที่ 2 และ 6 สอดคล้องกับสิ่งนี้อย่างไรเนื่องจากดูเหมือนว่าพวกมันเป็นกระดานสองแผ่นที่อัศวินเท่านั้นที่สามารถกระโดดข้ามได้ บางทีฉันอาจจะหายไปบางสิ่งบางอย่าง?
ElPedro

2
@ElPedro พวกเขายังคงเป็นบอร์ดเดียวไม่ใช่แค่บอร์ดต่อเนื่อง ส่วนหนึ่งของรูปร่างโดยพลการคือแผงสามารถไม่ต่อเนื่อง
ข้าวสาลีตัวช่วยสร้าง

ตัวอย่างที่ 3 ไม่ควรเป็น "ราชาราชินี" ใช่ไหม
Kritixi Lithos

ขอบคุณ @ ความร้อน ไม่แน่ใจว่าชัดเจนจากคำถาม แต่ฉันเข้าใจแล้ว
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สำหรับ Knight, 2Rook, 3Bishop และ4King หากไม่พบวิธีแก้ไขมันจะล้นสแต็กอย่างสม่ำเสมอ (ซึ่งนับว่าเป็นการโยนข้อผิดพลาดใช่ไหม)

แรงบันดาลใจที่นำมาจากบท LYAH บน Monads- (%)เป็นเพียงทั่วไปและแข็งแรงเล่นกอล์ฟinManyกับเทียบเท่า(&) (Control.Monad.<=<)ทุกสิ่งทุกอย่างควรเป็นคำอธิบายที่มากขึ้น

นี่สามารถเล่นกอล์ฟได้มากขึ้น แต่ตอนนี้ฉันสนุกพอแล้ว

Ungolfed:

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

Mathematica, 326 325 bytes

ขอบคุณ 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@ry@b

ในที่สุดบรรทัดที่ 9 ถึง 11 จะเลือกองค์ประกอบของ{b, k, n, r}เส้นทางที่สั้นที่สุดระหว่างจุดยอดเป้าหมายสองแห่ง FindShortestPathจะโยนข้อผิดพลาดและคืนค่าที่ไม่ประเมินค่าถ้าจุดยอดเป้าหมายไม่ปรากฏในกราฟ (ซึ่งจะเกิดขึ้นหากไม่มีขอบเกิดจากมัน) ดังนั้นเราจึงใช้h@__ -> 0เพื่อส่งกลับ0ในกรณีเหล่านั้นแทน และการขาดเส้นทางระหว่างจุดยอดที่ถูกต้องส่งคืนรายการความยาว0ดังนั้นMin[z~Complement~{0}]คำนวณความยาวของเส้นทางที่เล็กที่สุดที่มีอยู่จริงโดยไม่สนใจกรณีที่ไม่ดีข้างต้น


มีเหตุผลใดสำหรับ double f ในชื่อฟังก์ชั่น? หรือเป็นข้อ จำกัด ทางคณิตศาสตร์?
masterX244

โอ้ฮ่าฮ่าไม่มีข้อ จำกัด ทางจิตใจในส่วนของฉัน :) ฉันมีfในเซสชั่นที่แล้ว แต่ฉันควรจะมีการเปลี่ยนแปลงก่อนที่จะส่ง!
Greg Martin
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.