Computer science and IT assignments Undergraduate

Mini Spite and Malice game

The game Mini Spite and Malice, invented specifically for Assignment 3, is a simplified variation of an old card game from the 19th century known as the Russian Bank. The old game is played with two decks of 52 traditional cards. Our variation uses other cards.

The Mini Spite and Malice will be played with a total of 120 cards:10 sets of 10 cards (“0 to “9) and 20 jokers (“*). The joker is a wild card and can have a value of any card from “0 to “9. The game is played with two players.

Once the cards are shuffled, each player is dealt 20 cards: starting with Player A and alternating between Player A and B, each player receives 5 cards for their hand and then 15 cards for their “Goal Pile” (a stack).  Each player tries to play through their Goal Pile – the first player to play all of the cards from their Goal Pile wins.

After dealing the cards to the 2 players, the remaining cards are placed face down in a card shoe from which the players are dealt new cards at each turn such that a player always starts playing with 5 cards in their hand.

Mini Spite and malice

How to start the game?

Each player turns their top card on their Goal pile (peek) and the one with the highest card starts (0<1<2<3<4<5<6<7<8<9<*).  In the case that both players have the same top card, Player A goes first.

How to play?

There are up to four Playing Piles. These are community piles used by both players.

Initially, these four are empty. Each Playing Pile is opened with a “0”. Playing proceeds upwards from “0” to “9”. A joker (wild card) can be played at any time, and takes on the appropriate value.  Once a “9” is played on a Playing Pile, that pile of cards is removed from the playing area and put aside. The Playing Pile is then empty and available again.  Any jokers in the removed Playing Pile regain their wild card value.

The player plays from the cards in the hand, the top of the Goal Pile, as well as from the top of their Discard Piles. Each player can have up to 4 Discard Piles, and only the top of each Discard Pile can be played.

Both players can see the card on top of each Goal Pile, as well as the cards in both hands, in all Discard Piles, and all Playing Piles.

At each turn, a player is dealt enough new cards to reach five in the hand. The player then tries to play cards so that they can play the card on top of their Goal Pile, while also trying to strategize and leave the game in a state so that the opponent cannot play the card on top of their Goal Pile.

If a card from the top of the Goal Pile is played, the next card on the pile becomes visible and can also be played.

When no available card can be played (off the Goal Pile, in the hand, or from the Discard Piles), the player discards one card (typically the highest one in the hand), onto one of their four Discard Piles.

Players MUST play the card “0” if a Playing Pile is free. Also, players cannot discard the card “0”. (If the player cannot play any more cards and only have “0” cards in their hand, their turn ends without adding a card to any of their Discard Piles.) Once a card is discarded, it cannot be moved from one Discard Pile to another, and the contents of the Discard Piles cannot be rearranged. A card from the Discard Piles can be played only when it is on top of one of the four Discard Piles.

Hint for playing: Players often try to organize the Discard Piles by descending card ranks (i.e. lower cards on top) so that they may be played sequentially.

If all five cards in the hand can be played onto the Playing Piles and the player runs out of cards before making a discard, the player draws five more new cards from the shoe to replenish their hand and play again.  The player continues in this way until they cannot make any further plays and are forced to discard a card. Once a discard is made, the turn moves to the next player. The next player always starts their turn by drawing enough new cards to get 5 in their hand.

If the shoe is empty, the completed playing piles removed from the playing area can be reshuffled to constitute a new shoe. In our game, after 5 complete playing piles are cleared, the cleared cards are shuffled and added to the bottom of the shoe.  Therefore, the shoe acts like a queue, where cards are dealt from the top (front) and added to the bottom (back).

The player who manages to play the last card of their Goal Pile first wins.

Summary:

The Player has one Goal Pile (with the top card showing), 5 cards in the hand, and up to 4 Discard Piles.

The playing area has up to 4 Playing Piles on which cards are stacked “0” to “9”. A complete pile from “0” to “9” is removed to free the pile.

