import java.util.Vector;

/**
 * PegSolitaireNode.java - Traditional 5-on-a-side Triangle Peg
 * Solitaire; Goal: to leave one peg after removal of all others via
 * linear jumps.
 *
 * @author Todd Neller
 * @version 1.0
 *

Copyright (C) 2003 Todd Neller

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

Information about the GNU General Public License is available online at:
  http://www.gnu.org/licenses/
To receive a copy of the GNU General Public License, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.

 */

public class PegSolitaireNode extends SearchNode 
{
    /**
     * variable <code>pegs</code> - state (peg 'O' or empty ' ') of
     * each of the 15 triangle positions numbers from left to right,
     * top to bottom.  */
    private char[] pegs = new char[15];

    /*
Peg position layout:
        0 
       / \
      1---2
     / \ / \ 
    3---4---5
   / \ / \ / \
  6---7---8---9 
 / \ / \ / \ / \
10--11--12--13--14
    */

    /**
     * constant <code>LINEAR_JUMP_POSITIONS</code> - lists of positions in a
     * line along which jumps can occur */
    private static final int[][] LINEAR_JUMP_POSITIONS = {{0,1,3,6,10}, {2,4,7,11}, {5,8,12}, {10,11,12,13,14}, {6,7,8,9}, {3,4,5}, {14,9,5,2,0}, {13,8,4,1}, {12,7,3}};

    
    /**
     * Creates a <code>PegSolitaireNode</code> instance and sets it
     * to an initial search state. */
    public PegSolitaireNode() 
    {
	for (int i=0; i<15; i++)
	    pegs[i] = 'O';
	pegs[4] = ' ';
    }


    /**
     * <code>isGoal</code> - test whether or not the current node is a
     * goal node.
     *
     * @return a <code>boolean</code> value */
    public boolean isGoal() 
    {
	// If depth is 13, we've jumped and removed 13 pegs.  Starting
	// with 14, that leaves 1 (our goal).
	return (depth == 13);
    }


    /**
     * <code>expand</code> - return a (possibly empty) Vector of this
     * node's children
     *
     * @return a <code>Vector</code> of SearchNodes */
    public Vector expand() 
    {
	// For each operation, check if it is valid and will change
	// the state.  If so, generate a child and add it to the
	// children Vector.
	Vector children = new Vector();
	// For each line of positions, and ...
	for (int i = 0; i < LINEAR_JUMP_POSITIONS.length; i++) {
	    int[] lineOfPos = LINEAR_JUMP_POSITIONS[i];
	    // ... for each three positions along that line
	    for (int j = 0; j < (lineOfPos.length - 2); j++)
		// ... check if a jump can occur.
		if (pegs[lineOfPos[j+1]] == 'O' && (pegs[lineOfPos[j]] != pegs[lineOfPos[j+2]])) {
		    // If it can, create the child node and add it.
		    PegSolitaireNode child = (PegSolitaireNode) this.childClone();
		    for (int k = j; k < j + 3; k++)
			child.pegs[lineOfPos[k]] = 
			    (child.pegs[lineOfPos[k]] == 'O') ? ' ' : 'O';
		    children.add(child);
		}
	}
	return children;
    }


    /**
     * <code>clone</code> - return a deep copy of this node.
     *
     * @return an <code>Object</code> value
     */
    public Object clone() 
    {
	PegSolitaireNode newNode = (PegSolitaireNode) super.clone();
	newNode.pegs = (char[]) pegs.clone();
	return newNode;
    }    


    /**
     * The <code>equals</code> method is especially useful for
     * repeated state detection.
     *
     * @param o an <code>Object</code> value - object to test for
     * equality with this
     * @return a <code>boolean</code> value - whether or not two
     * objects are equal */
    public boolean equals(Object o) 
    {
	if (o instanceof PegSolitaireNode) { 
	    PegSolitaireNode n = (PegSolitaireNode) o;
	    // Check that all peg positions are identical.
	    for (int i=0; i<pegs.length; i++)
		if (pegs[i] != n.pegs[i])
		    return false;
	    return true;
	}
	return false;
    }


    /**
     * <code>toString</code> - especially useful for debugging,
     * tracing search execution, reporting results, etc.
     *
     * @return a <code>String</code> value */
    public String toString() 
    {
	StringBuffer sb = new StringBuffer();
	sb.append("        ");
	sb.append(pegs[0]);
	sb.append("\n       / \\\n      ");
	sb.append(pegs[1]);
	sb.append("---");
	sb.append(pegs[2]);
	sb.append("\n     / \\ / \\ \n    ");
	sb.append(pegs[3]);
	sb.append("---");
	sb.append(pegs[4]);
	sb.append("---");
	sb.append(pegs[5]);
	sb.append("\n   / \\ / \\ / \\\n  ");
	sb.append(pegs[6]);
	sb.append("---");
	sb.append(pegs[7]);
	sb.append("---");
	sb.append(pegs[8]);
	sb.append("---");
	sb.append(pegs[9]);
	sb.append(" \n / \\ / \\ / \\ / \\\n");
	sb.append(pegs[10]);
	sb.append("---");
	sb.append(pegs[11]);
	sb.append("---");
	sb.append(pegs[12]);
	sb.append("---");
	sb.append(pegs[13]);
	sb.append("---");
	sb.append(pegs[14]);
	sb.append("\n");
	return sb.toString();
    }
    
}// PegSolitaireNode
