跟着BOY學習--史上最通俗易懂的連連看算法--cocos2d-x 環境下開發

兄弟們大家好,本來說好的是星期五出連連看的。不過被我給睡過去了,這些天一直都很瞌睡。不過睡眠好了做事的效率就高。希望兄弟們不要見怪。廢話話不多說,首先我先說明說明一下《連連看地圖佈局之謎》

先上一張圖給大家看看

當大家看到這張圖片的時候會看到周圍一圈對號,這個是我做標記用的,當然 真正的開發遊戲過程中 這些對號是不存在的。我這裏想給大家說明的是 假如我們的 地圖是14*8的 那麼其實真正的地圖佈局應該是16*10 爲什麼要這麼做呢 那是因爲我們要讓我們所有的路線都從我們規定的方格內經過,不能越界。如果你是14*8 的那麼當四邊上有可以連通的時候 就要做大量的判斷來處理。那麼爲什麼我們不避免這些問題呢。這樣我們在規劃路線的時候 就不存在了特殊的情況。
   不知道大家是否明白我說的什麼意思。如果不懂的話可以給我留言我會給大家回覆 解答。
   關於圖片的生成我這裏說一下 如何保證所有的圖片 都是成對出現呢 這裏有個前提條件就是我們的地圖佈局一定要成偶數。那麼我們在生出圖片的 我們每一次取出一張圖片生成兩個一模一樣的 這樣就保證地圖裏面所有的圖片肯定是成對出現的。
  主要代碼是這樣的

  int totalcout=this->row*this->cloum;
                CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("point.plist","point.png");
                CCArray* temparry=CCArray::create();
                // 一次生成兩張一樣的
                for (int i=0;i<totalcout/2;i++){
                        int num=CCRANDOM_0_1()*35;//因爲是圖片的張數是從0到36張 所以隨機從0 到35
                        CustomSprite*  phit1=  CustomSprite::createWithSpritePicIndex(num,CCSize(picWidth,picHeight));                
                        CustomSprite*  phit2=  CustomSprite::createWithSpritePicIndex(num,CCSize(picWidth,picHeight));                
                        temparry->addObject(phit1);
                        temparry->addObject(phit2);
                }

 是不是很簡單啊
   至於如何把生成的東西給打亂。這個cocos2d-x 提供了很好用的方法那就是從數組中取出的時候 可以隨機去取出。
  下面把整個地圖佈局的方法給貼出來
bool LLKmapLayer::setUpdateView(){
        bool isRet=false;
        do {
                //得到需要的總張數  // 一定要是偶數
                int totalcout=this->row*this->cloum;
                CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("point.plist","point.png");
                CCArray* temparry=CCArray::create();
                // 一次生成兩張一樣的
                for (int i=0;i<totalcout/2;i++){
                        int num=CCRANDOM_0_1()*35;//因爲是圖片的張數是從0到36張 所以隨機從0 到35
                        CustomSprite*  phit1=  CustomSprite::createWithSpritePicIndex(num,CCSize(picWidth,picHeight));                
                        CustomSprite*  phit2=  CustomSprite::createWithSpritePicIndex(num,CCSize(picWidth,picHeight));                
                        temparry->addObject(phit1);
                        temparry->addObject(phit2);
                }

                for(int i=0;i<row+2;i++){
                        for(int j=0;j<this->cloum+2;j++){

                                if ((i==0)||(j==0)||(j==cloum+1)||(i==row+1)){
                                        CustomSprite*  temp=  CustomSprite::createWithSpritePicIndex(0,CCSize(picWidth,picHeight));
                                        temp->displayCustome();
                                        temp->setX(j);
                                        temp->setY(i);

                                        temp->setAnchorPoint(ccp(0,0));
                                        temp->setPosition(ccp(45*(j-1),51*(i-1)));
                                                this->addChild(temp);
                                        this->totalArray->addObject(temp);

                                }else {
                                        CustomSprite* phit=(CustomSprite*)temparry->randomObject();
                                        temparry->removeObject(phit,false);
                                        phit->setAnchorPoint(ccp(0,0));
                                        phit->setPosition(ccp(45*(j-1),51*(i-1)));
                                        this->addChild(phit);
                                        llkArray->addObject(phit);
                                        phit->setX(j);
                                        phit->setY(i);
                                        this->totalArray->addObject(phit);
                                }
                        }
                }
                isRet=true;        
        } while (0);
        return isRet;
}