The goal of the game is to play all the cards from one’s Goal Pile.

A card shoe is an object used in casinos to hold multiple decks of playing cards. In this assignment a shoe is implemented as a Queue of shuffled cards.

In Assignment 3 you will implement the game described above. The specifications are as follows:

Task 1 : The Card Class

Implement a class named Card. An instance of this class should have two private properties, face and value. Face is a string and value is an integer. This allows a wild card “*” to have a value. The card is initialized with a given value, and the face is assigned automatically based on this value. If the value is -1 then face is ‘*’. The face can be “*”, “0”, “1”, “2”, “3”, “4”, “5”, “6”, “7”, “8”, or “9”.  An AssertionError should be raised if an invalid value is provided when attempting to create an instance of this Card class.

The method assign(value) allows assigning a new value to the card only if face of the card is ‘*’.  Again, an AssertionError should be raised if an invalid value is provided.  An Exception should be raised if trying to change the value of a non-joker card.

The other methods in the interface include getValue() which returns the value of a card, getFace() which returns the face of a card.  __str__() generates “[self.face]” and __repr__() gives str()+”.”+self.value.

Task 2: The PlayStack Class
Implement a class named PlayStack. An instance of this class should have a property cards, which is a list of ordered cards that behaves like a stack. This property should not be directly accessible from outside the class. An instance of this class should behave like a stack, but it is a special stack as you will see below. You can only add cards from one end.  Be sure to implement it so that you are adding to the end that will result in O(1) time efficiency.

Implement a method peekValue() which returns the value of the card on top of cards.  Raise an Exception “Error: No cards in the playing stack” when appropriate.

Implement a method peekFace() which returns the face of the card on top of cards. Raise an Exception “Error: No cards in the playing stack” when appropriate.

Implement a method named playCard(card), that takes a card and pushes it on top of the cards stack. The card with value 0 can only be added when the cards stack is empty, and the method only accepts valid cards from the Card class. Also, an added card can only be pushed on top of a card of directly lower value.  For example, a card of value 5 can be added only on a card of value 4; Only a card of value 8 can be pushed on top of a card of value 7. If an error occurs the method should raise an Exception “Error: Card rejected”. When the card of value 9 is played and accepted, the stack should be emptied and the method returns a list of the faces of all cards that were in the stack. Otherwise, the method returns an empty list.

Implement the __str__() method to convert a PlayStack instance into a string such that the string represents the cards in the stack  from the lowest value on the left to the highest value on the right delimited by two “|”, eg. |[0][1][*][3][4][5]|.

Task 3: The Hand Class
Implement the class Hand which represents the cards held. An instance of this class should have the private property hand, which is a list of up to 5 Cards.

Implement the methods of the class. The interface consists of:
sort() sorts the cards in increasing order by value. ([*] is considered to have a value of -1 until played onto a Playing Pile.)
pop() returns and removes the card on the far right. (i.e. the largest value card when the hand is sorted.)  An Exception should be raised if there is no card to pop.
pop(i) returns and removes the card at position i.  Check that i is an integer in the correct range; an AssertionError should be raised if i is invalid.
index(v) returns the index of the first card with value v.  An AssertionError should be raised if v is invalid.  Returns -1 if there are no cards with value v in the hand.
check0() returns the index of the first card [0] in the hand. Returns -1 if there are no [0] cards in the hand.
size() returns the number of cards in the hand.
add(cardList) adds Cards in the cardList to the hand. Raises an Exception if adding those cards will cause the hand to contain more than 5 cards.

Implement a method to convert a Hand into a string. The cards should show the face.

Task 4: Shuffle
Write a function that shuffles cards. Do not use any built-in shuffling function. This task is about creating your own. The function receives a list of cards and returns a list of the same cards, but shuffled. To shuffle the cards, proceed as follows. Repeat until you have no more cards to select: Select a random number between 0 and the size of the list of cards, pop the card at that position and append it to a result list. Return the result list.  You should use the random module, but do NOT use the random.shuffle() function.

