私をここから連れ出してください


12

チャレンジ

グリッドサイズ、障害物の位置、プレイヤーの位置、ターゲットの位置を考えると、プレイヤーがターゲットに到達し、同時に障害物を回避するためのパスを見つけることが必要です。

ここに画像の説明を入力してください


入力

  • N:グリッドサイズN x N
  • P:プレイヤーの位置[playerposx, playerposy]
  • T:ターゲットの位置[targetposx, targetposy]
  • O:障害物の位置[[x1, y1], [x2, y2],...,[xn, yn]]

出力

パス:パスプレーヤーはターゲットに到達するために使用できます[[x1, y1], [x2, y2],...,[xn, yn]]


ルール

  1. ポイント[0,0]はグリッドの左上隅にあります。
  2. プレイヤーの位置は常にグリッドの左側になります。
  3. ターゲットの位置は常にグリッドの右側になります。
  4. グリッドには常に少なくとも1つの障害があります。
  5. プレーヤーまたはターゲットの位置に障害物が重なっていないと想定できます。
  6. 必ずしも最小パスを見つける必要はありません。
  7. プレイヤーは、左、右、上、下のみを斜めに移動することはできません。
  8. 任意の便利な方法で入力を取得できます。
  9. プレイヤーがターゲットに到達するためのパスは常に存在すると仮定できます。
  10. 明らかに、入力ごとに複数の有効なパスが存在するため、1つを選択します。
  11. N > 2グリッドが少なくともであると仮定し3 x 3ます。

入力:9[6, 0][3, 8][[0, 5], [2, 2], [6, 4], [8, 2], [8, 7]]
可能な出力:[[6, 0], [6, 1], [6, 2], [6, 3], [5, 3], [5, 4], [5, 5], [5, 6], [5, 7], [5, 8], [4, 8], [3, 8]]

入力:6[1, 0][3, 5][[1, 2], [2, 5], [5, 1]]
可能な出力:[[1, 0], [1, 1], [2, 1], [2, 2], [2, 3], [2, 4], [3, 4], [3, 5]]


注意

これXは行と列のYためです。それらを画像内の座標と混同しないでください。

編集

@digEmAllが指摘したように、ルール#2#3playerY = 0およびのためtargetY = N-1です。そのため、必要に応じて、入力としてのみplayerXとand targetXを使用できます(コードが短くなる場合)。


1
「プレイヤーの位置は常に左側にあり、ターゲットは右側にあります」:これは、player-y = 0およびtarget-y = N-1を意味しますか?もしそうなら、プレーヤーとターゲットのx座標(1つの数字)をそのまま受け入れることができますか?
digEmAll

1
@digEmAll良い点。正直なところ、私はこれを考えていませんでした。はい、編集できます。
DimChtz

関連するが簡単。関連するが難しい。
user202729

パスは最初から最後までである必要がありますか、それとも逆の順序にすることはできますか?
kamoroso94

1
@ kamoroso94はい、ターゲット設定を開始(完了):)
DimChtz

回答:


5

JavaScript(ES6)、135バイト

入力をとして受け取ります。(width, [target_x, target_y], obstacles)(source_x, source_y)ここで、障害物"X,Y"形式の文字列の配列です。

文字列の配列を"X,Y"フォーマットで返します。

(n,t,o)=>g=(x,y,p=[],P=[...p,v=x+','+y])=>v==t?P:~x&~y&&x<n&y<n&[...o,...p].indexOf(v)<0&&[0,-1,0,1].some((d,i)=>r=g(x+d,y-~-i%2,P))&&r

オンラインでお試しください!

コメント済み

(n, t, o) =>              // n = width of maze, t[] = target coordinates, o[] = obstacles
  g = (                   // g() = recursive search function taking:
    x, y,                 //   (x, y) = current coordinates of the player
    p = [],               //   p[] = path (a list of visited coordinates, initially empty)
    P = [                 //   P[] = new path made of:
      ...p,               //     all previous entries in p
      v = x + ',' + y     //     the current coordinates coerced to a string v = "x,y"
    ]                     //
  ) =>                    //
    v == t ?              // if v is equal to the target coordinates:
      P                   //   stop recursion and return P
    :                     // else:
      ~x & ~y             //   if neither x nor y is equal to -1
      && x < n & y < n    //   and both x and y are less than n
      & [...o, ...p]      //   and neither the list of obstacles nor the path
        .indexOf(v) < 0   //   contains a position equal to the current one:
      && [0, -1, 0, 1]    //     iterate on all 4 possible directions
        .some((d, i) =>   //     for each of them:
          r = g(          //       do a recursive call with:
            x + d,        //         the updated x
            y - ~-i % 2,  //         the updated y
            P             //         the new path
          )               //       end of recursive call
        ) && r            //     if a solution was found, return it