是不是很少的代碼就實現了這個功能了。
下面就開始我們今天的重頭戲 那就是連連看的主要算法
首先先說明最簡單 那就是一線貫通。


大家看到我畫的紅線   是連連看中最簡單的 兩種連接方式 
   只要兩張圖片 處於同一水平線或者同一垂直線  如果兩張圖片中沒有別的圖片間隔就代表可以連通消除了
  主要代碼

// 這個是橫向檢測
CCArray* LLKAlgorithm::horizon(cocos2d::CCArray* llkArray,cocos2d::CCArray* hitArray){
        CustomSprite* hit1=(CustomSprite*)hitArray->objectAtIndex(0);// 取出第一個
        CustomSprite* hit2=(CustomSprite*)hitArray->objectAtIndex(1);// 取出第二個
        int x1=hit1->getX(); // 得到第一個X 座標
        int x2=hit2->getX(); // 得到第二個X 座標
        bool isda=x1>x2?true:false;// 得出那個座標肯後
        int temp=isda?x1-x2:x2-x1; // 獲取兩個兩個點之間的 間隔
        CCArray* temparray=CCArray::create();// 記錄兩個點之間 所經過的點

        if (temp==1){// 表示兩個是相鄰的兩個
                temparray->addObject(hit1);
                temparray->addObject(hit2);
        }else {    

                if (isda){
                        temparray->addObject(hit1);
                        temparray->addObject(hit2);
                        for(int i=1;i<temp;i++){
                                CustomSprite* hitteim=LLKAlgorithm::getCustByXandY(llkArray,x1-i,hit2->getY());
                                // 如果是已經消除的那麼 就可以繼續查詢
                                if (!hitteim->getIsEliminate()){
                                        LLKAlgorithm::removeAllArray(temparray,false);
                                        break;
                                }else {
                                        temparray->addObject(hitteim);
                                }
                        }

                }else {
                        temparray->addObject(hit2);
                        temparray->addObject(hit1);
                        for(int i=1;i<temp;i++){
                                CustomSprite* hitteim=LLKAlgorithm::getCustByXandY(llkArray,x2-i,hit2->getY());
                                // 如果是已經消除的那麼 就可以繼續查詢
                                if (!hitteim->getIsEliminate()){
                                        LLKAlgorithm::removeAllArray(temparray,false);
                                        break;
                                }else {
                                        temparray->addObject(hitteim);
                                }
                        }
                }

        }


        return temparray;

}
//這個是縱向檢測
CCArray*  LLKAlgorithm::vertical(cocos2d::CCArray* llkArray,cocos2d::CCArray* hitArray){
        CustomSprite* hit1=(CustomSprite*)hitArray->objectAtIndex(0);// 取出第一個
        CustomSprite* hit2=(CustomSprite*)hitArray->objectAtIndex(1);// 取出第二個
        int y1=hit1->getY(); // 得到第一個Y 座標
        int y2=hit2->getY(); // 得到第二個Y 座標
        bool isda=y1>y2?true:false;// 得出那個座標肯後
        int temp=isda?y1-y2:y2-y1; // 獲取兩個兩個點之間的 間隔
        CCArray* temparray=CCArray::create();// 記錄兩個點之間 所經過的點

        if (temp==1){// 表示兩個是相鄰的兩個
                temparray->addObject(hit1);
                temparray->addObject(hit2);
        }else {    

                if (isda){
                        temparray->addObject(hit1);
                        temparray->addObject(hit2);
                        for(int i=1;i<temp;i++){
                                CustomSprite* hitteim=LLKAlgorithm::getCustByXandY(llkArray,hit2->getX(),y1-i);
                                // 如果是已經消除的那麼 就可以繼續查詢
                                if (!hitteim->getIsEliminate()){
                                        LLKAlgorithm::removeAllArray(temparray,false);
                                        break;
                                }else {
                                        temparray->addObject(hitteim);
                                }
                        }

                }else {
                        temparray->addObject(hit2);
                        temparray->addObject(hit1);
                        for(int i=1;i<temp;i++){
                                CustomSprite* hitteim=LLKAlgorithm::getCustByXandY(llkArray,hit2->getX(),y2-i);
                                // 如果是已經消除的那麼 就可以繼續查詢
                                if (!hitteim->getIsEliminate()){
                                        LLKAlgorithm::removeAllArray(temparray,false);
                                        break;
                                }else {
                                        temparray->addObject(hitteim);
                                }
                        }
                }

        }



        return temparray;
}

