Previous Section Table of Contents Next Section

Go Fish, Part II: Ask if Another Hand Has a Card

This function constitutes another component of the Python version of Go Fish. This function checks if the other player has any cards of a specified rank, and if so, it transfers them to the player's hand. If this results in the player having all four cards of that rank, the cards are deleted from the player's hand.

Here's a quick recap of the relevant definitions from the previous example (this function only concerns itself with hands; it does not use the deck):

  • Cards are identified by their rank and suit: The rank is one of the elements of the list ["2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"] and the suit is one of the elements of the list ["spades", "hearts", "diamonds", "clubs"].

  • A hand is a dictionary. In each element of the dictionary, the key is a card rank and the value is a list, containing names of the suits that the hand holds for that rank. For example, if a hand has the 3 of spades and the 3 of hearts, and no other 3s, then the key "3" will have the value ["spades", "hearts"]. A key should not have an empty list associated with it; if no cards of given rank are held, no value exists for that key.

The checkCard() function takes four parameters: The name of the player's hand (a string with the name of the hand used only for printing if cards are laid down), the player's hand, the rank of card to check, and the opponent's hand.

Source Code


 1.      import random

 2.

 3.      def checkCard ( handName, playerHand,

 4.                      cardRank, opponentHand ):

 5.

 6.        """ Check if opponentHand contains any cards of the

 7.            specified rank, if it does, transfer them to

 8.            playerHand.

 9.

10.            handName: A string with the name of playerHand

11.            playerHand: A hand dictionary, as described above.

12.            cardRank: A string with the name of a

13.                      card rank ("2" through "10", "J", "Q",

14.                      "K", or "A")

15.            opponentHand: A hand dictionary, described above.

16.

17.            Returns: 1 if a card is transferred, 0 otherwise.

18.      """

19.

20.      if cardRank in opponentHand:

21.

22.          transferCards = opponentHand[cardRank]

23.          # transferCards is a list!

24.          del opponentHand[cardRank]

25.          if cardRank in playerHand:

26.              playerHand[cardRank].extend(transferCards)

27.          else:    # shouldn't happen, but handle it

28.              playerHand[cardRank] = transferCards

29.

30.          if len(playerHand[cardRank]) == 4:

31.              print handName, "lay down", cardRank + "s"

32.              del playerHand[cardRank]

33.

34.              return 1

35.

36.            else:

37.

38.                return 0


Suggestions

  1. Does the code have any implied elses? What input would cause them to execute?

  2. The comment on line 23 is one of the few in the main algorithm, suggesting a non-obvious aspect of the code. Is the comment accurate?

  3. Because the statement on line 28 would not normally execute in a real game of Go Fish (you can't ask for a given rank unless you already have a card of that rank in your hand), it is risky code. It might never have been tested, yet someone who calls this function from somewhere else might assume it works. Thus, it is a good area to check for a bug.

Hints

Walk through the checkCard() function with the following parameters:

  1. Opponent does have a card of that rank:

    
    handName == "HAND"
    
    playerHand == { "5" : [ "spades", "hearts" ] }
    
    cardRank == "5"
    
    opponentHand == { "5" : [ "diamonds" ],
    
                      "10" : [ "clubs" ] }
    
    

  2. Opponent does not have a card of that rank:

    
    handName == "HAND"
    
    playerHand == { "A" : [ "clubs" ] }
    
    cardRank == "A"
    
    opponentHand ==  { "2" : [ "hearts" ] }
    
    

  3. Opponent has two cards of that rank, and the result is that player holds all four cards of that rank:

    
    handName == "HAND"
    
    playerHand == { "6" : [ "spades", "hearts" ],
    
                    "Q" : [ "spades", "hearts" ] }
    
    cardRank == "6"
    
    opponentHand == { "6" : [ "diamonds", "clubs" ] }
    
    

  4. Opponent has cards of that rank, but player does not (which should not happen in a real game of Go Fish):

    
    handName == "HAND"
    
    playerHand == { "J" : [ "hearts" ] }
    
    cardRank == "2"
    
    opponentHand == { "2" : [ "clubs", "spades" ] }
    
    

Explanation of the Bug

Lines 34-38 are incorrectly indented, which in Python means they are associated with the wrong block of code. Line 34, which is


return 1


should execute in all cases where the if on line 20 is true (a card of the specified rank is in the opponent's hand, which results in it being transferred to the player's hand, which is the defined situation where the function should return 1). Line 36 should be an else clause of that if, not from the if on line 30. So lines 34-38 are indented one indentation level (four spaces, given how the code is formatted) more than they should be.

As the code stands now, if cardRank is found in the opponent's hand but the player does not wind up with all four cards of that rank, the function returns 0 instead of 1 (as it should). If cardRank is not found at all in the opponent's hand, the function exits without a return statement. (In Python, this results in the function returning the built-in constant None.) This improper indenting is an F.location error.

    Previous Section Table of Contents Next Section