0

Here is the error:

Traceback (most recent call last): File "C:/Users/Wattel/Desktop/21 21 21.py", line 177, in main() File "C:/Users/Wattel/Desktop/21 21 21.py", line 167, in main PPOINTS, DPOINTS, PHAND, DHAND = dLoop(PHAND, DHAND, DECK) TypeError: 'NoneType' object is not iterable

I know that it has something to do with this code, but can't figure out what the problem is exactly:

scoreHAND(DHAND) < 18 or scoreHAND(DHAND) < 21 and scoreHAND(DHAND) < scoreHAND(PHAND) or scoreHAND(DHAND) < 21

Here is the rest of my code:

##21 Card Game 
##Wattel
##2016 Spring

from random import *
import random
from random import shuffle, randint

CARDPOINTS = {'AD': 11,'AH': 11,'AC': 11,'AS': 11,
              'KD': 10,'KH': 10,'KC': 10,'KS':10,
              'QD': 10,'QH': 10,'QC': 10,'QS': 10, 
              'JD': 10,'JH': 10,'JC': 10,'JS': 10,
              '10D': 10,'10H': 10,'10C': 10,'10S': 10,
              '9D': 9,'9H': 9,'9C': 9,'9S': 9,
              '8D': 8,'8H': 8,'8C': 8,'8S': 8,
              '7D': 7,'7H': 7,'7C': 7,'7S': 7,
              '6D': 6,'6H': 6,'6C': 6,'6S': 6,
              '5D': 5,'5H': 5,'5C': 5,'5S': 5,
              '4D': 4,'4H': 4,'4C': 4,'4S': 4,
              '3D': 3,'3H': 3,'3C': 3,'3S': 3,
              '2D': 2,'2H': 2,'2C': 2,'2S': 2,}

List = ['AD','AH','AC','AS',
            'KD','KH','KC','KS',
            'QD','QH','QC','QS', 
            'JD','JH','JC','JS',
            '10D','10H','10C','10S',
            '9D','9H','9C','9S',
            '8D','8H','8C','8S',
            '7D','7H','7C','7S',
            '6D','6H','6C','6S',
            '5D','5H','5C','5S',
            '4D','4H','4C','4S',
            '3D','3H','3C','3S',
            '2D','2H','2C','2S',]

def want2play():
    Hit2Play = input(" Hit 'y' to begin your game of 21): ")
    print ("")
    return Hit2Play

def deckCheck(DECK):
    print (DECK)
    print("There are:",len(DECK),"cards in the deck.") 
    if len(DECK) < 20:
        DECK = shuffleDeck() 
        return DECK
    else:
        return DECK

def openingDeal(DECK):
    PHAND = [] 
    DHAND = [] 
    DHANDT = [] 
    PHAND, DECK  = dealOneCard(PHAND, DECK) 
    DHAND, DECK = dealOneCard(DHAND, DECK)
    DHANDT.append(DHAND[0]) 
    PHAND, DECK  = dealOneCard(PHAND, DECK)
    DHAND, DECK = dealOneCard(DHAND, DECK)
    DHANDT.append("back of card")
    PPOINTS = scoreHAND(PHAND)     
    printScores_0(PPOINTS, PHAND, DHANDT)
    return PHAND, DHAND, DHANDT, DECK

def pLoop(PHAND, DHAND, DHANDT, DECK):
    while scoreHAND(PHAND) < 21:
        hitorhold = input('Do you want to hit or hold?: ')
        if hitorhold == 'hit':
            dealOneCard(PHAND, DECK)
            printScores_0(scoreHAND(PHAND), PHAND, DHANDT)
        elif hitorhold == 'hold':
            print('Player holds')
            printScores_0(scoreHAND(PHAND), PHAND, DHANDT)
            break
    return PHAND, DHAND, DECK