其中返回的 array 就是兩個圖片的之間的路徑  包含兩張圖片在內。

對於兩張圖片是否可以垂直相連或者橫向相連這個我不用多講大家都應該明白怎麼去做。

下面講解一個拐角相連的情況
首先我先上張圖


      看到這張圖片的時候大家先看藍色矩形框裏面 是兩張可以經過一個拐角消除的圖片  但是怎麼確定兩張圖片可以經過一個拐角就可以連接呢 
   大家有沒有發現 這兩個張圖片剛好是矩形的兩個對角頂點 。也就是說圍繞着兩張圖片我們可以畫出一個最小的矩形,而矩形的其中兩個頂點就是這兩張圖片。
   好大家如果理解了這裏 我們就說下面的,如果不理解好好的想一下。既然已知矩形的 其中兩個頂點,那麼另外兩個頂點的座標也就輕鬆的計算出來。就是我們看到的兩個綠色的框。
    我們先拿出最上面的那個綠色的矩形框,我們發現他不是一個空白或者說已經消除的一個圖片 。那麼這個頂點是不符合規則的。我們看下面的那個綠色矩形框。 我們驚奇的發現 他竟然和我們選擇的那兩張(藍色框)圖片能直接連通 也就是通過這個綠色的矩形框(已經消除掉的) 我們可以把他轉化成 一個橫向可以連通和一個縱向可以連通的。
    看到這裏有的人或許已經恍然大悟了。其實我們要向知道兩個點是否可以經過一個拐角相連,我們首先要確定兩個圖片的座標點是可以畫出一個矩形的並且這個矩形的兩個對角頂點就是你選中的兩張圖片。(必須是對角)然後我們找出這兩個矩形另外兩個頂點的座標,找到時候首先要確定找到這個頂點必須是已經消除的掉的一個空白在哪裏,或者說沒有阻礙物。如果找到一個這樣的頂點,那麼只要這個頂點能和我們剛開始選擇的那兩張圖片 形成一個縱向的連通和一個橫向的連通 那麼就說明這兩個點可以經過一個拐角進行相連。
  簡單一點說就是 兩個拐角的==想辦法轉成===》一個縱向連通+一個橫向連通。
  說到這裏不知道大家是否已經明白我所表達的意思。
主要代碼實現

