www.pudn.com > j2mewireless_examples.zip > Board.java


/*
 * @(#)Board.java	1.4 01/04/04
 * Copyright (c) 1999-2001 Sun Microsystems, Inc. All Rights Reserved.
 */
package examples.sokoban;

import java.io.IOException;

/**
 * Board knows how to move the pusher and how the pusher moves
 * the pieces.  It also keeps track of the number of moves
 * and pushes and the level.
 */
public class Board  {
	/*
	 * Directly accessible fields of the game board;
	 * do not set outside this class.
	 */
	int width;		// Width of the board
	int height;		// Height of the board
	int nmoves;		// number of moves executed
	int npushes;		// number of pushes executed
	
	private byte[] array;   	// width * height array of game state
	private int pusher;	// position of the pusher at index into array
	private int packets;	// total number of packets
	private int stored;	// number of packets in Stores
	private byte[] moves;	// recorded moves for undo
	
	// Move directions
	public static final int LEFT = 0;
	public static final int RIGHT = 3;
	public static final int UP = 1;
	public static final int DOWN = 2;
	public static final int MOVEPACKET = 4;
	
	// Bit definitions for pieces of each board position
	public static final byte GROUND = 0;	// If nothing there
	public static final byte STORE = 1;	// If it is a storage place
	public static final byte PACKET = 2;	// If it has a packet
	public static final byte WALL = 4;	// If it is a wall
	public static final byte PUSHER = 8;	// If the pusher is there
	
	/**
	 * Creates new Board initialized to a simple puzzle.
	 */
	public Board() {
		moves = new byte[200];
		screen0();
	}
	
	/*
	 * Create the hard coded simple game board.
	 */
	public void screen0() {
		width = 9;
		height = 7;
		array = new byte[width*height];
		nmoves = 0;
		npushes = 0;
		for (int x = 0; x < width; x++) {
			for (int y = 0; y < height; y++) {
				byte t = (x == 0 || y == 0 ||
				x == width-1 || y == height-1) ? WALL : GROUND;
				set(x, y, t);
			}
		}
		packets = 2; stored = 0;
		set(2, 2, PACKET);
		set(4, 4, PACKET);
		set(4, 2, STORE);
		set(6, 4, STORE);
		pusher = index(1, 1);
	}
	
	/**
	 * Move the pusher in the direction indicated.
	 * If there is a wall, don't move.
	 * if there is a packet in that direction, try to move it.
	 * @param move the direction; one of LEFT, RIGHT, UP, DOWN
	 */
	public void move(int move) {
		int p = pusher + indexOffset(move);
		
		// Handle the simple cases
		if ((array[p] & WALL) != 0)
			return;
		
		int m = movePacket(p, move);
		if (m >= 0) {
			/*
			 * Put the pusher in the new index
			 * and save the move in case of undo.
			 */
			pusher = p;
			saveMove(m);
		}
	}
	
	/**
	 * Move the packet in the direction indicated relative to
	 * the pusher.  If it fits into a store position remember.
	 * @return -1 if can't be moved or the updated move
	 * including the packet flag if there was a packet to move.
	 */
	private int movePacket(int index, int move) {
		if ((array[index] & PACKET) == 0)
			return move;	// no packet to move
		
		int dest = index + indexOffset(move);
		if (array[dest] > STORE)
			return -1;	// can't move packet into next spot.
		
		// Remove packet from current location
		array[index] &= ~PACKET;
		if ((array[index] & STORE) != 0)
			stored--;
		
		// Insert packet into new location
		array[dest] |= PACKET;
		if ((array[dest] & STORE) != 0)
			stored++;
		
		npushes++;		// count pushes done
		return move + MOVEPACKET;
	}
	
	/*
	 * Save a move, extending the array if necessary.
	 */
	private void saveMove(int move) {
		if (nmoves >= moves.length) {
			byte[] n = new byte[moves.length+50];
			System.arraycopy(moves, 0, n, 0, moves.length);
			moves = n;
		}
		moves[nmoves++] = (byte)move;
	}
	
	/*
	 * Undo the most recent move
	 */
	public void undoMove() {
		if (nmoves <= 0)
			return;
		int move = moves[--nmoves];
		int rev = (move & 3) ^ 3;	// reverse the direction
		int back = pusher + indexOffset(rev);
		
		if ((move & MOVEPACKET) != 0) {
			npushes--;		// "unpush"
			movePacket(pusher + indexOffset(move), rev);
		}
		pusher = back;
	}
	
	/**
	 * Determine if the screen has been solved.
	 */
	public boolean solved() {
		return packets == stored;
	}
	
	/*
	 * Return the pieces at the location.
	 * @param x location in the board.
	 * @param y location in the board.
	 * @return flags indicating what pieces are in this location.
	 * Bit flags; combinations of WALL, PUSHER, STORE, PACKET.
	 */
	public byte get(int x, int y) {
		int offset = index(x, y);
		if (offset == pusher)
			return (byte)(array[offset] | PUSHER);
		else
			return array[offset];
	}
	
	private void set(int x, int y, byte value) {
		array[index(x, y)] = value;
	}
	
	private int index(int x, int y) {
		if (x < 0 || x >= width ||
		    y < 0 || y >= height)
			return -1;
		
		return y * width + x;
	}
	
	/*
	 * Compute the offset in the array of the cell relative
	 * to the current pusher location in the direction of the move.
	 * Note: the walls around the edge always make a +/- guard band.
	 * Also, the order of evaluation should never try to get to +/- 2.
	 */
	private int indexOffset(int move) {
		switch (move & 3) {
			case LEFT:
				return -1;
			case RIGHT:
				return +1;
			case UP:
				return -width;
			case DOWN:
				return +width;
		}
		return 0;
	}
	
	/**
	 * Read a board from a stream.
	 * Read it into a fixed size array and then shrink to fit.
	 */
	public void read(java.io.InputStream is, int lev)
		throws IOException
	{
		final int W = 20;
		final int H = 20;
		byte[] b = new byte[W*H];
		
		int c, w = 0;
		int x = 0, y = 0, xn = 0, yn = 0;
		
		packets = 0;
		stored = 0;
		nmoves = 0;
		npushes = 0;
		
		while ((c = is.read()) != -1) {
			switch (c) {
				case '\n':
					if (x > w) {
						w = x;
					}
					
					y++;
					x = 0;
					break;
					
				case '$':
					b[y*W + x++] = PACKET;
					packets++;
					break;
					
				case '#':
					b[y*W + x++] = WALL;
					break;
					
				case ' ':
					b[y*W + x++] = GROUND;
					break;
					
				case '.':
					b[y*W+ x++] = STORE;
					break;
					
				case '+': // player and store in same place
					b[y*W + x++] = STORE;
				case '@':
					xn = x;
					yn = y;
					x++;
					break;
			}
		}
		
		/*
		 * Copy the board to an array sized to the \
		 * width and height of the board.
		 */
		width = w;
		height = y;
		array = new byte[width * height];
		for (y = 0; y < height; y++) {
			for (x = 0; x < width; x++) {
				array[y * width + x] = b[y * W + x];
			}
		}
		pusher = index(xn, yn);
	}
}