Daniel Ratner
Daniel Ratner

Reputation: 1

List index out of range: len(list) does not update after a few iterations

When I run the following code, I receive this error message:

IndexError: list index out of range

What is causing this?

cardChosen = deck[random.randint(0, len(deck))]

should keep decreasing for its maximum range every round, but the program says I am out of range.

import random

deck = [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14] * 4

scorePlayer1 = 0
scorePlayer2 = 0

player1 = input("Player 1: ")
player2 = input("Player 2: ")

while len(deck) > 0:
  def player_turn(player_name, deck):
    deck = deck
    print(len(deck))
    cardChosen = deck[random.randint(0, len(deck))]
    deck.remove(cardChosen)
    print(player_name + " chose " + str(cardChosen))
    return(cardChosen)

  a = player_turn(player1, deck)
  b = player_turn(player2, deck)

  if a > b:
    scorePlayer1 += 2
    print(player1 + " wins this round:)")
  elif b > a:
    scorePlayer2 += 2
    print(player2 +  " wins this round :)")
  elif a == b:
    print("War!")

  print(scorePlayer1)
  print(scorePlayer2)
else:
  print("Game Over")
  if scorePlayer1 > scorePlayer2:
    print(player1 + " has won the game:)")
  elif scorePlayer2 > scorePlayer1:
    print(player2 + " has won the game:)")
  elif scorePlayer1 == scorePlayer2:
    print("There has been a tie, both players won:)")

Upvotes: 0

Views: 55

Answers (2)

Maz
Maz

Reputation: 35

I encourage you to take a look at this rendition of your code. It can seem a little daunting at first, BUT it's only because there's so many #notes that I put in.

Here is the version with the notes

’’’
import random

deck = [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14] * 4
#>>> suggestion below
length = len(deck)
round = 1

scorePlayer1 = 0
scorePlayer2 = 0

player1 = input("Player 1: ")
player2 = input("Player 2: ")
print("Round: {}".format(round)) #>>> used for user clarification

# >>> Removed "while" statement, and kept the
#main player turn function as its own stand alone function
def player_turn(player_name, length):
    #deck = deck >>>Line not needed
    #print(len(deck)) >>> removed
    #cardChosen = deck[random.randint(0, len(deck))] >>>solution below
    cardChosen = random.choice(deck)
    deck.remove(cardChosen)
    #suggestion below
    length -= 1
    #print(player_name + " chose " + str(cardChosen)) >>>suggestion below
    print("{} drew the card: {}".format(player_name, cardChosen))
    #return(cardChosen) >>> suggestion below
    return cardChosen, length

#as long as the length of the deck (which is updated
#everytime the function is called) is greater than zero
while length > 0:
    round += 1#>>> used for user clarification
    #set the variables cardChosen and length to equal
    #whatever the output of the player turn function (with
    #2 argument given) returns
    cardChosen, length = player_turn(player1, length)

    #then set the players score to equal the card drawn
    scorePlayer1 += cardChosen
    player1_hand = cardChosen

    #afterwards repeat the same for player 2
    cardChosen, length = player_turn(player2, length)
    scorePlayer2 += cardChosen
    player2_hand = cardChosen

    #>>>replace "a" and "b" with better, readable variables
    #if a > b:
    if scorePlayer1 > scorePlayer2:
        scorePlayer1 += 2
        #print(player1 + " wins this round:)") >>> use the format method, highly recommended. suggestion below
        print("{} won this round".format(player1))
        print("{}'s score: {}".format(player1, scorePlayer1))
        print("{}'s score: {}".format(player2, scorePlayer2))

        print("\n\n") #>>>adds a space between rounds
    elif scorePlayer2 > scorePlayer1:
        scorePlayer2 += 2
        #print(player2 +  " wins this round :)") >>>suggestion below
        print("{} won this round".format(player2))
        print("{}'s score: {}".format(player1, scorePlayer1))
        print("{}'s score: {}".format(player2, scorePlayer2))
        print("\n\n") # >>> adds a space between rounds
    if player1_hand == player2_hand:
        #print("War!") >>> suggestiom below
        print("WAAAAAAAR!!!") #>>>How will anyone take you seriously if you dont scream!
        print("{}'s score: {}".format(player1, scorePlayer1))
        print("{}'s score: {}".format(player2, scorePlayer2))
        print("\n\n") # >>> adds a space between rounds
    #else: >>> unneeded "else" statement since the "while" loop automatically
    #stops once there are no more cards in the deck
    #add a pause so the viewer can comprehend what the heck just happened
    print("Number of cards left: {}".format(length))
    pause = input("Press ENTER to continue...")
    print("============================\n\n") #>>> adds a space
    print("Round: {}".format(round))


