CS 112 - Introduction to Computer Science II
Homework #2


Due: At the beginning of class 6.  

NOTE: This work is to be done in pairs.  This means that each team will perform one submission with all team names and studentIDs listed in the README file after the honor pledge.  I strongly recommend the Agile software development practice of Pair Programming (described simply here) for producing correct, high-quality solutions.  Although team members are permitted to divide work, each team member should be able to informally present all work of his/her teammate.

0. Practice Pair Programming: Follow the links above or find other good tutorials for learning about the "driver" and "navigator" roles of pair programming.  This can be combined with Pomodoro Technique in order to make sure you're taking adequate breaks, getting up, and moving.  Use a web-based timer to assist.

1. Perfect Shuffling: A perfect shuffle (a.k.a. a Faro shuffle) is one where the deck is cut perfectly in half and then "riffled" together alternating one card from each half like the teeth of a zipper before being pushed together. This is considered to be one of the most difficult sleights of hand in card magic, and it allows the performer to control the positions of all cards in the deck, rearranging the permutation in unexpected ways. There are two perfect shuffles that differ according to whether the first card down comes from the top or bottom half. A perfect out-shuffle leaves the top card on top, that is, outside the deck. A perfect in-shuffle leaves the top card at the second card, that is, inside the deck. For this exercise, you will model perfect in- and out-shuffling.

Implement and submit PerfectShuffler.java according to this specification and this toString() implementation specification: toString() should return a comma-and-space-separated list of the current permutation of deck indices (0-51).  The easiest way to do this is to make use of the Arrays.toString() method and return the result without the first ("[") and last ("]") characters. That is, return a substring of the return value from Arrays.toString().

Fun curiosity questions (optional - not to be turned in):

Example transcript (with underlined input):

0, 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, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
o
0, 26, 1, 27, 2, 28, 3, 29, 4, 30, 5, 31, 6, 32, 7, 33, 8, 34, 9, 35, 10, 36, 11, 37, 12, 38, 13, 39, 14, 40, 15, 41, 16, 42, 17, 43, 18, 44, 19, 45, 20, 46, 21, 47, 22, 48, 23, 49, 24, 50, 25, 51
i
13, 0, 39, 26, 14, 1, 40, 27, 15, 2, 41, 28, 16, 3, 42, 29, 17, 4, 43, 30, 18, 5, 44, 31, 19, 6, 45, 32, 20, 7, 46, 33, 21, 8, 47, 34, 22, 9, 48, 35, 23, 10, 49, 36, 24, 11, 50, 37, 25, 12, 51, 38

Note: To end the input on a Unix system, use Control-D.  For some Windows environments (e.g. Windows Eclipse), use Control-Z.

2. BigFraction: Call your class BigFraction.java and implement it according to this specification.  You will note that BigFraction is composed of BigInteger numerator and BigInteger denominator.  Like BigInteger and BigDecimal, BigFraction is immutable.  Also, take care to simplify all fractions during construction using the BigInteger gcd method and dividing both numerator and denominator by their greatest common divisor, noting that BigInteger has its own given gcd method.  In our specification, the denominator is always positive; only the numerator can be either positive or negative.  For a refresher on fraction arithmetic, see here

Note: Section 10.9 of the Liang text makes use of the legacy form of BigDecimal.divide. Be aware that the preferred modern form of BigDecimal division makes use of the RoundingMode class rather than BigDecimal integer constants to define the means of rounding. For these exercises, we will use the modern form of BigDecimal division as modeled in ObjectFun.java.

3. Pig Scoring Expectation: Call your class PigTurnMath.java and implement it according to this specification.  A method public static BigFraction expectedTurnScore(int holdAt) returns the expected score gain in the game of Pig assuming that a player holds at a turn total of holdAt or more. 

The algorithm can be described as follows: Create an array e indexed by turn total t for computing e[t], the expected turn score given that one has reached a turn total of t.  Initially, e[t] = t,  for holdAt<= t <= holdAt + 5. Then, working from t=holdAt-1 down to t=0, you can compute each e[t] = e[t+2]/6 + e[t+3]/6 + e[t+4]/6 + e[t+5]/6 + e[t+6]/6. (In other words, a non-1 roll with probability 1/6 will contribute to the current expected score by 1/6 times the expected score at the next turn total reached by the roll.) This calculation working backwards is called retrograde analysis, and you'll be working with BigFraction objects for exact computation. The value you finally compute in e[0] is your expected score at the beginning of your turn when t = 0.

Example: To compute the probability of reaching a holdAt target of 3, array e contains BigFraction values for {0, 0, 0, 3, 4, 5, 6, 7, 8}.
Working backwards from t = 2 (i.e. holdAt-1) down to 0:
e[2] = e[2+2]/6 + e[2+3]/6 + e[2+4]/6 + e[2+5]/6 + e[2+6]/6 = 4/6 + 5/6 + 6/6 + 7/6 + 8/6 = 30/6 = 5/1.
e[1] = e[1+2]/6 + e[1+3]/6 + e[1+4]/6 + e[1+5]/6 + e[1+6]/6 = 3/6 + 4/6 + 5/6 + 6/6 + 7/6 = 25/6.
e[0] = e[0+2]/6 + e[0+3]/6 + e[0+4]/6 + e[0+5]/6 + e[0+6]/6 = (5/1)/6 + 3/6 + 4/6 + 5/6 + 6/6 = 23/6.
This e[0] value is your expected score for your turn (when you begin with a turn total of t=0).

Use loops for (1) initializing your p values, (2) iterating down through the turn totals, and (3) iterating through the roll numbers 2-6 for each turn total.

A spreadsheet demonstrating this computation for a hold value of 20 (where the expected value is approximately 8.141795) is available in XLSX and ODS formats.

Main method:

	/**
	 * Test expectedTurnScore(100).  The result should be "The expected score of a Pig turn holding at or above 100 is approximately 1.036932 and exactly 838133061449206972214342104525152462563/808281277464764060643139600456536293376."
	 * @param args (unused)
	 */
	public static void main(String[] args) {
		int holdAt = 100;
		BigFraction frac = expectedTurnScore(holdAt);
		System.out.printf("The expected score of a Pig turn holding at or above %d is approximately %f and exactly %s.\n", holdAt, frac.asBigDecimal(6, RoundingMode.HALF_UP).doubleValue(), frac);
	}

Optional (not for submission): For which holdAt value(s) does one maximize expected turn score?

Rubric: (20 points total)

When grading exercises in general, only a perfect solution gets full credit.  For each of the first three errors found by the grader, a point or so is deducted, and any submitted solution that would require more debugging receives at most a couple mercy points based on the merit of the effort.  A submission that doesn't compile will receive no credit.  It is not the job of our graders to make your code syntactically correct.

You likely understand the frustration of using software that is less than perfect, so strive for the same standard of perfection you would wish from those who program your software.  This is an application of the Golden Rule to programming.