Faro Shuffle

Start: 09/07/2023
Due: 09/27/2023, by the beginning of class
Collaboration: individual
Important Links: gradesheet


What you are to turn in

This lab assignment calls on you to write a number of different Haskell function definitions. For each problem except the last, you are to turn in the code you write to define the function. For the last problem, you should turn in the two expressions that you evaluated and what their values are. You do not need to turn in any evidence of your testing, although you should be sure to test each function or expression as you write it.

Submit your program through moodle. Make sure your file has the .txt extension because Moodle enforces that.

Background

A perfect shuffle of a standard deck of 52 playing cards consists of cutting the deck in half (so that the first 26 cards are in one half and the remaining 26 cards are in the other half) and then interleaving the two groups of cards, so that the cards alternately come from the two halves. It’s an out-shuffle if the new deck starts with the first card from the first half; it’s an in-shuffle if the new deck starts with the first card from the second half.

The same process applies for decks of sizes other than 52, although one detail arises for decks with an odd number of cards: we need a convention for what it means to split the deck in half. We'll assume that for an out-shuffle, the first half gets the extra card, so that in a deck of 5 cards, for example, the first three cards are the first half and the remaining two cards are the other half. We assume that for an in-shuffle, the second half gets the extra card, so that in a deck of 5 cards, for example, the first two cards are the first half and the remaining three cards are the other half.

Magicians and group theorists have figured out that eight perfect out-shuffles restores a deck of 52 cards back to its original configuration. Similar results hold for other sizes of decks, though the out-shuffle number varies with the deck size.

Similar results hold for in-shuffles.

In this lab, you will use Haskell programming to explore perfect out-shuffles and perfect in-shuffles.

Technical details

We will be using the Glasgow Haskell Compiler (GHC) to process Haskell programs on your machine or on one of the MCS department machines. You should use the ghci command in a shell (terminal) window while learning the language. Be sure to ask for help if you need it. Many beginners run into trouble because Haskell's default grouping isn't what they expect. Haskell is like ordinary math notation in that extra parentheses never hurt.

Although you could in principle type your function definitions directly into ghci, you would be better off putting them in a file and loading that file in and interactively test it, or compile the source and then run the resulting executable at the shell prompt as demonstrated in class. Also, be sure you pay particular attention to the type that the GHC system infers for each function. (You can see the type of an expression exp by typing :t exp at the ghci prompt.) Make sure you understand what each type means and why it makes sense.

Specific tasks

The obvious representation of a deck of cards is as a list of consecutive positive integers from 1 to 52. That list should be restored to its original order by 8 perfect out-shuffles, just as much as a list of actual cards would be. To produce lists like this, you can use the infix [..] operator from the Prelude. To split a deck into two “equal” halves, you can use the funcion splitAt, also available from the Prelude.

  1. First, you need to define a function to outInterleave a pair of “equal-sized” lists as explained in the Background section. For example, outInterleave ([1,2], [10,20]) would evaluate to [1,10,2,20], while outInterleave ([1,2,3], [10,20]) would evaluate to [1,10,2,20,3]. Make sure your function works correctly in both cases.

  2. Next, you need to define a function to inInterleave a pair of “equal-sized” lists as explained in the Background section. For example, inInterleave ([1,2], [10,20]) would evaluate to [10,1,20,2], while inInterleave ([1,2], [10,20,30]) would evaluate to [10,1,20,2,30]. Make sure your function works correctly in both cases.

  3. Now you can put together splitAt, and outInterleave to write a function called outShuffle that takes a list and returns the result of performing one perfect out-shuffle on it. You will be able to make good use of a local variable definition. Be sure you get it right in the case where the length of the list is odd.

  4. Now you can put together splitAt, and inInterleave to write a function called inShuffle that takes a list and returns the result of performing one perfect in-shuffle on it. You will be able to make good use of a local variable definition. Be sure you get it right in the case where the length of the list is odd.

  5. Now write a outShuffleNumber function that will take an integer (the deck size), make a list that size, and return a count of how many perfect out-shuffles are needed to return it to a list equal to the original. You could make good use of a nested function definition. Test that the out-shuffle number for 52 is 8.

  6. Now write an inShuffleNumber function that will take an integer (the deck size), make a list that size, and return a count of how many perfect in-shuffles are needed to return it to a list equal to the original. You could make good use of a nested function definition. Test that the in-shuffle number for 52 is 52.

  7. The approach of testing shuffled lists for equality with the original is perfectly reasonable. However, for the sake of a really good example of where pattern matching is helpful, let's consider an alternative possibility. Given that we start with a list of increasing integers, we could stop when we return to a list that is in increasing order. Write a function isInOrder that takes a list of integers and returns a boolean indicating whether the list is strictly increasing. Use pattern matching to handle three cases: empty lists, one element lists, and lists with at least two elements. (You may also want to go back and look over your earlier function definitions to see if any of them could be cleaned up a bit using pattern matching.)

  8. Show how to use map to produce a list of the out-shuffle numbers for 5, 50, 500, and 5000. Also show how to use map to produce a list of the in-shuffle numbers for 5, 50, 500, and 5000.