5

R、227バイト

function(N,P,G,O){M=diag(N+2)*0
M[O+2]=1
b=c(1,N+2)
M[row(M)%in%b|col(M)%in%b]=1
H=function(V,L){if(all(V==G+2))stop(cat(L))
M[t(V)]=2
M<<-M
for(i in 0:3){C=V+(-1)^(i%/%2)*(0:1+i)%%2
if(!M[t(C)])H(C,c(L,C-2))}}
try(H(P+2,P),T)}

オンラインでお試しください!

それほど短くはなく、間違いなく最短経路を与えません(たとえば、最初の例を確認してください)。
基本的に再帰的な深さ優先検索を実行し、ターゲットに到達するとすぐに停止し、パスを出力します。

JayCeの出力フォーマットの改善に感謝


+1私はあなたが出力を印刷する方法が好きです(リストの典型的な退屈なリストではありません):)
DimChtz

@DimChtz:まあありがとうございます...それはヘルパー関数です、コードゴルフ関数は座標のリストを出力するだけx1 y1 x2 y2 ... xn ynです:D
digEmAll

1
はい、わかります:P
DimChtz

1
@DimChtzに同意します...そして、あなたwrite(t(mx),1,N)printingする代わりにもっと良く見えると思います:)
JayCe

@JayCe:良いアイデア、変わった!
digEmAll


3

Haskell133 131130バイト

  • BWOのおかげで-1バイト
(n!p)o=head.(>>=filter(elem p)).iterate(\q->[u:v|v@([x,y]:_)<-q,u<-[id,map(+1)]<*>[[x-1,y],[x,y-1]],all(/=u)o,x`div`n+y`div`n==0])

オンラインでお試しください!(いくつかのテストケース付き)

!入力として受け取る関数

  • n :: Int グリッドのサイズ
  • p :: [Int] リストとしてのプレイヤーの位置 [xp, yp]
  • o :: [[Int]] リストとしての障害物の位置 [[x1, y1], [x2, y2], ...]
  • t :: [[[Int]]](暗黙的)リストとしてのターゲットの位置[[[xt, yt]]](便宜上、トリプルリスト)

有効なパスをリストとして返します [[xp, yp], [x1, y1], ..., [xt, yt]]

ボーナスとして、最短経路(の1つ)を検出し、任意のプレーヤーとターゲットの位置に対して機能します。一方、それは非常に非効率的です(ただし、提供されている例は妥当な時間で実行されます)。

説明

(n ! p) o =                                                         -- function !, taking n, p, o and t (implicit by point-free style) as input
    head .                                                          -- take the first element of
    (>>= filter (elem p)) .                                         -- for each list, take only paths containing p and concatenate the results
    iterate (                                                       -- iterate the following function (on t) and collect the results in a list
        \q ->                                                       -- the function that takes a list of paths q...
            [u : v |                                                -- ... and returns the list of paths (u : v) such that:
                v@([x, y] : _) <- q,                                -- * v is an element of q (i.e. a path); also let [x, y] be the first cell of v
                u <- [id, map (+ 1)] <*> [[x - 1,y], [x, y - 1]],   -- * u is one of the neighbouring cells of [x, y]
                all (/= u) o,                                       -- * u is not an obstacle
                x `div` n + y `div` n == 0                          -- * [x, y] is inside the grid
            ]
    )

この関数はiterate、ターゲットから開始してプレイヤーの開始位置に到達することにより、再帰的なBFSを実行します。長さのパスk 長さの有効なパスに適切なセルを追加することにより取得されます k1、長さ1の唯一の有効なパス、つまりpathから始まります[[xt, yt]]

一見曖昧な表現[id, map (+ 1)] <*> [[x - 1,y], [x, y - 1]]は、単なる「ゴルフ」(-1バイト)バージョンです[[x + 1, y], [x, y + 1], [x - 1, y], [x, y - 1]]


2
PPCGへようこそ!素敵な最初の答え!
アーナウルド

1
@Arnauldありがとう!私は実際にあなたの135を打つために私のソリューションから数バイトを
絞ろ

1
素敵なゴルフ!関数の代わりに演算子を使用して1バイトを保存できます。オンラインで試してください!
ბიმო