print("Game Over")
if scorePlayer1 > scorePlayer2:
    #print(player1 + " has won the game:)") >>> suggestion below
    print("{} has won the game".format(player1))
elif scorePlayer2 > scorePlayer1:
    #print(player2 + " has won the game:)") >>> suggestion below
    print("{} has won the game".format(player2))
elif scorePlayer1 == scorePlayer2:
    print("There has been a tie, both players won:)")
```

And here is the version without the notes. Notice that it's just about the same size.

import random

deck = [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14] * 4
length = len(deck)
round = 1
scorePlayer1 = 0
scorePlayer2 = 0
player1 = input("Player 1: ")
player2 = input("Player 2: ")
print("Round: {}".format(round))

def player_turn(player_name, length):
    cardChosen = random.choice(deck)
    deck.remove(cardChosen)
    length -= 1
    print("{} drew the card: {}".format(player_name, cardChosen))
    return cardChosen, length

while length > 0:
    round += 1
    cardChosen, length = player_turn(player1, length)
    scorePlayer1 += cardChosen
    player1_hand = cardChosen
    cardChosen, length = player_turn(player2, length)
    scorePlayer2 += cardChosen
    player2_hand = cardChosen

    if scorePlayer1 > scorePlayer2:
        scorePlayer1 += 2
        print("{} won this round".format(player1))
        print("{}'s score: {}".format(player1, scorePlayer1))
        print("{}'s score: {}".format(player2, scorePlayer2))

        print("\n\n")
    elif scorePlayer2 > scorePlayer1:
        scorePlayer2 += 2
        print("{} won this round".format(player2))
        print("{}'s score: {}".format(player1, scorePlayer1))
        print("{}'s score: {}".format(player2, scorePlayer2))
        print("\n\n")
    if player1_hand == player2_hand:
        print("WAAAAAAAR!!!")
        print("{}'s score: {}".format(player1, scorePlayer1))
        print("{}'s score: {}".format(player2, scorePlayer2))
        print("\n\n")
    print("Number of cards left: {}".format(length))
    pause = input("Press ENTER to continue...")
    print("============================\n\n")
    print("Round: {}".format(round))

print("Game Over")
if scorePlayer1 > scorePlayer2:
    print("{} has won the game".format(player1))
elif scorePlayer2 > scorePlayer1:
    print("{} has won the game".format(player2))
elif scorePlayer1 == scorePlayer2:
    print("There has been a tie, both players won:)")

Please know that I am a beginner too, but I figure that we gotta help each other out you know?

So to answer your question, the problem like others have said can be solved using the random.choice(list) method

But other stuff that I would point out that could GREATLY shorten your code would be to start dipping your toes in classes. It's so much easier than it looks, but classes will allow you to create a 'player' class, that has objects called score, or name, or card_drawn so players.name = 'Mike', players.score = 27 etc...

I also restructured and placed your functions up top. This way your actual game play can be seperate. I very loosely think of functions as labels that alter the way the program is run. If you've ever used command prompts GOTO command it can almost in some small way be looked at the same way. The program STOPS, and goes to the function no matter where it is AS LONG as the function has ALREADY been defined.

If you have any questions please feel free to ask me, you could probably even help me out some too.

Upvotes: 0

Guimoute
Guimoute

Reputation: 4649

You are fetching random items 1 too far.

When the length of your list is 1 and you only have a choice left, cardChosen = deck[random.randint(0, len(deck))] is equivalent to cardChosen = deck[0] or deck[1] which does not exist.

You want to use random.randint(0, len(deck)-1).

Edit: always check the documentation of the libraries you use. For example, the built-in range(a, b) does not include b while random.randint(a, b) does.

Upvotes: 2

Related Questions