Pouring Water
/** Node in Pouring Water Problem
 * @author Lin Chen
 * @since 11.13.2017
 */
public class Node
{
	private int a = 10, b = 7, c = 4;//size of containers
	private int A, B, C;//real water volume in container
	private Node prev;//predecessor

	public Node(int A, int B, int C)
	{
		this.A = A;
		this.B = B;
		this.C = C;
		prev = null;
	}

	public int getA() {return A;}
	public int getB() {return B;}
	public int getC() {return C;}
	public int geta() {return a;}
	public int getb() {return b;}
	public int getc() {return c;}
	public Node getPrev() {return prev;}

	public void setA(int A) {this.A = A;}
	public void setB(int B) {this.B = B;}
	public void setC(int C) {this.C = C;}
	public void setPrev(Node n) {prev = n;}

	@Override
	public boolean equals(Object n)
	{
		Node temp = (Node)n;
		if((A == temp.A) && (B == temp.B) && (C == temp.C))
			return true;

		return false;
	}

	@Override
	public int hashCode()
	{
		return A+B*10+C*100;
	}

	public String toString()
	{
		return "("+A+"/"+a+","+B+"/"+c+","+C+"/"+c+")";
	}
}
			
/** Program to demo pouring water
 * @author Lin Chen
 * @since 11.13.2017
 */
import java.util.*;
import javafx.util.*;

public class P
{
	/** Calculate the remaining water after pouring water from A to B
	 * @param A volume of water in container A
	 * @param B volume of water in container B
	 * @param a volume of container A
	 * @param b volume of container B
	 * @return (volume in A, volume in B)
	 */
	public static Pair<Integer, Integer> pouring(int A, int B, int a, int b)
	{
		int tempA, tempB;
		if((b-B) > A)
		{
			tempA = 0;
			tempB = B+A;
		}
		else
		{
			tempB = b;
			tempA = A - (b-B);
		}

		return new Pair<Integer, Integer>(tempA, tempB);
	}

	/** Pouring water operation
	 * @param A volume of water in A
	 * @param B volume of water in B
	 * @param C volume of water in C
	 * @param A volume of container A
	 * @param B volume of container B
	 * @param C volume of container C
	 * @param direction pouring direction
	 * @return {@code Node}, a node from the operation
	 */
	public static Node pouringWater(int A, int B, int C, int a, int b, int c, String direction)
	{
		if(direction.equals("AB"))
		{
			Pair<Integer, Integer> p = pouring(A, B, a, b);
			return new Node(p.getKey(), p.getValue(), C);
		}
		else if(direction.equals("AC"))
		{
			Pair<Integer, Integer> p = pouring(A, C, a, c);
			return new Node(p.getKey(), B, p.getValue());
		}
		else if(direction.equals("BC"))
		{
			Pair<Integer, Integer> p = pouring(B, C, b, c);
			return new Node(A, p.getKey(), p.getValue());
		}
		else if(direction.equals("BA"))
		{
			Pair<Integer, Integer> p = pouring(B, A, b, a);
			return new Node(p.getValue(), p.getKey(), C);
		}
		else if(direction.equals("CA"))
		{
			Pair<Integer, Integer> p = pouring(C, A, c, a);
			return new Node(p.getValue(), B, p.getKey());
		}
		else if(direction.equals("CB"))
		{
			Pair<Integer, Integer> p = pouring(C, B, c, b);
			return new Node(A, p.getValue(), p.getKey());
		}
		else
			return null;
	}

	/** Check if the pouring from A to B is a valid operation
	 * @param A volume of water in A
	 * @param B volume of water in B
	 * @param a volume of container A
	 * @param b volume of container B
	 * @return {@code true}, valide; {@code false}, otherwise
	 */
	public static boolean isValid(int A, int B, int a, int b)
	{
		if(A <= 0)
			return false;
		if(B >= b)
			return false;
		return true;
	}

	/** Search all children of the current node, if they are valid and not visited, push into queue
	 * @param q a queue of Node
	 * @param u current node
	 * @param m hash table to check if the node has been visited
	 */
	public static void addChildren(Queue<Node> q, Node u, HashMap<Node, Integer> m)
	{
		int A, B, C, a, b, c;
		A = u.getA();
		B = u.getB();
		C = u.getC();
		a = u.geta();
		b = u.getb();
		c = u.getc();

		Node v;
		if(isValid(A, B, a, b))
		{
			v = pouringWater(A, B, C, a, b, c, "AB");
			v.setPrev(u);
			if(!m.containsKey(v))
			{
				q.add(v);
				m.put(v, 0);
			}
		}
		if(isValid(A, C, a, c))
		{
			v = pouringWater(A, B, C, a, b, c, "AC");
			v.setPrev(u);
			if(!m.containsKey(v))
			{
			q.add(v);
				m.put(v, 0);
			}
		}
		if(isValid(B, A, b, a))
		{
			v = pouringWater(A, B, C, a, b, c, "BA");
			v.setPrev(u);
			if(!m.containsKey(v))
			{
				q.add(v);
				m.put(v, 0);
			}
		}
		if(isValid(B, C, b, c))
		{
			v = pouringWater(A, B, C, a, b, c, "BC");
			v.setPrev(u);
			if(!m.containsKey(v))
			{
				q.add(v);
				m.put(v, 0);
			}
		}
		if(isValid(C, A, c, a))
		{
			v = pouringWater(A, B, C, a, b, c, "CA");
			v.setPrev(u);
			if(!m.containsKey(v))
			{
				q.add(v);
				m.put(v, 0);
			}
		}
		if(isValid(C, B, c, b))
		{
			v = pouringWater(A, B, C, a, b, c, "CB");
			v.setPrev(u);
			if(!m.containsKey(v))
			{
				q.add(v);
				m.put(v, 0);
			}
		}
	}

	/** Check if the current node is the target node
	 * @param u node
	 * @param target target volume
	 * @return {@code true}, target node; {@code false}, otherwise
	 */
	public static boolean checkNode(Node u, int target)
	{
		if(u.getA() == target)
			return true;
		if(u.getB() == target)
			return true;
		if(u.getC() == target)
			return true;
		return false;
	}

	/** Breadth First Search all possible nodes
	 * @param s start node
	 * @param target target volume of water
	 * @return target node
	 */
	public static Node BFS(Node s, int target)
	{
		Queue<Node> q = new LinkedList<Node>();
		HashMap<Node, Integer> m = new HashMap<Node, Integer>();

		q.add(s);
		m.put(s, 0);

		while(!q.isEmpty())
		{
			Node u = q.poll();
			if(checkNode(u, target))
				return u;
			addChildren(q, u, m);
		}

		return null;
	}

	/** print path finding the target node
	 * @param u target node
	 */
	public static void printNode(Node u)
	{
		if(u == null)
			return;
		printNode(u.getPrev());
		System.out.println(u);
	}

	public static void main(String args[])
	{
		Node s = new Node(0, 7, 4);

		Node t = BFS(s, 2);

		printNode(t);
	}
}