0
\$\begingroup\$

I'm trying to create a puzzle game where you move tiles to certain positions to make a whole image. I need help with randomizing the tiles start position so that they don't create the whole image at the beginning. There is also something wrong with my offset, that's why it's set to (0,0). I know my code is not good, but I'm just starting to learn.

My start-up tile positioning code

        spriteBatch = new SpriteBatch(GraphicsDevice);
        PictureTexture = Content.Load<Texture2D>(@"Images/bildgraff");
        FrameTexture = Content.Load<Texture2D>(@"Images/framer");

        //Laddar in varje liten bild av den stora bilden i en array

        for (int x = 0; x < 4; x++)
        {
            for (int y = 0; y < 4; y++)
            {

                Vector2 position = new Vector2(x * pictureWidth, y * pictureHeight);

                position = position + Offset;

                Rectangle square = new Rectangle(x  * pictureWidth, y * pictureHeight, pictureWidth, pictureHeight);



                Square frame = new Square(position, PictureTexture, square, Offset, index);
                squareArray[x, y] = frame;

                index++;
            }
        }         

For reference, here is the square class:

class Square
{

    public Vector2 position;
    public Texture2D grafTexture;
    public Rectangle square;
    public Vector2 offset;
    public int index;

    public Square(Vector2 position, Texture2D grafTexture, Rectangle square, Vector2 offset, int index)
    {
        this.position = position;
        this.grafTexture = grafTexture;
        this.square = square;
        this.offset = offset;
        this.index = index;
    }

    public void Draw(SpriteBatch spritebatch)
    {
        spritebatch.Draw(grafTexture, position, square, Color.White);
    }

    public void RandomPosition() {  }

    public void Swap(Vector2 Goal )
    {
        if (Goal.X > position.X)
        {
             position.X = position.X + 144;
        }
        else if (Goal.X < position.X)
        {
            position.X = position.X - 144;
        }
        else if (Goal.Y < position.Y)
        {
            position.Y = position.Y - 95;
        }
        else  if (Goal.Y > position.Y)
        {
            position.Y = position.Y + 95;
        }
    }
}
\$\endgroup\$
1
  • 3
    \$\begingroup\$ Welcome to gamedev! Please read the site's FAQ gamedev.stackexchange.com/faq and specify the problem you face instead of showing source code. To position tiles randomly, you want to have a grid of tiles (e.g. Array of arrays of tiles) iterate through them and swap each iterated tile with other tile at random indexes, e.g. for ( i = 0; i < ROWS; i++ ) for ( j = 0; j < COLS; j++) swapTiles(grid[i][j], grid[Math.random()*ROWS][Math.random()*COLS]); \$\endgroup\$ Commented Oct 10, 2012 at 14:42

2 Answers 2

4
\$\begingroup\$

The easy way is to shuffle from a solved puzzle to a not solved puzzle. Don't just swap a random tile with another random tile, you might not be able to get back to the orginal (you created an unsolvable puzzle!)

The hard way involves some math, see http://mathworld.wolfram.com/15Puzzle.html

\$\endgroup\$
1
1
\$\begingroup\$

Not going to read your code. But I think it's important that you understand the problem conceptually, then should have no problems implementing it.

The easiest way for you to shuffle your tiles (not the most efficient -- but the easiest) is to:

  1. Pick a random x and random y coordinate within your x and y ranges respectively, calling this coordinate loc1;
  2. Repeat, calling this loc2;
  3. Swap the contents between loc1 and loc2.

  4. Repeat steps 1-3 as many times as necessary.

That's the naive approach, because it will often pick an already-shuffled tile to shuffle again. That means it will take more CPU time to get a good, even shuffle. But I would try it like this first. Then if you need to be more efficient, you can record exactly which locations have already been touched on by the shuffle algorithm, in a collection (list or hashmap/dictionary) and just avoid shuffling those again. That is, each time you do a shuffle between two tiles, you just push those locations into the collection, and on each subsequent shuffle you're going to only shuffle tiles that aren't in that collection. If you use a list, it will be a little slower, as you will have to run through many list elements to check what's already been shuffled.

On the other hand, if you use a hash, you may have the hash equality problem, which is easiest solved by assigning each tile a unique ID (or, for the more adept coder, use bitshifting to combine x & y into a unique key for each tile position). I suggest you use a list for now. It's likely you don't have hundreds of thousands of tiles to shuffle :)

EDIT: Another way is to push all your tiles into a linear list, then just do pairwise shuffle of individual elements in the list, then push those sequentially back into the 2D tile layout, row by row or column by column.

\$\endgroup\$
1
  • \$\begingroup\$ Note that while it's good enough for puzzle games like this, most implementations of the 'naive' form of this algorithm don't produce an evenly-distributed random shuffle - this is crucially important when you're writing a digital card game, for instance. \$\endgroup\$ Commented Nov 6, 2012 at 18:42

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .