チェス盤を脱出する


23

自分がチェス盤に乗っているのを見つけます。あなたは出口を見ることができますが、それはひどく遠くにあり、あなたはむしろずっと歩きたくないでしょう。幸いなことに、地元の人たちがあなたに乗車を申し出ています。騎士、ルーク、司教、王は皆あなたを目的地に連れて行きますが、これがチェス盤であることを見て、目的地に向かう途中でチェスのルールを順守しなければなりません。できるだけ早くここから出たいと思いますが、誰の申し出を受け入れますか?

仕事

任意の形状とサイズのチェス盤とチェス盤上の2つのポイントが与えられた場合、できるだけ少ない移動で2つの場所の間を移動できるチェスの駒を出力します。取締役会は必ずしも継続的ではなく、取締役会のセクション間にギャップがある可能性があることを意味します。4つのピース(キング、ルーク、ナイト、ビショップ)はそれぞれ、チェスの標準ルールに従って移動できます。クイーンとポーンの駒は、この挑戦​​から意図的に除外されています。

I / O

任意の合理的な形式で入力を受け付け、選択した任意の形式で出力することもできます。入力と出力は一貫したものでなければなりません。複数のピースが同じ移動数で目的地に到達できる場合、最短時間でそこに到達できるすべてのピースを出力する必要があります。4つの部分のいずれも最後まで到達できない場合、他のすべての可能な出力とは異なる限り、何でも出力できます。これには、何も出力しないか、エラーをスローすることが含まれます。

テストケース

正方形は開始点を示し、円は終了点を示します。


テスト1

司教


テスト2

騎士


テスト3

キング


テスト4

ルーク


テスト5

キング、ナイト


テスト6

なし


いいね 私はこれが好きですが、「任意の形とサイズのチェス盤」は単一のエンティティではありませんか?例2と例6がこれにどのように適合するかは実際にはわかりません。それらは、ナイトのみがジャンプできる2つの別個のボードのように見えます。たぶん私は何かが欠けていますか?
エルペドロ

2
@ElPedroそれらはまだ単一のボードであり、連続したボードではありません。任意の形状の一部は、ボードが非連続であることです。
小麦ウィザード

例3では、「王様、女王」ではないでしょうか。
KritixiのLithos

@小麦に感謝します。それが質問から明らかだったのかどうかはわかりませんが、私は今理解しています。
エルペドロ

2
@KritixiLithos物事を面白くするために、クイーンやポーンはありません。
小麦ウィザード

回答:


8

Haskell447 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キングの。解決策が見つからない場合は、一貫してスタックがオーバーフローします(エラーをスローするものとしてカウントされますよね?)。

モナドに関するLYAHの章からインスピレーションを得(%)たものは、単に一般化されゴルフさ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

Mathematica、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}]]);

機能を定義f3つの引数を取るには:gボード表す整数の順序対のリストである、とwしてx開始と終了の正方形を表すペアを命じました。出力は{b, k, n, r}、2つの正方形の間の最小移動パスを持つ(それぞれ司教、王、騎士、およびルークを表す)サブセットです。たとえば、3番目のテストケースはによって呼び出されf[{{0, 0}, {1, 1}, {1, 2}, {0, 3}}, {0, 0}, {0, 3}]、戻ります{k}。最後の2つのテストケースはそれぞれ{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@#は、これらの隣接グラフの1つを取得し、その接続コンポーネントを見つけます。これは、頂点のすべてのラインセグメントを特定の方向にグループ化することに対応します(ルークまたはビショップが1つずつ移動する必要がないように)。次にe@t@#、6行目で、同じ接続されたコンポーネント内の頂点のすべてのペアの間にエッジを配置し、それらFlattenを1つのグラフにまとめます。したがって、6行目から8行目は、ルークのグラフy@rと司教のグラフを定義していますy@b

最後に、9行目から11行目{b, k, n, r}で、2つのターゲット頂点間の最短パスを生成する要素を選択します。FindShortestPathは、ターゲット頂点がグラフに表示されない場合はエラーをスローし、未評価で返します(エッジが発せられない場合に発生します)。そのため、代わりにこれらの場合にh@__ -> 0戻り0ます。また、有効な頂点間にパスがない場合、lengthのリストが返される0ためMin[z~Complement~{0}]、実際に存在する最小パスの長さを計算し、上記の悪いケースを無視します。


関数名に二重fがある理由は何ですか?それとも数学の限界ですか?
masterX244

ああ、ハハ、いいえ、それは私の側の精神的な制限です:)私はfそのセッションですでに持っていましたが、提出する前にそれを変更する必要がありました!
グレッグマーティン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.