Jimmy's Blog – Slide Number Puzzle Game with Echo2 Framework

I’m checking Echo2 framework these couple days and try to make a simple game just to get to know the framework better.
Since I’m not a JavaScript expert it’s good to know that there’s framework that I can use to create AJAX web app with desktop feel easily.
The game is about re-ordering number by moving number to the empty space. It’s simple and fun, this sample is hardcoded to only support 3×3 size.

I assume you know Java, JSP, Servlet basics.
Download Echo 2 from : Echo2 Website
I personally use Eclipse for my IDE.

Step by step:

1. Create web project with your IDE, this should set up your project structure based on IDE you used.
2. Add Echo 2 library to your build path (Echo2_App.jar, Echo2_WebContainer.jar, Echo2_WebRender.jar).
3. Add servlet mapping in your web.xml

  <servlet>
    <description></description>
    <display-name>NumberGameServlet</display-name>
    <servlet-name>NumberGameServlet</servlet-name>
    <servlet-class>gnu.jimmy.java.echo2.numbergame.NumberGameServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>NumberGameServlet</servlet-name>
    <url-pattern>/game</url-pattern>
  </servlet-mapping>

4. Create NumberGameServlet that extend WebContainerServlet. This class will only return the application instance to be displayed to user.

 
package gnu.jimmy.java.echo2.numbergame;
 
import nextapp.echo2.app.ApplicationInstance;
import nextapp.echo2.webcontainer.WebContainerServlet;
 
/**
 * Servlet implementation class NumberGameServlet
 */
public class NumberGameServlet extends WebContainerServlet {
	private static final long serialVersionUID = 1L;
 
	@Override
	public ApplicationInstance newApplicationInstance() {
        return new NumberGameApp();
	}
}

5. Create class NumberGameApp that extend ApplicationInstance.
This is the core of the game, the game code is simple – we store the number position data and allow user to switch between number with button up/down/left/right or click the button near the empty one.
After that there will be checking if the number is order properly.
There’s also button to random the numbers, this will trigger up/down/left/right movements.

 
package gnu.jimmy.java.echo2.numbergame;
 
import nextapp.echo2.app.ApplicationInstance;
import nextapp.echo2.app.Button;
import nextapp.echo2.app.Color;
import nextapp.echo2.app.ContentPane;
import nextapp.echo2.app.Extent;
import nextapp.echo2.app.Grid;
import nextapp.echo2.app.ImageReference;
import nextapp.echo2.app.Label;
import nextapp.echo2.app.ResourceImageReference;
import nextapp.echo2.app.Window;
import nextapp.echo2.app.WindowPane;
import nextapp.echo2.app.event.ActionEvent;
import nextapp.echo2.app.event.ActionListener;
import nextapp.echo2.app.layout.GridLayoutData;
 
public class NumberGameApp extends ApplicationInstance implements ActionListener {
 
	private Window window;
	private ContentPane contentPane;
	private Grid container;
	private Button[] numbers = new Button[9];
	private Button random;
	private Button up;
	private Button left;
	private Button right;
	private Button down;
	private WindowPane pane;
	private Label paneLabel;
	private int[] numberData = new int[9];
	private int[] numberPos = new int[9];
 
	@Override
	public Window init() {
		window = new Window();
		contentPane = new ContentPane();
		window.setContent(contentPane);
 
		container = new Grid();
		container.setSize(3);
		contentPane.add(container);
 
		for (int i=0;i<numbers.length;i++) {
			ImageReference image = new ResourceImageReference("image/"+(i+1)+".png");
			numbers[i] = new Button(image);
			GridLayoutData layoutData = new GridLayoutData();
			layoutData.setBackground(new Color(0xffffcf));
			numbers[i].setLayoutData(layoutData);
			numbers[i].addActionListener(this);
			numberData[i] = i;
			numberPos[i] = i;
		}
 
		random = new Button(new ResourceImageReference("image/b_random.png"));
		random.addActionListener(this);
		up = new Button(new ResourceImageReference("image/b_up.png"));
		up.addActionListener(this);
		down = new Button(new ResourceImageReference("image/b_down.png"));
		down.addActionListener(this);
		left = new Button(new ResourceImageReference("image/b_left.png"));
		left.addActionListener(this);
		right = new Button(new ResourceImageReference("image/b_right.png"));
		right.addActionListener(this);
 
		pane = new WindowPane("Message", new Extent(200), new Extent(100));
		paneLabel = new Label();
		pane.add(paneLabel);
		pane.setModal(true);
 
		imageRefresh();
 
		return window;
 
	}
 