@BWOヒントをありがとう。私はここにいるので、聞いたことがない多くのトリックがあります
Delfad0r

1
ところで Haskellのヒントが記載されたセクションがあり、このセクションやその他のトリックを見つけることができます。:ああ、あまりにもチャットは常にありますモナドと男性の
ბიმო

1

Retina 0.8.2、229バイト

.
$&$&
@@
s@
##
.#
{`(\w.)\.
$1l
\.(.\w)
r$1
(?<=(.)*)\.(?=.*¶(?<-1>.)*(?(1)$)\w)
d
}`\.(?=(.)*)(?<=\w(?(1)$)(?<-1>.)*¶.*)
u
+T`.`#`.(?=(.)*)(?<=d#(?(1)$)(?<-1>.)*¶.*)|(?<=(.)*.).(?=.*¶(?<-2>.)*(?(2)$)u#)|(?<=#r).|.(?=l#)
.(.)
$1

オンラインでお試しください!I / O形式が適切かどうかわからない。説明:

.
$&$&

各セルを複製します。左側のコピーは一時的な作業領域として使用されます。

@@
s@

迷路の開始点を訪問済みとしてマークします。

##
.#

空の迷路の終わりをマークします。

{`(\w.)\.
$1l
\.(.\w)
r$1
(?<=(.)*)\.(?=.*¶(?<-1>.)*(?(1)$)\w)
d
}`\.(?=(.)*)(?<=\w(?(1)$)(?<-1>.)*¶.*)
u

使用可能なワーキングセルが存在している間に、それらを以前に訪れた隣接するセルに向けます。

+T`.`#`.(?=(.)*)(?<=d#(?(1)$)(?<-1>.)*¶.*)|(?<=(.)*.).(?=.*¶(?<-2>.)*(?(2)$)u#)|(?<=#r).|.(?=l#)

作業セルをガイドとして使用して、出口から開始までのパスをトレースします。

.(.)
$1

作業セルを削除します。


1

JavaScript、450バイト

入力をとして受け取ります(n, {playerx, playery}, {targetx, targety}, [{obstaclex, obstacley}])。の配列を返します{hopx, hopy}

j=o=>JSON.stringify(o);l=a=>a.length;c=(a,o)=>{let i=l(a);while(i>0){i--;if(j(a[i])==j(o)){return 1;}}return 0;}h=(p,t,o)=>{if(p.y<t.y&&!c(o,{x:p.x,y:p.y+1})){return{x:p.x,y:p.y+1};}if(p.y>t.y&&!c(o,{x:p.x,y:p.y-1})){return{x:p.x,y:p.y-1};}if(p.x<t.x&&!c(o,{x:p.x+1,y:p.y})){return{x:p.x+1,y:p.y};}if(p.x>t.x&&!c(o,{x:p.x-1,y:p.y})){return{x:p.x-1,y:p.y};}return t;}w=(n,p,t,o)=>{let r=[];r.push(p);while(j(p)!==j(t)){p=h(p,t,o);r.push(p);}return r;}

これが私の混乱の難読化されていないバージョンです:

// defining some Array's function for proper comparaisons
json = (object) => { return JSON.stringify(object) };
length = (array) => { return array.length; }
contains = (array, object) => {
    let i = length(array);
    while (i > 0) {
    i--;
        if (json(array[i]) == json(object)) { return true; }
    }
    return false;
}
//return next found hop
getNextHop = (player, target, obstacles) => {
    //uggly serie of conditions
    //check where do we have to go and if there is an obstacle there
    if(player.y<target.y && !contains(obstacles, [x:player.x, y:player.y+1])) { return [x:player.x, y:player.y+1]; }
    if(player.y>target.y && !contains(obstacles, [x:player.x, y:player.y-1])) { return [x:player.x, y:player.y-1]; }
    if(player.x<target.x && !contains(obstacles, [x:player.x+1, y:player.y])) { return [x:player.x+1, y:player.y]; }
    if(player.x>target.x && !contains(obstacles, [x:player.x-1, y:player.y])) { return [x:player.x-1, y:player.y]; }
    return target;
}
//return found path
getPath = (gridsize, player, target, obstacles) => {
    let path = [];
    path.push(player);
    //while player is not on target
    while(json(player)!=json(target)) {
        player = getNextHop(player, target, obstacles); //gridsize is never used as player and target are in the grid boundaries
        path.push(player);
    }
    return path;
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.