/*
 * Created on Dec 12, 2003
 * CS 108
 * Section A
 */
package finalproject;

/**
 * @author Eric Knibbe
 *
 * This is a game where the user is presented with a grid of scrambled numbers, 
 * and the goal is to arrange the numbers in such a way so they're in order, much like 
 * those sliding-tile games you can find at dollar stores. 
 */
public class SlidingTile {
	//instance variables
	/**
	 * An array of scrambled numbers from which the array for the chosen game is derived.
	 */
	private int[] referenceMixedArray =
		{
			4,
			7,
			3,
			1,
			6,
			8,
			2,
			5,
			9,
			10,
			14,
			12,
			11,
			15,
			13,
			16,
			17,
			20,
			23,
			19,
			18,
			21,
			22,
			24,
			25,
			26,
			30,
			31,
			27,
			29,
			35,
			28,
			33,
			32,
			34,
			36 };
	/**
	 * An array of the same numbers, in order, from which the array of numbers in order is derived.
	 */
	private int[] referenceOrderedArray =
		{
			1,
			2,
			3,
			4,
			5,
			6,
			7,
			8,
			9,
			10,
			11,
			12,
			13,
			14,
			15,
			16,
			17,
			18,
			19,
			20,
			21,
			22,
			23,
			24,
			25,
			26,
			27,
			28,
			29,
			30,
			31,
			32,
			33,
			34,
			35,
			36 };
	/**
	 * The array of scrambled numbers for the game. This is generated when the game size is chosen.
	 */
	private int[] myMixedArray;
	/**
	 * The array of ordered numbers for the game. This is generated when the game size is chosen, 
	 * and is what the mixed array is compared to after each move. 
	 */
	private int[] myOrderedArray;
	/**
	 * The size of the game, where the number of tiles is mySize squared. Here the default value is 4.
	 */
	private int mySize = 4;
	/**
	 * The index of myMixedArray that represents the open tile (which incidentally contains the 
	 * value mySize squared).
	 */
	private int myOpenTileIndex;
	/**
	 * The index of myMixedArray that represents the tile selected by the player. 
	 */
	private int mySelectedTileIndex;

	//accessor methods
	/**
	 * @return mySize
	 */
	public int getSize() {
		return mySize;
	}
	/**
	 * @param int index
	 * @return myMixedArray[index] (the value contained in myMixedArray[index])
	 */
	public int getMixedArrayItem(int index) {
		return myMixedArray[index];
	}
	/**
	 * @param int index
	 * @return myOrderedArray[index] (the value contained in myOrderedArray[index])
	 */
	public int getOrderedArrayItem(int index) {
		return myOrderedArray[index];
	}
	/**
	 * @return myOpenTileIndex
	 */
	public int getOpenTileIndex() {
		return myOpenTileIndex;
	}
	/**
	 * @return mySelectedTileIndex
	 */
	public int getSelectedTileIndex() {
		return mySelectedTileIndex;
	}

	/**
	 * Constructor for the Sliding Tile class.
	 * @param: a typed int value for how big the puzzle will be.
	 */
	public SlidingTile(int size) {
		mySize = size;
		myMixedArray = new int[mySize * mySize];
		myOrderedArray = new int[mySize * mySize];
		fillArrays();
		setOpenTileIndex();
	}

	/**
	 * Fills the arrays myMixedArray and myOrderedArray from referenceMixedArray 
	 * and referenceOrderedArray.
	 */
	public void fillArrays() {
		for (int i = 0; i < (mySize * mySize); i++) {
			myMixedArray[i] = referenceMixedArray[i];
			myOrderedArray[i] = referenceOrderedArray[i];
		}
	}

	/**
	 * Determines the index of the currently open tile, which is mySize squared.
	 */
	public void setOpenTileIndex() {
		for (int i = 0; i < (mySize * mySize); i++) {
			if (myMixedArray[i] == (mySize * mySize)) {
				myOpenTileIndex = i;
				break;
			}
		}
	}

	/**
	 * Determies the index of the selected tile, based on the value of the tile recieved.
	 * @param value
	 */
	public void setSelectedTileIndex(int value) {
		for (int i = 0; i < (mySize * mySize); i++) {
			if (myMixedArray[i] == value) {
				mySelectedTileIndex = i;
				break;
			}
		}
	}

	/**
	 * Switches the values of mySelectedTileIndex and myOpenTileIndex, and sets the 
	 * myOpenTileIndex to the index of the tile just moved. 
	 *
	 */
	public void exchangeTiles() {
		myMixedArray[myOpenTileIndex] = myMixedArray[mySelectedTileIndex];
		myMixedArray[mySelectedTileIndex] = (mySize * mySize);
		myOpenTileIndex = mySelectedTileIndex;
	}

	/**
	 * Checks if the selected tile is in a position that can be moved, using the other IsValid methods.
	 * Also first checks if the value entered is within range.
	 * @param value
	 * @return a boolean value
	 */
	public boolean selectionIsValid(int value) {
		if (value >= 1 && value <= (mySize * mySize)) {
			setSelectedTileIndex(value);
			return (
				topIsValid()
					|| bottomIsValid()
					|| leftIsValid()
					|| rightIsValid());
		} else {
			return false;
		}
	}

	/**
	 * Checks if the selected tile is above the open tile. 
	 * @return a boolean value
	 */
	public boolean topIsValid() {
		return ((myOpenTileIndex - mySelectedTileIndex) == mySize);
	}

	/**
	 * Checks if the selected tile is below the open tile.
	 * @return a boolean value
	 */
	public boolean bottomIsValid() {
		return ((mySelectedTileIndex - myOpenTileIndex) == mySize);
	}

	/**
	 * Checks if the selected tile is to the left of the open tile. 
	 * @return a boolean value
	 */
	public boolean leftIsValid() {
		if (myOpenTileIndex != 0
			&& myOpenTileIndex != mySize
			&& myOpenTileIndex != 2 * mySize
			&& myOpenTileIndex != 3 * mySize
			&& myOpenTileIndex != 4 * mySize
			&& myOpenTileIndex != 5 * mySize
			&& myOpenTileIndex - mySelectedTileIndex == 1) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * Checks if the selected tile is to the right of the open tile.
	 * @return a boolean value
	 */
	public boolean rightIsValid() {
		if (myOpenTileIndex != mySize - 1
			&& myOpenTileIndex != 2 * mySize - 1
			&& myOpenTileIndex != 3 * mySize - 1
			&& myOpenTileIndex != 4 * mySize - 1
			&& myOpenTileIndex != 5 * mySize - 1
			&& myOpenTileIndex != 6 * mySize - 1
			&& mySelectedTileIndex - myOpenTileIndex == 1) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * Checks if the puzzle is completed by comparing the elements in myMixedArray and
	 * myOrderedArray. 
	 * @return a boolean value (true if all the elements match)
	 */
	public boolean puzzleIsSovled() {
		boolean bool = true;
		for (int i = 0; i < myMixedArray.length; i++) {
			if (!(myMixedArray[i] == myOrderedArray[i]))
				bool = false;
		}
		return bool;
	}

}