	private void switchNumber(int n1, int n2) {
		System.out.println("Switching : " + n1 + " - " + n2);
		int t = numberData[n1];
		numberData[n1] = numberData[n2];
		numberData[n2] = t;
		numberPos[numberData[n1]]=n1;
		numberPos[numberData[n2]]=n2;
		imageRefresh();
	}
 
	private void imageRefresh() {
		container.removeAll();
		for (int i=0;i<numbers.length;i++) {
			container.add(numbers[numberData[i]]);
		}
		ImageReference imgEmpty = new ResourceImageReference("image/empty.png");
		container.add(new Label(imgEmpty));
		container.add(new Label(imgEmpty));
		container.add(new Label(imgEmpty));
		container.add(new Label(imgEmpty));
		container.add(up);
		container.add(new Label(imgEmpty));
		container.add(left);
		container.add(random);
		container.add(right);
		container.add(new Label(imgEmpty));
		container.add(down);
		container.add(new Label(imgEmpty));
	}
 
	@Override
	public void actionPerformed(ActionEvent e) {
		int numberPress=-1;
		if (e.getSource() == up) {
			moveUp();
		} else if (e.getSource() == down) {
			moveDown();
		} else if (e.getSource() == left) {
			moveLeft();
		} else if (e.getSource() == right) {
			moveRight();
		} else if (e.getSource() == random) {
			int total = ((int)(Math.random()*100))+10;
			for (int i=0;i<total;i++) {
				int move = ((int)(Math.random()*100));
				if (move%4 == 0) {
					moveUp();
				} else if (move%4 == 1) {
					moveDown();
				} else if (move%4 == 2) {
					moveLeft();
				} else if (move%4 == 3) {
					moveRight();
				}
			}
		} else {
			for (int i=0;i<9;i++) {
				 if (e.getSource() == numbers[i]) {
					 numberPress=numberPos[i];
				 }
			}
			if (numberPress==numberPos[8]-3) {
				moveDown();
			} else if (numberPress==numberPos[8]+3) {
				moveUp();
			} else if (numberPress==numberPos[8]-1) {
				moveRight();
			} else if (numberPress==numberPos[8]+1) {
				moveLeft();
			}
		}
		if (checking()) {
			contentPane.add(pane);
			pane.setPositionX(new Extent(10));
			pane.setPositionY(new Extent(10));
			paneLabel.setText("Puzzle Finished");
		} else {
			paneLabel.setText("");
		}
	}
 
	private void moveUp() {
		if (numberPos[8]<=5) {
			switchNumber(numberPos[8], numberPos[8]+3);
		}
	}
 
	private void moveDown() {
		if (numberPos[8]>=3) {
			switchNumber(numberPos[8], numberPos[8]-3);
		}
	}
 
	private void moveLeft() {
		if (numberPos[8]%3 != 2) {
			switchNumber(numberPos[8], numberPos[8]+1);
		}
	}
 
	private void moveRight() {
		if (numberPos[8]%3 != 0) {
			switchNumber(numberPos[8], numberPos[8]-1);
		}
	}
 
	private boolean checking() {
		boolean match=true;
		for (int i=0;i<9;i++) {
			if (numberData[i]!=i) {
				match=false;
			}
		}
		return match;
	}
 
}

Screenshot:

Game Screenshot

Game Screenshot

Code logic:
- I create all number using button and add action listener on it.
- On number button clicked it will check if the number is next to empty space, if yes it will switch it.
- Random button will random the movement from 10-110 movement, so the numbers will be disordered but for sure it can be re-ordered.
- Arrow will make empty space switch with number next to it
- After every movement it will check if the numbers already ordered properly

Any question just drop a comment :)

3 comments

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

WP-SpamFree by Pole Position Marketing