Jump to content
  • Advertisement
Sign in to follow this  
kibokun

Bejeweled-like match checking / Board Randomization

This topic is 3272 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I currently have a grid of blocks, each of a different color. I'm currently having some logic issues about checking for matches when a player shifts a block. The player is allowed to swap two adjacent blocks in any of the 4 cardinal directions. Currently, I'm only allowing matches of 3 in a row. (I also have a problem getting my boards random enough.) After each swap, I need to check for matches including the blocks that have been swapped. It's turning into a complicated mess and I feel like I'm losing sight of occam's razor here. Has anyone implemented this before that can give me a few hints? Also, how do these puzzle games generally make sure their boards are not initialized with 3-4 matches already aligned? I currently have 6 colors and on my 10x10 board, there's usually 3-5 matches after initialization. I naively assign each block a random color. Thanks

Share this post


Link to post
Share on other sites
Advertisement
Checking for matches (three in a row) should be trivial. Scan the board piece by piece, tag pieces that makes three-in-a-row.

Once all pieces are tagged, drop the pieces down (from left-right, bottom-up), and do another full-board scan.


enum { COLUMNS = 12, ROWS = 20, LENGTH = 3, EMPTY = -1 };
struct Piece
{
Piece() { val = EMPTY; chained = false; }
int val;
bool chained;
};

Piece board[COLUMNS][ROWS];

Piece* piece(int c, int r);
bool analyseBoard();
bool analysePieces(int c, int r, int dc, int dr);
void dropColumn(int c, int r, int count);
void resolveBoard();
void updateBoard();

Piece* piece(int c, int r)
{
if(c < 0 || c >= COLUMNS) return NULL;
if(r < 0 || r >= ROWS) return NULL;
return &(board[c][r]);
}

bool analyseBoard()
{
bool foundChain = false;

for(int c = 0; c < COLUMNS; c++)
{
for(int r = 0; r < ROWS; r++)
{
Piece* p = piece(c, r);
if(p->val == EMPTY) continue;

// only need to check two cardinal directions.
foundChain |= analysePieces(c, r, 0, 1);
foundChain |= analysePieces(c, r, 1, 0);
}
}
return foundChain;
}

// check pieces from coordinates (c, r), and along direction (dc, dr)
bool analysePieces(int c, int r, int dc, int dr)
{
int val = piece(c, r)->val; // value to match
int count = 0; // number of pieces sharing that value
Piece* p[LENGTH]; // pointers to pieces

for(int i = 0; i = LENGTH; i ++, c += dc, r += dr)
{
p = piece(c, r);

// neighbouring piece matches that value
if(p && p->val == val)
count++;
}

// we've reached our length
if(count == LENGTH)
{
for(int i = 0; i = LENGTH; i ++)
p->chained = true;
return true;
}
return false;
}

void resolveBoard()
{
for(int c = 0; c < COLUMNS; c++)
{
for(int r = 0; r < ROWS; )
{
Piece* p = piece(c, r);

// piece flagged as chained
if(p->chained)
{
// drop column (c), from row(r) down by one.
dropColumn(c, r, 1);
}
// piece not chained, go to next piece above
// else we need to check it again as it's been replaced.
else
{
r++;
}
}
}
}

// drop column (c), from row (r), down by (count) pieces.
void dropColumn(int c, int r, int count)
{
for(int i = r; i < ROWS; i++)
{
// piece to replace
Piece* p = piece(c, i);

// piece above
Piece* above = piece(c, i + count);

// replace piece with the one above
// if outside the board, replace with empty piece.
*p = (above != NULL)? (*above) : Piece();
}
}
void updateBoard()
{
// while we find chains, remove the chained pieces.
while(analyseBoard())
resolveBoard();
}


in case of your randomisation, just replace some of the piece that part of a chain by another value. The chances are, that will break the chain. If it doesn;t use another random value until it does.

You can analyse the board, find tagged pieces, and change some of them with another value (one that is not the same as the its neighbours), analyse again (clear the chained flag first!), ect, until you find no more chains. Not ideal, but that should reset the board pretty quickly.

EDIT : CODE NOT TESTED!

[Edited by - oliii on December 2, 2009 5:16:54 AM]

Share this post


Link to post
Share on other sites
Thanks a lot. :) I wrote similar code that worked out fine with a few tweaks to allow me to call the same function AnalyzeBoard(), but have it perform different logic depending on whether I'm sanitizing the board before the player begins or simply checking for player-created matches.

You're right though. This was rather trivial and I'm not sure why I was making it so complicated before. It happens. :)

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!