Task 5: The Game
After shuffling all the cards, cards are distributed to the two players. The remaining cards go to the shoe. The player with the highest card on top of their Goal stack starts the game (or Player A starts if the top Goal cards are the same). Then the two players alternate until one finishes their goal pile. A diagram with the basic game algorithm is given below.

Appendix

The interface for one turn should look something like this:

—————————————-
PlayerA Hand [[*][2][3][7][8]]
PlayerA Discard 1: [9]
PlayerA Discard 2: [7]
PlayerA Discard 3: []
PlayerA Discard 4: []
PlayerA Goal [6] 10 cards left

Play Stack 1 : |[0][1]|
Play Stack 2 : ||
Play Stack 3 : |[0][1][2][3][4]|
Play Stack 4 : |[0][1]|

PlayerB Hand [[3][3][5][6][9]]
PlayerB Discard 1: [9]
PlayerB Discard 2: [4]
PlayerB Discard 3: []
PlayerB Discard 4: []
PlayerB Goal [9] 5 cards left
—————————————-
PlayerB, choose action: p (play) or x (discard/end turn)
p
Play from where: hi = hand at position i (1..5); g = goal; dj = discard pile j (1..4)?
h3
Which Play Stack are you targeting (1..4)?
3
—————————————-
PlayerA Hand [[*][2][3][7][8]]
PlayerA Discard 1: [9]
PlayerA Discard 2: [7]
PlayerA Discard 3: []
PlayerA Discard 4: []
PlayerA Goal [6] 10 cards left

Play Stack 1 : |[0][1]|
Play Stack 2 : ||
Play Stack 3 : |[0][1][2][3][4][5]|
Play Stack 4 : |[0][1]|

PlayerB Hand [[3][3][6][9]]
PlayerB Discard 1: [9]
PlayerB Discard 2: [4]
PlayerB Discard 3: []
PlayerB Discard 4: []
PlayerB Goal [9] 5 cards left
—————————————-
PlayerB, choose action: p (play) or x (discard/end turn)
p
Play from where: hi = hand at position i (1..4); g = goal; dj = discard pile j (1..4)?
h3
Which Play Stack are you targeting (1..4)?
3
—————————————-
PlayerA Hand [[*][2][3][7][8]]
PlayerA Discard 1: [9]
PlayerA Discard 2: [7]
PlayerA Discard 3: []
PlayerA Discard 4: []
PlayerA Goal [6] 10 cards left

Play Stack 1 : |[0][1]|
Play Stack 2 : ||
Play Stack 3 : |[0][1][2][3][4][5][6]|
Play Stack 4 : |[0][1]|

PlayerB Hand [[3][3][9]]
PlayerB Discard 1: [9]
PlayerB Discard 2: [4]
PlayerB Discard 3: []
PlayerB Discard 4: []
PlayerB Goal [9] 5 cards left
—————————————-
PlayerB, choose action: p (play) or x (discard/end turn)
x
Which Discard Pile are you targeting (1..4)?
1
—————————————-
PlayerA Hand [[*][2][3][7][8]]
PlayerA Discard 1: [9]
PlayerA Discard 2: [7]
PlayerA Discard 3: []
PlayerA Discard 4: []
PlayerA Goal [6] 10 cards left

Play Stack 1 : |[0][1]|
Play Stack 2 : ||
Play Stack 3 : |[0][1][2][3][4][5][6]|
Play Stack 4 : |[0][1]|

PlayerB Hand [[3][3]]
PlayerB Discard 1: [9]
PlayerB Discard 2: [4]
PlayerB Discard 3: []
PlayerB Discard 4: []
PlayerB Goal [9] 5 cards left
—————————————-
PlayerA, choose action: p (play) or x (discard/end turn)

Leave a Reply

Your email address will not be published. Required fields are marked *