def dLoop(PHAND, DHAND, DECK):
    printScores_1(scoreHAND(PHAND), scoreHAND(DHAND), PHAND, DHAND)

    if scoreHAND(DHAND) < 18 or scoreHAND(DHAND) < 21 or scoreHAND(DHAND) < scoreHAND(PHAND) or scoreHAND(DHAND) < 21 or scoreHAND(PHAND) < 22:
        dealOneCard(DHAND, DECK)
        printScores_1(scoreHAND(PHAND), scoreHAND(DHAND), PHAND, DHAND)
        return scoreHAND(PHAND), scoreHAND(DHAND), PHAND, DHAND
    else:
        return scoreHAND(PHAND), scoreHAND(DHAND), PHAND, DHAND


def checkScore(pWin, dWin, PPOINTS, DPOINTS):
    if DPOINTS > PPOINTS and DPOINTS < 22:
        dWin += 1
        print (' ')
        print ("Dealer Win")
        return pWin, dWin

    elif PPOINTS == DPOINTS and PPOINTS < 21:
        dWin += 1
        print (' ')
        print ("Dealer Win")
        return pWin, dWin

    elif PPOINTS > 21 and DPOINTS < 21:
            dWin += 1
            print(' ')
            print("Dealer Win")
            return pWin, dWin

    elif PPOINTS < 22 and DPOINTS > 21:
            pWin += 1
            print (' ')
            print ("Player Win")
            return pWin, dWin

    elif PPOINTS > 21 and DPOINTS > 21:
            print (' ')
            print ("Tie.")
            return pWin, dWin

    elif PPOINTS == 21 and DPOINTS == 21:
            print(' ')
            print("Tie.")
            return pWin, dWin

def dealOneCard(HAND,DECK):
    theCard = DECK.pop(0)
    HAND.append(theCard) 
    return HAND, DECK

def shuffleDeck():
    CardPile = len(List)
    random.shuffle(List)
    return List

def scoreHAND(HAND):
    points = addScore(HAND) 
    aceCount=0
    if points > 21:
        aceCount += HAND.count('AS')
        aceCount += HAND.count('AH')
        aceCount += HAND.count('AC')
        aceCount += HAND.count('AD')
        while points > 21 and aceCount > 0:
            points -= 10
            aceCount -= 1
        return points
    else:
        return points

def addScore(HAND):
    tempScore = 0
    for i in HAND:
        tempScore += CARDPOINTS[i]
    return tempScore 

def printScores_0(POINTS, HAND, HAND1):
    print("Player's cards: ", HAND, "Player's hand score: ", POINTS)
    print("Dealer's cards: ", HAND1)

def printScores_1(PPOINTS, DPOINTS, PHAND, DHAND):
    print("Player's cards: ", PHAND, "Player's hand score: ", PPOINTS)
    print("Dealer's cards: ", DHAND, "Dealer's hand score: ", DPOINTS)

def main():
    DECK = shuffleDeck()
    pWin = 0
    dWin = 0
    while True:
        Hit2Play = want2play()
        if Hit2Play == 'y':
            DECK = deckCheck(DECK)
            PHAND, DHAND, DHANDT, DECK = openingDeal(DECK)
            PHAND, DHAND, DECK = pLoop(PHAND, DHAND, DHANDT, DECK)
            PPOINTS, DPOINTS, PHAND, DHAND = dLoop(PHAND, DHAND, DECK)
            pWin, dWin = checkScore(pWin, dWin, PPOINTS, DPOINTS)
            print("")
            print("Player's Wins:", pWin, "Dealer's Wins:",dWin)
            print("")

        else:
            print("Player's Wins:", pWin, "Dealer's Wins:",dWin)

            break
main()
pp_
  • 3,435
  • 4
  • 19
  • 27
Wattel
  • 1
  • 4
  • PEP-8 suggests that ALL_CAPS should be reserved for constants. – Hugh Bothwell Feb 13 '16 at 03:40
  • Are you sure that's the stack trace? It should trace down to the exact point where iteration failed which is further down the call stack than the line you show. From the bottom of the stack trace, look at the code at each line and ask yourself how that variable got to be `None`. Scatter prints around if you need more information. – tdelaney Feb 13 '16 at 03:49
  • Regardless of the help you get below, after you send your program in, you should take a copy of of this broken code, and learn to use pdb, the python debugger! http://stackoverflow.com/questions/1623039/python-debugging-tips --- https://docs.python.org/2/library/pdb.html – pyInTheSky Feb 13 '16 at 04:37
  • If an answer helped you, you should accept it as a solution. – Hugh Bothwell Feb 18 '16 at 02:52

