/* * CoffeeCan.java * * This is an OO version of the "Coffee Can" problem first suggested by * David Gries in _The Science of Programming_ page 165: * *	"A coffee can contains some black beans and white beans.  The *	 following process is repeated as long as possible: * *	 Randomly select two beans from the can.  If they have the same color,  *	 throw them out, but put another black bean in.	 (Enough extra black beans  *	 are available to do this.)	 If they are of different colors, place the  *	 white one back in the can and throw the black one away. * *	 Execution of this process reduces the number of beans in the can by one. *	 Repetition of this process must terminate with exactly one bean in the  *	 can, for then two beans cannot be selected.  The question is: what, if  *	 anything, can be said about the color of the final bean based on the  *	 number of white beans and the number of black beans initially in the can?" * * The class has an invariant which is partially given below.  Discovering the * rest of the invariant is the key to answering the question. * * Each method is documented with preconditions and postconditions.	 To avoid * saying the same thing twice, information in the @param tags should be * considered part of the precondition, and information in the @return tags * should be considered part of the postcondition. * * Copyright (c) 2000 - Russell C. Bjork * */ import java.io.*;/** Representation for Gries' coffee can. * *	Invariant: there is at least one bean in the can and  *			   the number of beans of each color is >= 0 and *			   ???? * */ public class CoffeeCan{	/** Main program.  Repeatedly ask user for maximum number of beans of each	 *	color in can, and then play one instance of the "coffee can" game, 	 *	reporting activity to System.out.  Stop when max = 0.	 *	 *	NOTE: By entering a negative value, the user can cause the precondition	 *	of the constructor to be violated.	What happens in this case?	 *	 */	 	public static void main(String [] args) throws IOException	{		BufferedReader input = new BufferedReader(new InputStreamReader(System.in));				System.out.print("Maximum number of beans of each color: ");		int max = Integer.parseInt(input.readLine());				while (max != 0)		{			// Play one game						CoffeeCan theCan = new CoffeeCan(max);			String initialContents = theCan.reportContents();			System.out.println("Initial contents: " + initialContents);						while (theCan.numberOfBeans() > 1)			{				System.out.println();				try				{ 					Thread.sleep (5 * 1000);				}				catch (InterruptedException e)				{ }									String roundResults = theCan.playOneRound();				System.out.println("Results of round: " + roundResults);								String currentContents = theCan.reportContents();				System.out.println("Current contents: " + currentContents);			}						String finalColor = theCan.lastBeanColor();			System.out.println("Color of the final bean is " + finalColor);			System.out.println();							// Ask user for parameters for next game, or 0 to quit						System.out.print("Maximum number of beans of each color - 0 to quit: ");			max = Integer.parseInt(input.readLine());		}				System.exit(0);	}		/** Constructor	 *	 *	Precondition: max >= 1	 *	 *	@param max maximum number of beans of each color that can	 *		   initially be in the can	 *	 *	Postconditions: can contains between 1 and max white beans and	 *					between 1 and max black beans.	 *	 */	 	public CoffeeCan(int max)	{		whiteBeans = (int) (1 + max * Math.random());		blackBeans = (int) (1 + max * Math.random());	}		/** Report current contents of the can	 *	 *	Preconditions: none	 *	 *	Postcondition: can contents are unchanged	 *	 *	@return string describing the current contents of the can	 *	 */	 	public String reportContents()	{		return "Can contains: " + whiteBeans +			" white beans and " + blackBeans + " black beans - total = " +			(whiteBeans + blackBeans);	}	 	/** Report number of beans currently in the can	 *	 *	Preconditions: none	 *	 *	Postconditions: can contents are unchanged	 *	 *	@return total number of beans in can	 *	 */	 	public int numberOfBeans()	{		return whiteBeans + blackBeans;	}		/** Play one round of the "coffee can" game.  Draw two beans and put	 *	one back, as described by the rules above.	 *	 *	Precondition: there is more than one bean in the can	 *	 *	Postcondition: the number of beans in the can is reduced by 1, in	 *				   accordance with the rules of the game	 *	 *	@return string describing what took place	 *	 */	 	public String playOneRound()	{		String first = chooseBean();		if (first.equals("White"))			whiteBeans --;		else			blackBeans --;				String second = chooseBean();		if (second.equals("White"))			whiteBeans --;		else			blackBeans --;					String putBack;		if (first.equals(second))		{			putBack = "Black";			blackBeans ++;		}		else		{			putBack = "White";			whiteBeans ++;		}				return "Drew: " + first + ", " + second + ".  Put back: " + putBack;	}	/** Choose a single bean to draw	 *	 *	Preconditions:	there is at least one bean in the can	 *	 *	Postconditions: Return value is either "White" or "Black", 	 *					and there is at least one bean in the can of that color	 *	 *	@return color of bean to draw	 *	 */	 	private String chooseBean()	{		if (whiteBeans > 0 && blackBeans > 0)			if (Math.random() < 0.5)				return "White";			else				return "Black";							else if (whiteBeans > 0)			return "White";					else // must be the case that blackBeans > 0			return "Black";	}		/** Report the color of the final bean	 *	 *	Preconditions: the can contains exactly one bean	 *	 *	Postcondition: can contents are unchanged	 *	 *	@return color of the one bean in the can	 *	 */	 	public String lastBeanColor()	{		if (whiteBeans == 1)			return "White";					else // must be that blackBeans == 1			return "Black";	}	// Number of beans of each kind currently in the can		private int whiteBeans;	private int blackBeans;}		