0

提案を学習するための単純なマッチ 3 ゲームを構築しています。今、宝石がある方向 (X または Y) に移動したときの単純なゲームのセクションがあり、周りの宝石が
同じで、1 つ以上連続しているかどうかを調べる必要があります。あまりスマートではないソリューションをプログラムし、それをより一般的にするためのアイデアを探しています。これはコメント付きの私のコードです:

/

* 
 detect and store the gems that are alike the selected gem
*/

bool GameController::matchDetector(Gem* pSelected)
{
    // get the gem that are near the selected gem based on the selected gem movement type 
    // for example if moved right the movement type is (RightMovment) so the next gem is row,col+1
    Gem* pNextSprite = getNextGem(pSelected,pSelected->getGemState());
    // array that will store the Gems that are found for each direction array of its own
    CCArray * rightGemsToRemove = CCArray::create();
    CCArray * leftGemsToRemove = CCArray::create();
    CCArray * upperGemsToRemove = CCArray::create();
    CCArray * downGemsToRemove = CCArray::create();

    if(pNextSprite == NULL)
    {
        return false;
    }
    //copy the selected NEXT gem to the selected gem
    //so the calculation to find the next gems will be right 
    pSelected->swap(pNextSprite);
    int col = pSelected->getColNum();
    int row = pSelected->getRowNum();
    /*

        its long switch case that on its option doing the same so only the first one commented 

    */
    switch(pSelected->getGemState())
    {
        case kMoveRight:
        {
            // if its right direction i need to run on all the right gems until its NOT the same and stor it 
            for(int i=pSelected->getColNum()+1;i < maxGemsInCol;i++)
            {
                std::string nextInnerSpriteId = pUT->setGemId(i,row);
                // get the next gem from the container 
                Gem* pNextInnerSprite = (Gem*)GameSingleTone::getInstance()->getGemsDictionary()->objectForKey(nextInnerSpriteId);

                if(pNextInnerSprite == NULL)
                {
                    return false;
                }
                else
                {
                    // add it to the container 
                    rightGemsToRemove->addObject(pNextInnerSprite);
                }
            }
            break;
        }
        case kMoveLeft:
        {

            for(int i=pSelected->getColNum()-1;i < maxGemsInCol;i++)
            {
                std::string nextInnerSpriteId = pUT->setGemId(i,row);
                Gem* pNextInnerSprite = (Gem*)GameSingleTone::getInstance()->getGemsDictionary()->objectForKey(nextInnerSpriteId);

                if(pNextInnerSprite == NULL)
                {
                    return false;
                }
                else
                {
                    leftGemsToRemove->addObject(pNextInnerSprite);
                }
            }
            break;
        }
        case kMoveUp:
        {
            for(int i=pSelected->getRowNum()+1;i < maxGemsInRow ;i++)
            {
                std::string nextInnerSpriteId = pUT->setGemId(col,i);
                Gem* pNextInnerSprite = (Gem*)GameSingleTone::getInstance()->getGemsDictionary()->objectForKey(nextInnerSpriteId);

                if(pNextInnerSprite == NULL)
                {
                    return false;
                }
                else
                {
                    upperGemsToRemove->addObject(pNextInnerSprite);
                }
            }
            break;
        }
        case kMoveDown:
        {
            for(int i=pSelected->getRowNum()-1;i < maxGemsInRow ;i++)
            {
                std::string nextInnerSpriteId = pUT->setGemId(col,i);
                Gem* pNextInnerSprite = (Gem*)GameSingleTone::getInstance()->getGemsDictionary()->objectForKey(nextInnerSpriteId);

                if(pNextInnerSprite == NULL)
                {
                    return false;
                }
                else
                {
                    downGemsToRemove->addObject(pNextInnerSprite);
                }
            }
            break;
        }
    }

    /*
    this function will run on all the arrays and will check which gems needs to be removed from the GRID and all the rest ( fill the grid with new gems and so on .. ) 
    */
    handleGems(downGemsToRemove,upperGemsToRemove,leftGemsToRemove,rightGemsToRemove)

}
4

1 に答える 1

1

現在使用しているアルゴリズムにはまったく問題はないと思います(「異なる方向に宝石を当てるまで、指定された方向に宝石をループします」)。ゲーム ボードに数百万の行または列がない限り、これにはせいぜい数マイクロ秒しかかからず、使用できる最も単純なアルゴリズムです。

私が理解できないことの 1 つは、なぜ 4 つの個別のリストを蓄積するのかrightGemsToRemoveleftGemsToRemoveなどhandleGems()です。そうでない場合は、単一のgemsToRemoveリストを使用してください。

別の提案: 基本的に同一のコードを含む 4 つのケースがあります。この種の繰り返しは、バグが発生する肥沃な土壌です。ロジックに何らかの変更を加える必要がある場合、4 つのコピーすべてに同じ変更を加えるのを忘れたり、誤って間違った変更を加えたりする可能性があります (たとえば、コピー アンド ペーストを使用)。 )。switchステートメントを次のように減らすことをお勧めします。

int dx, dy;
switch (switch(pSelected->getGemState())) {
case kMoveRight: dx = 1;  dy = 0;  break;
case kMoveLeft:  dx = -1; dy = 0;  break;
case kMoveUp:    dx = 0;  dy = -1; break;
case kMoveDown:  dx = 0;  dy = 1;  break;
}

その後、 と に追加するループdxを1 つだけ記述できます。xdyy

int x = pSelected->getColNum() + dx;
int y = pSelected->getRowNum() + dy;
while (x >= 0 && x < maxGemsInRow && y >= 0 && x < maxGemsInCol) {
    std::string nextInnerSpriteId = pUT->setGemId(x, y);
    Gem* pNextInnerSprite = (Gem*)GameSingleTone::getInstance()->getGemsDictionary()->objectForKey(nextInnerSpriteId);

    if(pNextInnerSprite == NULL) {
        return false;
    } else {
        gemsToRemove->addObject(pNextInnerSprite);
    }

    x += dx;
    y += dy;
}

間違いなくさらに良い: kMoveRightetc. がすべて小さな整数値の場合、静的配列から直接それらを検索することができます:

static int dxFromMovement[] = { 1, -1, 0, 0 };
static int dyFromMovement[] = { 0, 0, -1, 1 };

dx = dxFromMovement[pSelected->getGemState()];
dy = dyFromMovement[pSelected->getGemState()];

これは少し速いかもしれませんが、私の意見では少し不明確であり、速度の違いはそれほど目立たないため、私の意見では価値がありません.

于 2013-08-31T18:24:52.477 に答える