4 Answers4

1

The only problem I see with this code is in the checkScore() function, every if statement returns the same thing, but there is no return outside of the ifs. If you missed a corner case or something then this will throw an error. I suggest moving the line

return pwin, dwin

outside the if, elif block. If this does not fix your issue then try revising the dloop function; the error you receive should only happen if the function returns None.

Jacob H
  • 864
  • 1
  • 10
  • 25
  • Could you please show me an example of what you mean? – Wattel Feb 13 '16 at 03:35
  • 1
    I did a quick test, and encountered the same thing: `checkScore` sometimes returns `None`. I couldn't see any way for `dLoop` to do so, so I can't reconcile the posted code with the code that generated OP's original error. – Tom Karzes Feb 13 '16 at 03:35
  • 1
    Wattel, there is no final `else:` in `checkScore`, so it sometimes returns `None`. Add an `else:` – Tom Karzes Feb 13 '16 at 03:36
  • Is the else: the problem you think? – Wattel Feb 13 '16 at 03:39
0

Here is the final code results! Does anyone find any problems at all?

##21 Card Game 
##Wattel
##2016 Spring

from random import *
import random
from random import shuffle, randint

CARDPOINTS = {'AD': 11,'AH': 11,'AC': 11,'AS': 11,
              'KD': 10,'KH': 10,'KC': 10,'KS':10,
              'QD': 10,'QH': 10,'QC': 10,'QS': 10, 
              'JD': 10,'JH': 10,'JC': 10,'JS': 10,
              '10D': 10,'10H': 10,'10C': 10,'10S': 10,
              '9D': 9,'9H': 9,'9C': 9,'9S': 9,
              '8D': 8,'8H': 8,'8C': 8,'8S': 8,
              '7D': 7,'7H': 7,'7C': 7,'7S': 7,
              '6D': 6,'6H': 6,'6C': 6,'6S': 6,
              '5D': 5,'5H': 5,'5C': 5,'5S': 5,
              '4D': 4,'4H': 4,'4C': 4,'4S': 4,
              '3D': 3,'3H': 3,'3C': 3,'3S': 3,
              '2D': 2,'2H': 2,'2C': 2,'2S': 2,}

def shuffleDeck():

    List = ['AD','AH','AC','AS',
            'KD','KH','KC','KS',
            'QD','QH','QC','QS', 
            'JD','JH','JC','JS',
            '10D','10H','10C','10S',
            '9D','9H','9C','9S',
            '8D','8H','8C','8S',
            '7D','7H','7C','7S',
            '6D','6H','6C','6S',
            '5D','5H','5C','5S',
            '4D','4H','4C','4S',
            '3D','3H','3C','3S',
            '2D','2H','2C','2S',]
    CardPile = len(List)
    random.shuffle(List)
    return List

def want2play():
    Hit2Play = input(" Hit 'y' to begin your game of 21): ")
    print ("")
    return Hit2Play

def deckCheck(DECK):
    print (DECK)
    print("There are:",len(DECK),"cards in the deck.") 
    if len(DECK) < 20:
        DECK = shuffleDeck() 
        return DECK
    else:
        return DECK

def openingDeal(DECK):
    PHAND = [] 
    DHAND = [] 
    DHANDT = [] 
    PHAND, DECK  = dealOneCard(PHAND, DECK) 
    DHAND, DECK = dealOneCard(DHAND, DECK)
    DHANDT.append(DHAND[0]) 
    PHAND, DECK  = dealOneCard(PHAND, DECK)
    DHAND, DECK = dealOneCard(DHAND, DECK)
    DHANDT.append("back of card")
    PPOINTS = scoreHAND(PHAND)     
    printScores_0(PPOINTS, PHAND, DHANDT)
    return PHAND, DHAND, DHANDT, DECK

