もう一つの答えはすでにかなり長いので、そのままにしておきます。この答えははるかに良く、単純で、正しいですが、他の答えには間違った答えを生み出すいくつかのエッジケースがあります-私はその演習を読者に任せます。
注:わかりやすくするために改行が追加されています。ブロック全体が単一のクエリです
;with Walker(StartX,StartY,X,Y,Visited) as (
select X,Y,X,Y,CAST('('+right(X,3)+','+right(Y,3)+')' as Varchar(Max))
from puzzle
union all
select W.StartX,W.StartY,P.X,P.Y,W.Visited+'('+right(P.X,3)+','+right(P.Y,3)+')'
from Walker W
join Puzzle P on
(W.X=P.X and W.Y=P.Y+1 OR -- these four lines "collect" a cell next to
W.X=P.X and W.Y=P.Y-1 OR -- the current one in any direction
W.X=P.X+1 and W.Y=P.Y OR
W.X=P.X-1 and W.Y=P.Y)
AND W.Visited NOT LIKE '%('+right(P.X,3)+','+right(P.Y,3)+')%'
)
select X, Y, Visited
from
(
select W.X, W.Y, W.Visited, rn=row_number() over (
partition by W.X,W.Y
order by len(W.Visited) desc)
from Walker W
left join Walker Other
on Other.StartX=W.StartX and Other.StartY=W.StartY
and (Other.Y<W.Y or (Other.Y=W.Y and Other.X<W.X))
where Other.X is null
) Z
where rn=1
最初のステップは、すべてのセルで開始し、ステップをたどることなく可能な限り移動する「ウォーカー」再帰テーブル式を設定することです。セルが再訪問されないようにするためには、すべての開始点から訪問された各セルを格納する訪問済み列を使用します。特に、この条件AND W.Visited NOT LIKE '%('+right(P.X,3)+','+right(P.Y,3)+')%'
すでにアクセスしたセルを拒否します。
残りがどのように機能するかを理解するには、CTEの後に「StartX、StartYによるウォーカーオーダーから*を選択」を実行して「ウォーカー」CTEによって生成された結果を確認する必要があります。 5つのセルを持つ「ピース」は、少なくとも5つのグループに表示され、それぞれに異なる(StartX,StartY)
があります。 、ただし、各グループには5つの(X,Y)
がすべて含まれています 異なる「訪問済み」パスを持つピース。
サブクエリ(Z)は、LEFT JOIN + IS NULLを使用して、条件で定義された「最初のXY座標」を含む各グループの単一の行にグループを削除します
。 Other.StartX=W.StartX and Other.StartY=W.StartY
and (Other.Y<W.Y or (Other.Y=W.Y and Other.X<W.X))
(StartX、StartY)から開始してアクセスできる各セルを対象とし、同じグループ内の他のセルと比較し、他のセルが上位行にないセル、またはそれらが同じ行は、このセルの左側にあります。ただし、これでも結果が多すぎます。 (3,4)と(4,4)の2セルのピースだけを考えてみましょう:
StartX StartY X Y Visited
3 4 3 4 (3,4) ******
3 4 4 4 (3,4)(4,4)
4 4 4 4 (4,4)
4 4 3 4 (4,4)(3,4) ******
******
でマークされた(3,4)の「最初のXY座標」で2行が残ります 。必要な行は1つだけなので、Row_Numberを使用します。番号を付けているので、最長のVisited
を使用することをお勧めします。 パス。これにより、多くのが得られます。 私たちが得ることができるように、ピース内のセル。
最後の外部クエリは、類似した各(X、Y)グループから最初の行(RN =1)を取得するだけです。
各ピースのすべてのセルを表示するには、行を変更しますselect X, Y, Visited
真ん中に
select X, Y, (
select distinct '('+right(StartX,3)+','+right(StartY,3)+')'
from Walker
where X=Z.X and Y=Z.Y
for xml path('')
) PieceCells
この出力を与えるもの
X Y PieceCells
1 1 (1,1)(2,1)(2,2)(3,2)
3 4 (3,4)(4,4)
5 6 (5,6)
7 5 (7,5)(8,5)(9,5)
8 1 (10,1)(8,1)(8,2)(9,1)(9,2)(9,3)