CCArray*  LLKAlgorithm::oneCorner(cocos2d::CCArray* llkArray,cocos2d::CCArray* hitArray){
        CustomSprite* hit1=(CustomSprite*)hitArray->objectAtIndex(0);// 取出第一個
        CustomSprite* hit2=(CustomSprite*)hitArray->objectAtIndex(1);// 取出第二個
        int x1=hit1->getX();
        int x2=hit2->getX();
        int y1=hit1->getY();
        int y2=hit2->getY();
        bool isXg=x1>x2?true:false;//如果是true 表示hit1 在hit2 的後面
        bool isYg=y1>y2?true:false;//如果是true 表示hit1 在hit2 的上面
        // 下面我們計算出矩形的另外的兩個重點
        // 先計算出  在矩形上面所對應的 
        int temx=0;
        int temy=0;        

        // 求取最上面的哪一個對應的座標點

        if(isYg){
                temy=hit1->getY();
                temx=hit2->getX();
        }else {
                temy=hit2->getY();
                temx=hit1->getX();
        }
        CCArray* temparray=CCArray::create();// 記錄兩個點之間 所經過的點

        CustomSprite* hity=LLKAlgorithm::getCustByXandY(llkArray,temx,temy);// 得到最上面的那個對應的矩形頂點的 精靈圖片
        CCArray* tempHit=CCArray::create();
        //頂點必須是已經消除的 要不肯定不能貫通
        if (hity->getIsEliminate()){
                tempHit->addObject(hity);
                tempHit->addObject(isYg?hit1:hit2);
                CCArray* temx=LLKAlgorithm::horizon(llkArray,tempHit);// 獲取X 方向上是否可以連通
                if(temx->count()>0){// 表示可以連通
                        temparray->addObjectsFromArray(temx);
                        LLKAlgorithm::removeAllArray(tempHit,false);
                        tempHit->addObject(hity);
                        tempHit->addObject(isYg?hit2:hit1);
                        CCArray* temy=LLKAlgorithm::vertical(llkArray,tempHit);
                        if (temy->count()>0){
                                temparray->removeObject(hity,false);
                                temparray->addObjectsFromArray(temy);
                        }else {
                                LLKAlgorithm::removeAllArray(temparray,false);
                        }
                }else {
                        LLKAlgorithm::removeAllArray(tempHit,false);
                }
        }
        // 表示上面的路走不通
        if (temparray->count()==0){
                // 獲取X 方向矩形所對應的的點                
                //temx=isXg?hit1->getX():hit2->getX();
                //temy=isXg?hit2->getY():hit1->getY();

                if (isYg){
                        temy=hit2->getY();
                        temx=hit1->getX();
                }else {
                        temy=hit1->getY();
                        temx=hit2->getX();                
                }

                CustomSprite* hitx=LLKAlgorithm::getCustByXandY(llkArray,temx,temy);// 得到最上面的那個對應的矩形頂點的 精靈圖片
                if (hitx->getIsEliminate()){
                        tempHit->addObject(hitx);
                        tempHit->addObject(isYg?hit2:hit1);
                        CCArray* temx=LLKAlgorithm::horizon(llkArray,tempHit);// 獲取X 方向上是否可以連通
                        if(temx->count()>0){// 表示可以連通
                                temparray->addObjectsFromArray(temx);
                                LLKAlgorithm::removeAllArray(tempHit,false);
                                tempHit->addObject(hitx);
                                tempHit->addObject(isYg?hit1:hit2);
                                CCArray* temy=LLKAlgorithm::vertical(llkArray,tempHit);
                                if (temy->count()>0){
                                        temparray->removeObject(hitx,false);
                                        temparray->addObjectsFromArray(temy);
                                }else {
                                        LLKAlgorithm::removeAllArray(temparray,false);
                                }
                        }else {
                                LLKAlgorithm::removeAllArray(tempHit,false);
                        }
                }

        }

        return temparray;

}

下面我們說下拐兩角 可以相連的。