def pLoop(PHAND, DHAND, DHANDT, DECK):
    while scoreHAND(PHAND) < 21:
        hitorhold = input('Do you want to hit or hold?: ')
        if hitorhold == 'hit':
            dealOneCard(PHAND, DECK)
            printScores_0(scoreHAND(PHAND), PHAND, DHANDT)
        elif hitorhold == 'hold':
            print('Player holds')
            printScores_0(scoreHAND(PHAND), PHAND, DHANDT)
            break
    return PHAND, DHAND, DECK

def dLoop(PHAND, DHAND, DECK):
    printScores_1(scoreHAND(PHAND), scoreHAND(DHAND), PHAND, DHAND)

    if scoreHAND(DHAND) < 21 or scoreHAND(DHAND) < 21 or scoreHAND(DHAND) < scoreHAND(PHAND) or scoreHAND(DHAND) < 21 or scoreHAND(PHAND) < 22:
        dealOneCard(DHAND, DECK)
        printScores_1(scoreHAND(PHAND), scoreHAND(DHAND), PHAND, DHAND)
        return scoreHAND(PHAND), scoreHAND(DHAND), PHAND, DHAND
    else:
        return scoreHAND(PHAND), scoreHAND(DHAND), PHAND, DHAND


def checkScore(pWin, dWin, PPOINTS, DPOINTS):
    if DPOINTS > PPOINTS and DPOINTS < 22:
        dWin += 1
        print (' ')
        print ("Dealer Win")
        return pWin, dWin

    elif PPOINTS == DPOINTS and PPOINTS < 21:
        dWin += 1
        print (' ')
        print ("Dealer Win")
        return pWin, dWin

    elif PPOINTS > 21 and DPOINTS < 21:
        dWin += 1
        print(' ')
        print("Dealer Win")
        return pWin, dWin

    elif PPOINTS < 22 and DPOINTS > 21:
        pWin += 1
        print (' ')
        print ("Player Win")
        return pWin, dWin

    elif PPOINTS > 21 and DPOINTS > 21:
        print (' ')
        print ("Tie.")
        return pWin, dWin

    else:
        PPOINTS == 21 and DPOINTS == 21
        print(' ')
        print("Tie.")
        return pWin, dWin

def dealOneCard(HAND,DECK):
    theCard = DECK.pop(0)
    HAND.append(theCard) 
    return HAND, DECK

def scoreHAND(HAND):
    points = addScore(HAND) 
    aceCount=0
    if points > 21:
        aceCount += HAND.count('AS')
        aceCount += HAND.count('AH')
        aceCount += HAND.count('AC')
        aceCount += HAND.count('AD')
        while points > 21 and aceCount > 0:
            points -= 10
            aceCount -= 1
        return points
    else:
        return points

def addScore(HAND):
    tempScore = 0
    for i in HAND:
        tempScore += CARDPOINTS[i]
    return tempScore 

def printScores_0(POINTS, HAND, HAND1):
    print("Player's cards: ", HAND, "Player's hand score: ", POINTS)
    print("Dealer's cards: ", HAND1)

def printScores_1(PPOINTS, DPOINTS, PHAND, DHAND):
    print("Player's cards: ", PHAND, "Player's hand score: ", PPOINTS)
    print("Dealer's cards: ", DHAND, "Dealer's hand score: ", DPOINTS)

def main():
    DECK = shuffleDeck()
    pWin = 0
    dWin = 0
    while True:
        Hit2Play = want2play()
        if Hit2Play == 'y':
            DECK = deckCheck(DECK)
            PHAND, DHAND, DHANDT, DECK = openingDeal(DECK)
            PHAND, DHAND, DECK = pLoop(PHAND, DHAND, DHANDT, DECK)
            PPOINTS, DPOINTS, PHAND, DHAND = dLoop(PHAND, DHAND, DECK)
            pWin, dWin = checkScore(pWin, dWin, PPOINTS, DPOINTS)
            print("")
            print("Player's Wins:", pWin, "Dealer's Wins:",dWin)
            print("")

        else:
            print("Player's Wins:", pWin, "Dealer's Wins:",dWin)

            break
