You are blindfolded and then you are handed a pile of cards. The pile does not necessarily need to contain all 52 cards from a standard deck. Some of the cards in the pile face up, whereas the others face down. If we now tell you that the pile contains exactly $$u$$ face-up cards, how can you split it into two piles — not necessarily of equal size — so that each pile has the same number of cards facing up?
Although we could count the number of cards in the pile blindfolded, we don't even need to know the exact number of cards in the original pile. But let's say the pile consists of $$n$$ cards. Then there are $$u$$ face-up cards and $$n - u$$ cards facing down. We now split the original pile in two, with the first pile containing the first $$u$$ cards and the second pile containing the remaining $$n - u$$ cards.
If the first pile contains $$m$$ cards facing up, the second pile must contain the remaining $$u - m$$ face-up cards. The latter is also the exact number of face-down cards in the first pile. So by flipping all cards of the first pile, the number of face-up cards in both piles becomes $$u - m$$. Tada!
For example, suppose we are handed a pile of 16 cards, 7 of which are facing up. We then split the pile in two, with the first pile containing the first 7 cards and second pile containing the remaining 9 cards. If the first pile contains 3 face-up cards, the second pile must contain the remaining $$7 - 3 = 4$$ face-up cards. The first pile also has $$7 - 3 = 4$$ face-down cards. If we flip all cards of the first pile, then it now contains 4 face-up cards, just like the second pile.
A standard card deck includes 52 different cards, evenly distributed over four suits: 13 clubs (♣), 13 diamonds (♦), 13 hearts (♥) and 13 spades (♠). Clubs and spades are black, whereas diamonds and hearts are red. Each suit includes thirteen ranks: two through ten (with each card depicting that many symbols of its suit), jack, queen, king (each depicted with a symbol of its suit) and ace (depicting a single symbol of its suit). Commercial card decks may also include anywhere from one to six jokers, but we do not take these into account here.
Each card of a standard 52-card deck is represented by a string that contains the rank of the card, followed by its suit:
ranks: 2, 3, 4, 5, 6, 7, 8, 9, 10, J (jack), Q (queen), K (king) and A (ace)
suits: C (clubs; ♣), D (diamonds; ♦), H (hearts; ♥) and S (spades; ♠)
As such, the ace of spades is for example represented as AS, the ten of hearts as 10H and the king of clubs as KC. In addition we use uppercase for face-up cards (e.g. AS or 10H) and lowercase for face-down cards (e.g. as or 10h). Note that the last character of the string representation of a card is always an uppercase or lowercase letter (not a digit) that indicates the suit of the card.
The list representation of a pile of cards is a list containing the string representations of the consecutive cards in the pile, where the first element of the list is the top card in the pile. A pile of cards does not necessarily need to contain all 52 cards of a standard deck.
Define a class Pile that can be used to represent piles of cards with some cards facing up and others facing down. A list representation of the pile of cards must be passed when instantiating objects of the class Pile. The class may assume that the given list representation of the pile of cards is valid, without the need to check this explicitly. In addition, the class Pile must support at least the following methods:
A method faceUp that takes no arguments. The method must return an integer that indicates how many cards in the pile are currently facing up.
A method split that can be used to split the pile of cards $$s$$ on which the method is called into two new piles $$s_1$$ and $$s_2$$ (both objects of the class Pile). Pile $$s_1$$ must contain the first $$n$$ cards from pile $$s$$ and pile $$s_2$$ must contain the remaining cards of pile $$s$$, preserving the order of the cards as in pile $$s$$. The method may take an integer $$n \in \mathbb{N}$$ that indicates the number of cards in pile $$s_1$$. In case no argument is passed, the method must assume that $$n$$ equals the number of face-up cards in pile $$s$$. The method must return the tuple $$(s_1, s_2)$$.
A method flip that can be used to flip a selection of cards in the pile. Flipping a face-up card results in the card facing down. Flipping a face-down card result in the card facing up. Flipping cards never changes the order of the cards in the pile. The method may take an argument that indicates the positions of the cards that need to be flipped:
no argument: all cards in the pile must be flipped
integer argument: card at the given position must be flipped
argument is a collection (a list, a tuple or a set) of integers: cards at the given positions must be flipped
The cards are indexed top to bottom starting from zero to indicate their positions in the pile. The method must modify the state of the cards in the pile (face-up or face-down) and must return a reference to the object representing the pile.
The conversion of an object $$o$$ of the class Pile to a string — as obtained from the built-in functions repr and str — contains a representation of the pile of cards as shown in the interactive session below. The representation returned by the function repr is a Python expression that instantiates a new object of the class Pile having the same state as the current state of object $$o$$. The representation returned by the function str lists the representations of the consecutive cards in the pile (top to bottom), separated by spaces. Face-up cards are represented in the usual way, but face-down cards are represented by a double asterisk (**).
Also make sure the built-in operator == can be used to determine if two objects of the class Pile are equal. This is the case if both piles have the same number of cards facing up.
>>> cards = Pile(['AH', '3S', 'KC', '4H', '3D', '10H', '8D', '5D', '7C', 'QS', 'JC', '3H', 'KS', '4C', 'KD', '8S'])
>>> print(cards)
AH 3S KC 4H 3D 10H 8D 5D 7C QS JC 3H KS 4C KD 8S
>>> cards
Pile(['AH', '3S', 'KC', '4H', '3D', '10H', '8D', '5D', '7C', 'QS', 'JC', '3H', 'KS', '4C', 'KD', '8S'])
>>> cards.faceUp()
16
>>> cards.flip()
Pile(['ah', '3s', 'kc', '4h', '3d', '10h', '8d', '5d', '7c', 'qs', 'jc', '3h', 'ks', '4c', 'kd', '8s'])
>>> cards.flip(1).flip(4).flip([5, 9]).flip((10, 11, 13))
Pile(['ah', '3S', 'kc', '4h', '3D', '10H', '8d', '5d', '7c', 'QS', 'JC', '3H', 'ks', '4C', 'kd', '8s'])
>>> print(cards)
** 3S ** ** 3D 10H ** ** ** QS JC 3H ** 4C ** **
>>> cards.faceUp()
7
>>> cards1, cards2 = cards.split(4)
>>> print(cards1)
** 3S ** **
>>> cards1
Pile(['ah', '3S', 'kc', '4h'])
>>> cards1.faceUp()
1
>>> print(cards2)
3D 10H ** ** ** QS JC 3H ** 4C ** **
>>> cards2
Pile(['3D', '10H', '8d', '5d', '7c', 'QS', 'JC', '3H', 'ks', '4C', 'kd', '8s'])
>>> cards2.faceUp()
6
>>> cards1 == cards2
False
>>> cards3, cards4 = cards.split()
>>> print(cards3)
** 3S ** ** 3D 10H **
>>> cards3
Pile(['ah', '3S', 'kc', '4h', '3D', '10H', '8d'])
>>> cards3.faceUp()
3
>>> print(cards4)
** ** QS JC 3H ** 4C ** **
>>> cards4
Pile(['5d', '7c', 'QS', 'JC', '3H', 'ks', '4C', 'kd', '8s'])
>>> cards4.faceUp()
4
>>> cards3 == cards4
False
>>> cards3.flip()
Pile(['AH', '3s', 'KC', '4H', '3d', '10h', '8D'])
>>> print(cards3)
AH ** KC 4H ** ** 8D
>>> cards3.faceUp()
4
>>> cards3 == cards4
True
The successive statements in the above sample session correspond to the example of the card trick as given at the end of the introduction of this assignment. Click on the image below to see a visual representation of the successive steps of the card trick.
cards = Pile(['AH', '3S', 'KC', '4H', '3D', '10H', '8D', '5D', '7C', 'QS', 'JC', '3H', 'KS', '4C', 'KD', '8S'])
cards.flip()
cards.flip(1)
cards.flip(4)
cards.flip([5, 9])
cards.flip((10, 11, 13))
cards3, cards4 = cards.split()
cards3.flip()