September 19, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Getting Creative with Images Using Java: A Simple Puzzle

  • May 3, 2001
  • By Chunyen Liu
  • Send Email »
  • More Articles »

Introduction

This tutorial will focus on how to make use of some basic Java Development Kit (JDK) classes and image-manipulation techniques to create a simple image puzzle game. It is intended to give you a taste of how fun programming can be and a starting point leading to more serious applications, if you are really encouraged by these simple fundamental tips.

After seeing so many interesting interactive games on the Web, you are probably as motivated as I am to create one on your own. No matter how much fun you get from those commercial games, the chances are they never let you add your personal touch to them. What if you could create one yourself? Even if it is just a simple game, it can be fun, too! In fact, with all the programming tools and interfaces available in the standard Java package, it is not too difficult to put this thought into practice after all.

What elements are required for an image puzzle? The game needs to be able to take an image and properly resize the game panel. The next step will be slicing the image into puzzle pieces. Making customizable the number of rows and columns for the puzzle will be useful. Now these pieces need to be randomly scrambled for the game.

Up to this point, the game seems ready for play, but how do we move a puzzle piece? I use a simple mouse click in this demonstration, but you can set it up for the keyboard as well. Finally, some features (audio, messages, etc.) need to be added when the puzzle is completed. Of course, making a game more appealing and professional is much more than this. It generally requires a team's effort.

In this article, all the above issues will be described in more detail. The following are full working source code sets illustrating our implementation. Please let me know when you find bugs or add useful features to them.

Importing the Image

In Java, we have a method, getImage(), to input a GIF or JPG image file. The result is contained in an Image object. To create the puzzle pieces, we will need to save the image into an array buffer and do some simple cropping work. There is a JDK method available for this purpose. PixelGrabber() will get the pixel information from the photo image object and store data in the one-dimensional integer array.

// grab pixels into a 1D array
private void grabPixels()
   {
   PixelGrabber imagegrabber;

   imagegrabber = new PixelGrabber(photo, 0, 0, width, height,
      data, 0, width);
   try
      {
      imagegrabber.grabPixels();
      }
   catch(InterruptedException e) {}
   }

Dividing the Image into Puzzle Pieces

Now we have a one-dimensional array that holds the pixel information. The next step will be dividing the image into smaller puzzle pieces. Suppose we want the image divided into row rows and col columns. We thus have a total of row * col pieces. Also, each puzzle piece needs to be associated with an identifier. That way, we can use it to check whether the same puzzle piece has been restored to its original position. order is used for this reason. w is the width of each puzzle piece and h is the height. r, g, and b are for the red, green, blue channels of a pixel. They are extracted from the lower 24 bits of the integer representing a pixel. tt is a temporary one-dimensional array for each puzzle piece. MemoryImageSource() in JDK is used to make an image out of an array.

// restore all the puzzle positions   
public void resetPositions()
   { 
   for (int i = 0; i < row * col; i++)
      order[i] = i;
   repaint();
   }

// make each puzzle piece   
public void makePieces(int row, int col)
   {
   int [] tt;
   int idx = 0, xl = 0, yl = 0;
   int r = 0, g = 0, b = 0;
   int ww = -1, hh = -1;

   this.row = row;
   this.col = col;
   w = width / col;
   h = height / row;
   pieces = null;
   pieces = new Image[row * col];
   order = null;
   order = new int[row * col];
   for (int i = 0; i < row * col; i++)
      {
      tt = new int[w * h];        
      xl = (i % col) * w;
      yl = (int)(i / col) * h;

      for (int y = 0; y < h; y++)
         for (int x = 0; x < w; x++)
            {           
            idx = (y + yl) * width + (x + xl);
            r = (data[idx] & 0x00FF0000) >> 16;
            g = (data[idx] & 0x0000FF00) >> 8;
            b = data[idx] & 0x000000FF;
            tt[y * w + x] = (new Color(r,g,b)).getRGB();
            }

      pieces[i] =  createImage(new MemoryImageSource(w, h, tt, 0, w));
      ww = hh = -1;
      while (ww < 0 || hh < 0)
         {
         ww = pieces[i].getWidth(this);
         hh = pieces[i].getHeight(this);
         }
      order[i] = i;
      }
   }

Scrambling the Pieces

Since all puzzle pieces now have identifiers in the array, order, all we need to do is randomly switch their identifiers for shuffling. In case two identical pieces are selected, I simply increase the second identifier by one. Once the scrambling is done, the display area needs to be refreshed.

