兩點串連尋徑演算法
來源:互聯網
上載者:User
這個算是用我上次發布的連連看中的一個兩點串連演算法,上次發布了源碼以後,很多朋友發郵件或能過MSN尋問源碼中問題,演算法佔了一大部分,我當時答應會發一篇文章,詳細講解一下這個演算法,但由於最近忙於工作,所以一拖再拖,在這裡先說聲Sorry.
希望各位看了這個演算法後,能給點評價,謝謝。還有,上次把我連連看最終發布版拿到我在的C#開發群裡,沒想到一下子就發現了BUG,比較鬱悶的,主要平時也沒做測試,給女朋友玩的時候,都已經明確告訴她,這個不用點的,沒用的,這邊有用的。看來還是要好好測試一下,所以我決定過一兩天把那個最終版發布出來,希望大家幫忙測試一下(就當是工作之餘玩點小遊戲輕鬆一下)。 下面就來講演算法基本演算法如下:首先是知道它的要求:
1:兩個目標是相同的
2:兩個目標之間連接線的折點不超過兩個。(連接線由x軸和y軸的平行線組成) 那麼分析一下串連的情況可以看到,一般分三種情況
1:直線相連 2:一個折點 3:兩個折點。可以發現,如果有折點,每個折點必定有且至少有一個座標(x或者y)是和其中一個目標點是相同的,也就是說,折點必定在兩個目標點所在的x方向或y方向的直線上。
所以設計思路如下:
假設目標點 p1 , p2 ,如果有兩個折點分別為z1 , z2 那麼,所要進行的是
1:如果驗證p1 , p2 直線連線,則串連成立
2:搜尋以p1,p2的x,y方向四條直線即下文所講的十字路徑(可能某兩條直線會重合)上的有限點,每次取兩點作為z1,z2 ,驗證p1到z1/z1到z2/z2到p2 是否都能直線相連 ,是則串連成立。(如果z1=z2也就是只有一個折點,對判斷沒影響) 看下面的一個矩陣0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 9 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 9 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 希望串連的是兩個點(9)分別取出點1(3,2)和點2(12,5)的十字路徑(點1的路徑線以數字1表示,點2的路徑以數字2表示,交叉點任取一數),得結果也下,0 0 0 1 0 0 0 0 0 0 0 0 2 0 0 00 0 0 1 0 0 0 0 0 0 0 0 2 0 0 01 1 1 9 1 1 1 1 1 1 1 1 1 1 1 10 0 0 1 0 0 0 0 0 0 0 0 2 0 0 00 0 0 1 0 0 0 0 0 0 0 0 2 0 0 02 2 2 1 2 2 2 2 2 2 2 2 9 2 2 20 0 0 1 0 0 0 0 0 0 0 0 2 0 0 00 0 0 1 0 0 0 0 0 0 0 0 2 0 0 0 以上是具體思路,下面從代碼來具體講解思路,要判斷兩點是否可串連,首先要分別獲得這兩點的十字路徑, /// <summary>/// 獲點指定點的水平可達路徑/// </summary> private int[,] GetTempPointX(Common.Position p, int[,] buffer){// 橫向檢測,基點為1以左int nBufX = 1;buffer[0,0] = p.x;buffer[0,1] = p.y;for (int TmpX = p.x - 1; TmpX >= 0; --TmpX){ if (map[p.y,TmpX] == 0) { buffer[nBufX,0] = TmpX; buffer[nBufX,1] = p.y; ++nBufX; } else { break; } } // 橫向檢測,基點為1以右 for (short TmpX = (short)(p.x + 1); TmpX < Common.MAP_WIDTH; ++TmpX) { if (map[p.y,TmpX] == 0) { buffer[nBufX,0] = TmpX; buffer[nBufX,1] = p.y; ++nBufX; } else { break; } } buffer[nBufX,0] = -1; buffer[nBufX,1] = -1; return buffer;} /// <summary>/// 獲點指定點的垂直可達路徑/// </summary> private int[,] GetTempPointY(Common.Position p, int[,] buffer){ int nBufY = 1; buffer[0,0] = p.x; buffer[0,1] = p.y; // 縱向檢測,基點1以上 for (int TmpY = p.y - 1; TmpY >= 0; --TmpY) { if (map[TmpY,p.x] == 0) { buffer[nBufY,0] = p.x; buffer[nBufY,1] = TmpY; ++nBufY; } else { break; } } // 縱向檢測,基點1以下 for (int TmpY = p.y + 1; TmpY < Common.MAP_HEIGHT; ++TmpY) { if (map[TmpY,p.x] == 0) { buffer[nBufY,0] = p.x; buffer[nBufY,1] = TmpY; ++nBufY; } else { break; } } buffer[nBufY,0] = -1; buffer[nBufY,1] = -1; return buffer;} 獲得水平與垂直可達路徑的方法都已經有了,現在就可以進行判斷了 private bool CheckInLineX(int[,] buffer1, int[,] buffer2, bool isInternal){//判斷是否在同一條直線上,可加速檢測 if(CheckInLine(buffer1,buffer2)) {//該檢查方法CheckInLine略 return false; } // 橫向檢測:縱向通路檢測 // 連通標誌 bool isInLine = false; for (int nChkLink1 = 0; !(buffer1[nChkLink1,0] < 0 && buffer1[nChkLink1,1] < 0); ++nChkLink1) { // 設定同軸加速檢查標誌 bool bShortPass = false; for (int nChkLink2 = 0; !(buffer2[nChkLink2,0] < 0 && buffer2[nChkLink2,1] < 0); ++nChkLink2) { // 檢查是否在同一縱軸 if (buffer1[nChkLink1,0] == buffer2[nChkLink2,0]) { // 因為已經檢查到同軸點,所以設定同軸對比加速度檢查標誌為true bShortPass = true; // 計算對比點距離 int nStep = buffer1[nChkLink1,1] - buffer2[nChkLink2,1]; // 位移量 int OpNum; if (nStep > 0) { OpNum = -1; --nStep; } else { OpNum = 1; ++nStep; } isInLine = true; int tmpvx = buffer1[nChkLink1,0]; for (int mStep = nStep; mStep != 0; mStep += OpNum)//Math.Abs(mStep-0) < 1 { if (map[buffer1[nChkLink1,1] - mStep,tmpvx] == 0) { // 繼續檢查下一點 continue; } else { // 通路有阻礙,無法連通 isInLine = false; break; } } // 如果連通 if (isInLine == true) {#if DEBUG System.Windows.Forms.MessageBox.Show("Linked\n");#endif return true; } } else { // 判斷同軸加速檢查標誌,以確定檢查加速 if (bShortPass == true) { break; } } }}return false;}判斷的思路基本如下:從得到的兩個十字路徑中,先拿出橫軸(兩點的橫向線上的點),然後拿點1橫縱上的第一個連,找到點2橫縱上與其相對在同一直線上的點,然後判斷這兩個點是否可連能,如果可加通,則表示點1和點2是可連通的,如果不能連通,則拿點1橫軸上的下一個點,再去與點2橫軸上相應的點進行判斷,直到找到相連通的點或點1上的點全部判斷完。如果兩點的橫軸不能連通,然後比較兩點的縱軸。同軸加速檢查標誌是用來提早結束迴圈的,當兩個橫軸進行比較是否有點相連通時,其中一點如果比到與其同縱軸時,不管是否可連通,都不需要再比較下面的點。其實在這個地方可以加以修改,使其直接定位到對比軸內的相應位置(呵,由於比較忙,也沒空去搞這個東西,做完到現在已經好幾個月沒碰了) 這個演算法在連點上的擴充性不好,如果它的要求變成可以四折,五折,那樣的話,就很難擴充,相比之下,普通的那種尋路演算法,就要好多了,但我發現這個演算法在維度上的擴充比較好,如果將來有個3D的連連看,需要在3維空間中串連,也許這個演算法的擴充性可能會相對好一些。不知道各位有沒明白,其實我當時就覺得這個演算法好理解,才用它的,在效率上,我也不知道是這個演算法怎麼樣,或許還是大部分人用的尋路算好,希望各位評價一下這個演算法,給點意見,謝謝