main()
Wattel
  • 1
  • 4
0

I presume in your new code you made a typo, and

    else:
        PPOINTS == 21 and DPOINTS == 21
        print(' ')
        print("Tie.")
        return pWin, dWin

should be

    elif PPOINTS == 21 and DPOINTS == 21:
        print(' ')
        print("Tie.")
        return pWin, dWin

If that's the case, I wrote a quick test-frame like so:

results = [[''] * 25 for _ in range(25)]

for dp in range(25):
    for pp in range(25):
        res = checkScore(0, 0, pp, dp)
        if res is None:
            results[dp][pp] = 'N'
        else:
            p, d = res
            results[dp][pp] = ["=+","-="][d][p]

results.reverse()    # flip bottom-to-top
print("\n".join("".join(row) for row in results))

which gives (labels added): Edit: I got the scoring backwards:

      ++++++++++++++++++++++===
      ++++++++++++++++++++++===
      ++++++++++++++++++++++===
D     ---------------------=NNN
e  20 ---------------------N---
a     --------------------NN---       +  player wins
l     -------------------NNN---       =  player ties
e     ------------------NNNN---       -  player loses
r     -----------------NNNNN---
   15 ----------------NNNNNN---
P     ---------------NNNNNNN---       N  game crashes because
o     --------------NNNNNNNN---          checkScore does not
i     -------------NNNNNNNNN---          handle this combination
n     ------------NNNNNNNNNN---          of inputs
t  10 -----------NNNNNNNNNNN---
s     ----------NNNNNNNNNNNN---
      ---------NNNNNNNNNNNNN---
      --------NNNNNNNNNNNNNN---
      -------NNNNNNNNNNNNNNN---
    5 ------NNNNNNNNNNNNNNNN---
      -----NNNNNNNNNNNNNNNNN---
      ----NNNNNNNNNNNNNNNNNN---
      ---NNNNNNNNNNNNNNNNNNN---
      --NNNNNNNNNNNNNNNNNNNN---
    0 -NNNNNNNNNNNNNNNNNNNNN---

      0    5    1    1    2
                0    5    0

           Player Points

I see an awful lot of Ns there.


Edit 2: The solution:

The chart above should make it easy to see the geometric areas involved; we just need to rewrite checkScore to properly handle them:

def check_score(player_wins, dealer_wins, player_pts, dealer_pts):
    if dealer_pts > 21:
        if player_pts > 21:
            # no-one wins (top right square)
            print("\nTie")
            return player_wins, dealer_wins
        else:
            # player wins (top left rectangle)
            print("\nPlayer wins")
            return player_wins + 1, dealer_wins
    else:
        if player_pts > 21:
            # player loses (bottom right rectangle)
            print("\nDealer wins")
            return player_wins, dealer_wins + 1
        elif dealer_pts >= player_pts:
            # player loses (top triangle)
            print("\nDealer wins")
            return player_wins, dealer_wins + 1
        else:
            # player wins (bottom triangle)
            print("\nPlayer wins")
            return player_wins + 1, dealer_wins

and retesting gives us

++++++++++++++++++++++===
++++++++++++++++++++++===
++++++++++++++++++++++===
-------------------------
---------------------+---
--------------------++---      Problem solved!
-------------------+++---
------------------++++---
-----------------+++++---
----------------++++++---
---------------+++++++---
--------------++++++++---
-------------+++++++++---
------------++++++++++---
-----------+++++++++++---
----------++++++++++++---
---------+++++++++++++---
--------++++++++++++++---
-------+++++++++++++++---
------++++++++++++++++---
-----+++++++++++++++++---
----++++++++++++++++++---
---+++++++++++++++++++---
--++++++++++++++++++++---
-+++++++++++++++++++++---
Hugh Bothwell
  • 55,315
  • 8
  • 84
  • 99
0

For sake of comparison I wrote an OO version. Hope you learn lots from it ;-)

from random import shuffle

LOSE, TIE, WIN = -1, 0, 1

def get_yn(prompt, error_message=None, yes_values={'y','yes',''}, no_values={'n','no'}):
    """
    Prompt for input until a yes_value or no_value is entered.
    Return True for a yes_value or False for a no_value
    """
    while True:
        response = input(prompt).strip().lower()
        if response in yes_values:
            return True
        elif response in no_values:
            return False
        elif error_message is not None:
            print(error_message)

class Deck:
    SUITS  = ('D', 'H', 'C', 'S')
    FACES  = ('2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A')
    POINTS = ( 2,   3,   4,   5,   6,   7,   8,   9,   10,  10,  10,  10,  11 )

    def __init__(self):
        self.reset()

    def freshen(self):
        if len(self.cards) < 20:
            self.reset()

    def reset(self):
        self.cards = list(self.CARD_VALUES)
        shuffle(self.cards)

    def deal_to(self, hand):
        card = self.cards.pop()
        hand.cards.append(card)

# Back-patch because we cannot refer to Deck class variables until Deck is fully defined
Deck.CARD_VALUES = {f+s:p for f,p in zip(Deck.FACES, Deck.POINTS) for s in Deck.SUITS}

class Hand:
    def __init__(self):
        self.cards = []

    @property
    def points(self):
        # get sum of cards values, counting aces as 11
        card_value = Deck.CARD_VALUES.__getitem__
        total = sum(card_value(card) for card in self.cards)
        if total > 21:
            # Aces can also be counted as 1;
            #   if total is too high, try to get it <= 21
            max_aces = sum(card[0] == 'A' for card in self.cards)
            use_aces = (total - 12) // 10
            total -= 10 * min(use_aces, max_aces)
        return total

    def __str__(self):
        return "{}  ({} points)".format(" ".join(self.cards), self.points)

    def dealer_first_hand(self):
        # alternate __str__ for use while dealer's second card is hidden
        return "{} ??".format(self.cards[0])

def show_hands(player, dealer, first_hand=False):
    print("Player hand: {}".format(player))
    print("Dealer hand: {}\n".format(dealer.dealer_first_hand() if first_hand else dealer))

class TwentyOne:
    def __init__(self):
        self.deck = Deck()

    @staticmethod
    def result(player_pts, dealer_pts):
        if dealer_pts > 21:
            if player_pts > 21:
                # no-one wins (top right square)
                print("\nTie")
                return TIE
            else:
                # player wins (top left rectangle)
                print("\nPlayer wins")
                return WIN
        else:
            if player_pts > 21:
                # player loses (bottom right rectangle)
                print("\nDealer wins")
                return LOSE
            elif dealer_pts >= player_pts:
                # player loses (top triangle)
                print("\nDealer wins")
                return LOSE
            else:
                # player wins (bottom triangle)
                print("\nPlayer wins")
                return WIN

    def play(self):
        self.deck.freshen()
        player = Hand()
        dealer = Hand()
        # opening deal
        self.deck.deal_to(player)
        self.deck.deal_to(dealer)
        self.deck.deal_to(player)
        self.deck.deal_to(dealer)
        # player loop
        while player.points < 21:
            show_hands(player, dealer, True)
            if get_yn("Do you want to take another card? [Y/n] "):
                self.deck.deal_to(player)
            else:
                print("Player holds\n")
                break
        # dealer loop
        show_hands(player, dealer)
        while dealer.points < 17:
            self.deck.deal_to(dealer)
            show_hands(player, dealer)
        # tally the result
        return self.result(player.points, dealer.points)

def main():
    game   = TwentyOne()
    wins   = 0
    losses = 0
    while True:
        result  = game.play()
        wins   += (result == WIN)
        losses += (result == LOSE)
        print("Player won {}, dealer won {}\n".format(wins, losses))
        if not get_yn("Play again? [Y/n] "): break

if __name__ == "__main__":
    main()
Hugh Bothwell
  • 55,315
  • 8
  • 84
  • 99