大家看看藍色區域內的是我選擇的兩張圖片。從圖中我們看出這兩張圖片是可以經過兩個拐角相連的。
那麼如何知道可以經過兩個拐角可以 可以相連的 我相信通過上面那一個拐角的算法 大家或許就可以猜出來了。這裏我詳細說明一下 首先我們拿出一個點  那麼就像這個點的上下左右去找,找到一個 可以經過一個拐角和另外一個點相連的。經過一個拐角的算法請看上面那個講解。首先找到的這個點可以和我們拿出的這個點縱向相連或者橫向相連 。(但是必須保證這個點已經沒有別的圖片佔位置或者說是一個空白)。如果能找到這樣的一個點那麼就可以說明我們開始選擇的兩個圖片是可以經過兩個拐角進行相連的。
總體來說 可以這樣理解  兩個拐角==轉化成===》(一個橫向相連/縱向相連)+ 一個拐角可以相連的
一個拐角的看上面的解釋。
主要實現代碼

CCArray*  LLKAlgorithm::twoCorner(cocos2d::CCArray* llkArray,cocos2d::CCArray* hitArray){

        bool isjiance=false; // 這個主要來表示是否走了 一個拐角的判斷
        // 先獲取 當前X 的最大是多少  y 的最大是多少
        CustomSprite* lastCutom=(CustomSprite*)llkArray->lastObject();
        int max=lastCutom->getX();
        int may=lastCutom->getY();
        CustomSprite* hit1=(CustomSprite*)hitArray->objectAtIndex(0);// 取出第一個
        CustomSprite* hit2=(CustomSprite*)hitArray->objectAtIndex(1);// 取出第二個

        // 隨便拿出一個點  向他的四個方向出發 看看能否和另外一個變成一個拐角相連
        // 這裏我們就拿出取出的第一個點吧 hit1

        CCArray* temparray=CCArray::create();// 記錄兩個點之間 所經過的點
        int x1=hit1->getX(); // 得到第一個X 座標
        int y1=hit1->getY(); // 得到第1個Y座標
        // 首先向左檢測
        CCArray* temphit=CCArray::create(); 
        temphit->addObject(hit2);
        for(int i=(x1-1);i>=0;i--){
                CustomSprite* tepcou =LLKAlgorithm::getCustByXandY(llkArray, i, y1);
                if (tepcou->getIsEliminate()){
                        // 判斷看能否組成一個矩形
                        temparray->addObject(tepcou);
                        if(tepcou->getX()==hit2->getX()||hit2->getY()==tepcou->getY()){

                                continue;
                        }
                        isjiance=true;
                        temphit->addObject(tepcou);
                        CCArray* temparr=LLKAlgorithm::oneCorner(llkArray,temphit);
                        if (temparr->count()>0){
                                temparray->addObjectsFromArray(temparr);
                                break;
                        }else {
                                if(i==0){
                                        LLKAlgorithm::removeAllArray(temparray,false);
                                }

                                temphit->removeLastObject(false);
                        }
                }else{
                        LLKAlgorithm::removeAllArray(temparray,false);

                        break;
                }

        }

        if (isjiance==false){
                LLKAlgorithm::removeAllArray(temparray,false);                        
        }

        if(temparray->count()==0){
                bool isjiance=false; 
                // 向右檢測
                for(int i=(x1+1);i<=max;i++){
                        CustomSprite* tepcou =LLKAlgorithm::getCustByXandY(llkArray, i, y1);
                        if (tepcou->getIsEliminate()){
                                // 判斷看能否組成一個矩形
                                temparray->addObject(tepcou);
                                if(tepcou->getX()==hit2->getX()||hit2->getY()==tepcou->getY()){
                                        continue;
                                }
                                isjiance=true; 
                                temphit->addObject(tepcou);
                                CCArray* temparr=LLKAlgorithm::oneCorner(llkArray,temphit);
                                if (temparr->count()>0){
                                        temparray->addObjectsFromArray(temparr);
                                        break;
                                }else {
                                        if(i==max){
                                                LLKAlgorithm::removeAllArray(temparray,false);
                                        }                                
                                        temphit->removeLastObject(false);
                                }
                        }else{
                                LLKAlgorithm::removeAllArray(temparray,false);                        
                                break;
                        }
                }

                if (isjiance==false){
                        LLKAlgorithm::removeAllArray(temparray,false);                        
                }
        }

        if(temparray->count()==0){
                bool isjiance=false; 
                // 向下檢測                
                for(int i=(y1-1);i>=0;i--){
                        CustomSprite* tepcou =LLKAlgorithm::getCustByXandY(llkArray, x1, i);
                        if (tepcou->getIsEliminate()){
                                temparray->addObject(tepcou);
                                // 判斷看能否組成一個矩形
                                if(tepcou->getX()==hit2->getX()||hit2->getY()==tepcou->getY()){                                
                                        continue;
                                }
                                isjiance=true; 
                                temphit->addObject(tepcou);
                                CCArray* temparr=LLKAlgorithm::oneCorner(llkArray,temphit);
                                if (temparr->count()>0){
                                        temparray->addObjectsFromArray(temparr);
                                        break;
                                }else {
                                        if (i==0){
                                                LLKAlgorithm::removeAllArray(temparray,false);
                                        }                                        
                                        temphit->removeLastObject(false);
                                }
                        }else{
                                LLKAlgorithm::removeAllArray(temparray,false);
                                break;
                        }
                }
                if (isjiance==false){
                        LLKAlgorithm::removeAllArray(temparray,false);                        
                }
        }


        if(temparray->count()==0){
                bool isjiance=false; 
                // 向上檢測                
                for(int i=(y1+1);i<=may;i++){
                        CustomSprite* tepcou =LLKAlgorithm::getCustByXandY(llkArray, x1, i);
                        if (tepcou->getIsEliminate()){
                                temparray->addObject(tepcou);
                                // 判斷看能否組成一個矩形
                                if(tepcou->getX()==hit2->getX()||hit2->getY()==tepcou->getY()){
                                        continue;
                                }
                                isjiance=true; 
                                temphit->addObject(tepcou);
                                CCArray* temparr=LLKAlgorithm::oneCorner(llkArray,temphit);
                                if (temparr->count()>0){
                                        temparray->addObjectsFromArray(temparr);        
                                        break;
                                }else {
                                        if(i==may){
                                                LLKAlgorithm::removeAllArray(temparray,false);
                                        }

                                        temphit->removeLastObject(false);
                                }
                        }else{
                                LLKAlgorithm::removeAllArray(temparray,false);

                                break;
                        }
                }
                if (isjiance==false){
                        LLKAlgorithm::removeAllArray(temparray,false);                        
                }
        }

        if (temparray->count()>0){
                temparray->addObject(hit1);
        }

        return temparray;

寫到這裏連連看的算法基本算是已經完成了
     我在網上看了很多方法感覺不太容易理解,這個是我自己想出來的。感覺很通俗易懂,其實就是化繁爲簡。我最麻煩的變成最簡單。不過連連看的算法有很多種。不如著名的A* 尋路算法就可以。不過我感覺那個給大家講解其實會很麻煩,有希望瞭解瞭解的同學可以在百度上上搜索一下A* 尋路算法。
     其實我子所以寫這個練練看看的算法是交大家以後學習中的一種思路,有些同學一開始把問題弄得很複雜導致一時半會想不通,我建議剛開始考慮情況的時候從最簡單的開始考慮。到繁瑣的階段的時候看看能不能轉化成 簡單的方式。中國人其實都喜歡大事化小 小事化了  哈哈。 本章講解結束。 至於重新佈局+自動查找 等算法我會慢慢加進去 希望大家耐心等待。

    另外給大家說下以後我所有的博客首發地址將會是天地會的論壇,由於我是他們哪裏的原創管理。所以我以後在發佈博客首發地址將會天地會感興趣的同學可以關注一下

  http://bbs.9ria.com/forum.php?mod=forumdisplay&fid=318



     我給本算法起名字交錯化繁爲簡 算法。

       如果沒有看懂的同學可給我留言,我給給大家仔細講解一下

源碼下載

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章