package search; /** * Water Jugs Implementation. * CS373 Assignment #1 * @author: Joey Kiernan and Nathaniel Lim * @version: 0.2 * @date: 2/22/10 */ import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.StringTokenizer; public class JugsPuzzle implements ProblemGraph { public static final int EMPTY_FIRST = 1; public static final int EMPTY_SECOND = 2; public static final int FILL_FIRST = 3; public static final int FILL_SECOND = 4; public static final int FIRST_TO_SECOND = 5; public static final int SECOND_TO_FIRST = 6; private JugsState goalNode; public static void main (String [] args){ System.out.println("Hello World!"); System.out.println(JugsPuzzleAction.values().length); } //The Goal state is one with no water in the first //3 Gallon Jug, and 2 Gallons in the 4 Gallon Jug public JugsPuzzle (){ setGoalNode(new JugsState("(0 2)")); } public State getState(String stateString) { return new JugsState(stateString); } public class JugsState implements State { private int[] jugs = new int[2]; public JugsState(String configurationString){ StringTokenizer tokens = new StringTokenizer(configurationString, "() "); if(tokens.countTokens() != 2){ throw new RuntimeException("The string: " + configurationString + " is not a valid Coin Puzzle state string."); } for (int i = 0; i < jugs.length; i++){ String str = tokens.nextToken(); int val = Integer.decode(str); //Check to make sure the first value isn't greater than 3 //Or make sure the second value isn't greater than 4 //Or make sure the val is not negative if ( (val > 3 && i ==0) || (val > 4 && i == 1) || val < 0){ throw new RuntimeException("The string: " + configurationString + " is not a valid CoinPuzzle state string. The value " + val + " is not a valid entry."); } else { jugs[i] = val; } } } /** * String representation: number of gallons of water in each jug. */ public String toString() { String strBuf = "("; for (int i = 0; i < jugs.length; i++) { strBuf += "" + jugs[i]; if (i < jugs.length - 1) { strBuf += " "; } } strBuf += ")"; return strBuf; } /* * Writing a Heuristic for the * The Goal State is: * Goal State (0 2) */ public int h(){ int output = 0; if (jugs[0] != 0){ output++; } if (jugs[1] != 2){ output+=2; } return output; } public boolean isValidAction(JugsPuzzleAction action){ //Invalid Actions: overflow, and //Already taken care and protected against //So now some actions do not change the state //So we will consider these actions "invalid" int[] testJugs = action.newJugs(jugs); if (testJugs[0] == jugs[0] && testJugs[1] == jugs[1]){ return false; } else{ return true; } } private JugsState(JugsState parent, JugsPuzzleAction action) { // initialize to clone parent for (int i = 0; i < jugs.length; i++){ jugs[i] = parent.jugs[i]; } //Jugs now points to a new Jug array with the action performed on it jugs = action.newJugs(jugs); } public List<GraphNode> expandNode() { List<GraphNode> list = new ArrayList<GraphNode>(); for (JugsPuzzleAction a : JugsPuzzleAction.values()) { if (this.isValidAction(a)) { JugsState newNode = new JugsState(this, a); list.add(new GraphNode(newNode)); } } return list; } public boolean isGoal() { return this.equals(goalNode); } /** * The equals function is constructed from the two rows of the configuration * array. */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; final JugsState other = (JugsState) obj; if (!Arrays.equals(jugs, other.jugs)) return false; return true; } /** * The hash function is constructed from the two rows of the configuration * array. */ @Override public int hashCode() { final int PRIME = 31; return PRIME + Arrays.hashCode(jugs); } } public void setGoalNode(JugsState goalNode) { this.goalNode = goalNode; } public JugsState getGoalNode() { return goalNode; } enum JugsPuzzleAction { EMPTYFIRST(EMPTY_FIRST), EMPTYSECOND(EMPTY_SECOND), FILLFIRST(FILL_FIRST), FILLSECOND(FILL_SECOND), FIRSTTOSECOND(FIRST_TO_SECOND), SECONDTOFIRST(SECOND_TO_FIRST); // the change in the x coordinate of the blank space under this action private final int type; private JugsPuzzleAction(int type){ this.type = type; } /** * The change in the x coordinate of the blank space under the action * @return integer x coordinate delta */ public int getType(){ return type; } /* * This method generates the new amounts of water in * the jugs based on whatever action type it this is. */ public int[] newJugs (int[] jugs){ int room; int[] output = new int[2]; if (type==EMPTY_FIRST){ output[0] = 0; output[1] = jugs[1]; } else if (type == EMPTY_SECOND){ output[0] = jugs[0]; output[1] = 0; } else if (type == FILL_FIRST){ output[0] = 3; output[1] = jugs[1]; } else if (type == FILL_SECOND){ output[0] = jugs[0]; output[1] = 4; } else if (type == FIRST_TO_SECOND){ room = 4-jugs[1]; if (jugs[0] < (room)){ //pour it all in output[1] = jugs[1] + jugs[0]; output[0] = 0; } else { output[1] = 4; output[0] = jugs[0] - room; } } else if (type == SECOND_TO_FIRST){ room = 3-jugs[0]; if (jugs[1] < (room)){ //pour it all in output[0] = jugs[0] + jugs[1]; output[1] = 0; } else { output[0] = 3; output[1] = jugs[1] - room; } } return output; } } }