// rescramble the puzzle
public void rescramble()
   {
   int p = 0, q = 0, tem = 0;
   int total = row * col;

   for (int i = 0; i < total; i++)
      { 
      p = (int)((Math.round(Math.random() * 10 * total * total)) % total); 
      q = (int)((Math.round(Math.random() * 10 * total * total)) % total); 
      if (p == q) 
         q = (p + 1) % total;
      tem = order[p];
      order[p] = order[q];
      order[q] = tem;
      }
   repaint();
   }

Managing the Moves

All the puzzle pieces are now well scrambled. Interacting with the user is the next step. When a user clicks on the puzzle, we need to know if he/she hits a valid puzzle piece. If it is valid, can the piece be moved? The following code does exactly that. w and h are the width and height of each puzzle piece. xl and yl are the coordinates for the upper-left corner of the puzzle piece. The identifier for the selected puzzle piece is target. All four neighboring pieces have been checked to see if any of them is empty. If any of the four neighbors is empty, the selected piece can be moved to that location. Note, we use the last available identifier, total - 1, for the empty piece.

At the end, all the identifiers have been examined. If all of them match the original ones, the puzzle is completed.

// do when mouse is down
public boolean mouseDown(java.awt.Event evt, int x, int y)
   {
   int xl = 0, yl = 0;
   int target = -1;
   boolean done = false;
   int total = row * col;

   // check if we hit a valid puzzle piece      
   for (int i = 0; i < total; i++)
      {      
      xl = (i % col) * w;
      yl = (int)(i / col) * h;
      if (x >= xl && x < xl + w && y >= yl && y < yl + h)
         {       
         moveaudio.play();     
         target = i;
         break;            
         }
      }
         
   // left neighbor
   if (target > -1 && (target % col) != 0)
      {
      if (order[target - 1] == total - 1)
         {
         order[target - 1] = order[target];
         order[target] = total - 1;
         done = true;
         }
      }

   // right neighbor
   if (!done && target > -1 && (target % col) != col - 1)
      {
      if (order[target + 1] == total - 1)
         {
         order[target + 1] = order[target];
         order[target] = total - 1;
         done = true;
         }
      }

   // top neighbor
   if (!done && target > -1 && target / col  >= 1)
      {
      if (order[target - col] == total - 1)
         {
         order[target - col] = order[target];
         order[target] = total - 1;
         done = true;
         }
      }
 
   // bottom neighbor
   if (!done && target > -1 && target / col < row - 1)
      {
      if (order[target + col] == total - 1)
         {
         order[target + col] = order[target];
         order[target] = total - 1;
         done = true;
         }
      }

   // we have hit a movable puzzle liece
   if (done)
      moves++;
   repaint();

   // do we have a winner?      
   if (moves > 0)
      {
      for (int i = 0; i < total; i++) 
         {
         if (order[i] != i)
            return true;
         }         
      gameover = true;         
      }

   return true;
   }

Adding Configurable Parameters

To make the puzzle more attractive and configurable, here are some parameter options that have been added or can be added to the program. The current parameters available are the photo filename, number of rows and columns to divide the puzzle, and an audio filename for the puzzle move. Colors and fonts are probably the most common options users need. Caption support can be added for different language flavors. An on-screen timer would probably increase the playing excitement. Some interactive hints can provide extra help for those puzzles that are difficult to solve. I am sure you can think of many other configurable features to make better puzzles. These are just some pointers.

Summary

In this tutorial, I briefly describe how to make a Java image puzzle game from scratch with the basic tools available in the standard JDK distribution and provide my own implementation details. Of course, there are still many improvements that can be made to make it look and work better. Here are some possibilites:

  • Moving a piece is probably more intuitive by dragging instead of mouse clicks.
  • When a user clicks on a puzzle piece, I simply position the piece at its destination. Since this is a sliding puzzle, moving the puzzle piece a small step at a time by animation is more visually appealing.
  • Rectangular puzzle pieces do not resemble real-world puzzle games. An image mask can be created to extract the desired puzzle shape.
  • Some artificial intelligence algorithms can be implemented to suggest the best puzzle piece for the next move.

Okay, you can now relax and enjoy your own little puzzle game!

References

  1. Ken Arnold and James Gosling, "The Java Programming Language", Addison-Wesley, 1997.
  2. Elliotte Rusty Harold, "Java I / O", O'Reilly and Associates Inc, 1999.
  3. Jerry Jackson and Alan McClellan, "Java by Example", Sun Microsystems Press, 1999.

Download the Files

About the Author

Chunyen Liu is a software engineer at a global positioning company, GARMIN International. Some of his 100-plus Java programs have won major programming contests. Check out his personal page for more details. He also owns a Java-intensive site called The J Maker.






Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel