user2137452
user2137452

Reputation: 145

Is it possible the len function in python is malfuntioning?

This is a very strange error, I have no idea what is going on. Essentially my code is top trumps its not fully done yet but anyway. For those of you who have played top trumps my code simulates the passing of cards between the two hands. However if you look at line 129 (if len(Your_Hand)== 0:) where I have used len() to print the length of these hands, they dont add up. Ie len() says a length which when one reads the list is obviously not right?

Thanks if you could take a look and try and help me as to what is going on that would be brilliant!

This is my code:

#top trumps stuff
import random
import time

pack = [("harry Potter",2,3,4,5),
         ("Hermione Granger", 5,6,7,8),
         ("Ron Weasley", 12, 13,4,5),
         ("Neville Longbottom", 1,1,1,1),
         ("Ginny Weasley",2,3,4,5),
         ("Draco Malfoy",3,6,7,8) ]

pile_1 = []
pile_2 = []
clash_pile = []
Your_Hand = 0
Opponent_Hand = 0
end_loop=0
catagory_exchange = {"brains":0,
                     "knowledge": 1 ,
                      "cunning": 2, 
                      "evil":3}

choice = 0
acceptable_answers = catagory_exchange.keys()
proceed = 0
clash = 0 
end_game = 0

#Shuffles the pack
random.shuffle(pack)

# Deals the cards
Dealer_count =0
while Dealer_count <len(pack):
    pile_1.append(pack[0])
    pack.remove(pack[0])
    pile_2.append(pack[0])
    pack.remove(pack[0])

#Asks Which pile they'd like
Which_Pile = raw_input(">> Which Pile would you like 1 or 2?")

while end_loop  != 1:
    if Which_Pile == "1":
        Your_Hand = pile_1
        Opponent_Hand = pile_2
        print "Lets now start!"
        end_loop = 1

    elif Which_Pile == "2":
        Your_Hand = pile_2
        Opponent_Hand = pile_1
        print "Lets now start!"
        end_loop = 1
    else:
        Which_Pile =  raw_input("You didn't pick 1 or 2! Pick again!!")

while end_game != 1:

    print len(Your_Hand)
    print Your_Hand

    print len(Opponent_Hand)
    print Opponent_Hand

    print Your_Hand[0]
    choice = raw_input(">> choose a catagory, brains, knowledge, cunning, evil - ")

    if choice in acceptable_answers:
        proceed = 1
    else:
        print "Thats not an catagory"

    if proceed == 1:

        if Your_Hand[0][catagory_exchange[choice]] > Opponent_Hand[0][catagory_exchange[choice]]:
            if clash == 1:
                print "You won the cards from previous rounds aswell!!"
                clash = 0
                clash_pile[:] = []

            else:
                print "You won the card you received %s" % Opponent_Hand[0][0]
            Your_Hand.append(Opponent_Hand[0])
            Your_Hand.append(clash_pile)
            Opponent_Hand.remove(Opponent_Hand[0])
            Your_Hand.append(Your_Hand[0])
            Your_Hand.remove(Your_Hand[0])

        elif Your_Hand[0][catagory_exchange[choice]] < Opponent_Hand[0][catagory_exchange[choice]]:
            if clash ==1:
                print "You lost the cards from previous rounds aswell"
                clash = 0
                clash_pile[:] = []

            else:
                print "You lost the card"
            Opponent_Hand.append(Your_Hand[0])
            Your_Hand.append(clash_pile)
            Your_Hand.remove(Your_Hand[0])
            Opponent_Hand.append(Opponent_Hand[0])
            Opponent_Hand.remove(Opponent_Hand[0])

        if Your_Hand[0][catagory_exchange[choice]] == Opponent_Hand[0][catagory_exchange[choice]]:
            clash =1
            print "They both have the same value"
            print "They have been added to a pile which you will win when you win the next round"
            clash_pile.append(Your_Hand[0])
            clash_pile.append(Opponent_Hand[0])
            Opponent_Hand.remove(Opponent_Hand[0])
            Your_Hand.remove(Your_Hand[0])

if len(Your_Hand)== 0:
    print "Oh no! You have run out of cards! You lose!!"

if len(Opponent_Hand)==0:
    print "Well done! Your opponent has run out of cards! You win!!"

Upvotes: 0

Views: 375

Answers (2)

steveha
steveha

Reputation: 76715

I rewrote your program and it works for me now. Several things I found:

The big problem was the one noted by @Kevin in his answer: you were using list.append() instead of list.extend() to copy cards from clash_pile.

Also, category_exchange contained values that were off by one. Item 0 in each card is a string, and choosing brains was causing a string compare between card names. (I was very puzzled when I kept winning hands with Neville Longbottom!)

I rewrote the code to move cards. Instead of first calling .append() and then calling .remove(), I am calling .pop() to remove the value and return it, and doing that inside .append(). When it's all on one line, you are less likely to see a bug where someone changes just one of the two lines of code.

Also, instead of flag variables to signal when an acceptable input has been found, I am using infinite loops and simply breaking when an acceptable input has been found.

Also, instead of using flag variables to signal things like "clash pile has cards in it", or checking for length of 0 on card lists, I changed it to just directly check the list values.

Also, since I am very lazy, I made the program accept a number for a category. Instead of typing knowledge you can just type 2 and it works.

Let me know if you have any questions.

#top trumps stuff
import random
import time

pack = [
    ("Harry Potter",2,3,4,5),
    ("Hermione Granger", 5,6,7,8),
    ("Ron Weasley", 12, 13,4,5),
    ("Neville Longbottom", 1,1,1,1),
    ("Ginny Weasley",2,3,4,5),
    ("Draco Malfoy",3,6,7,8)
]

pile_1 = []
pile_2 = []
clash_pile = []
category_exchange = {
    "brains" : 1,
    "knowledge" : 2 ,
    "cunning" : 3, 
    "evil" : 4,
}

#Shuffles the pack
random.shuffle(pack)

# Deals the cards
while pack:
    pile_1.append(pack.pop(0))
    pile_2.append(pack.pop(0))

#Asks Which pile they'd like

while True:
    Which_Pile = raw_input(">> Which Pile would you like 1 or 2?")
    if Which_Pile.strip() == "1":
        Your_Hand = pile_1
        Opponent_Hand = pile_2
        print "Lets now start!"
        break
    elif Which_Pile.strip() == "2":
        Your_Hand = pile_2
        Opponent_Hand = pile_1
        print "Lets now start!"
        break
    else:
        print "You didn't pick 1 or 2! Pick again!!"

while True:
    if not Your_Hand:
        print "Oh no! You have run out of cards! You lose!!"
        break

    if not Opponent_Hand:
        print "Well done! Your opponent has run out of cards! You win!!"
        break

    print "\n"

    print "DEBUG: Opponent: len: %d  top_card: %s" % (len(Opponent_Hand), str(Opponent_Hand[0]))
    print "DEBUG: You: len: %d  top_card: %s" % (len(Your_Hand), str(Your_Hand[0]))

    print "Here is your top card: '%s'" % str(Your_Hand[0])

    while True:
        choice = raw_input(">> choose a category, brains, knowledge, cunning, evil: ")

        if choice in category_exchange:
            i = category_exchange[choice]
            break
        else:
            try:
                i = int(choice)
            except ValueError:
                pass
            if i in category_exchange.values():
                break
        print "That's not a category"


    print "Opponent had: %s" % str(Opponent_Hand[0])

    if Your_Hand[0][i] > Opponent_Hand[0][i]:
        if clash_pile:
            print "You won the cards from previous rounds as well!!"
        else:
            print "You won the card!"

        Your_Hand.append(Opponent_Hand.pop(0))
        Your_Hand.extend(clash_pile)
        clash_pile = []
        Your_Hand.append(Your_Hand.pop(0))

    elif Your_Hand[0][i] < Opponent_Hand[0][i]:
        if clash_pile:
            print "You lost the cards from previous rounds as well"
        else:
            print "You lost the card!"

        Opponent_Hand.append(Your_Hand.pop(0))
        Opponent_Hand.extend(clash_pile)
        clash_pile = []
        Opponent_Hand.append(Opponent_Hand.pop(0))

    else:
        assert Your_Hand[0][i] == Opponent_Hand[0][i]
        print "Both cards have the same value."
        print "They have been added to a pile which will go to the next winner."
        clash_pile.append(Your_Hand.pop(0))
        clash_pile.append(Opponent_Hand.pop(0))

Upvotes: 1

Kevin
Kevin

Reputation: 76194

After a few rounds my hand had a length of 3, composed of one Ron Weasley card, and two empty lists: [('Ron Weasley', 12, 13, 4, 5), [], []]. I'm guessing you don't want to have those empty lists there.

The culprit appears to be this line:

Your_Hand.append(clash_pile)

Which always adds an empty list to your hand.

you probably want extend rather than append. Additionally, you should add the clash pile to the winner's hand before you reset the clash pile to [].

Other observations possibly not related to your original problem:

  • the if in the line if Your_Hand[0][catagory_exchange[choice]] == Opponent_Hand[0][catagory_exchange[choice]]: should probably be elif
  • you get the cards in the clash pile regardless of who actually wins the clash
  • the game does not end when I take my opponent's last card
  • If every card goes into the clash, the players no longer have anything to fight with (although that may be a problem inherent to Top Trumps)

Upvotes: 4

Related Questions