I am making a game using pygame based on the game war. I am getting an error when running the code for splitting my deck in the main loop (it is in its own file). The error says:
"/usr/local/Cellar/python/2.7.10_2/Frameworks/Python.framework/Versions/2.7/lib/python2.7/random.py", line 275, in choice
return seq[int(self.random() * len(seq))] # raises IndexError if seq is empty
IndexError: list index out of range
The deck splitting file looks like this:
import Deck
from random import *
deck = Deck.deck
playerDeck = []
AIDeck = []
def splitDeck():
player_deck_count = 26
while player_deck_count > 0:
transfer_card = (choice(deck))
playerDeck.append(transfer_card)
deck.remove(transfer_card)
player_deck_count -= 1
AIDeck = deck
shuffle(playerDeck)
shuffle(AIDeck)
print "Player deck length:" + str(len(playerDeck))
print "AI deck length:" + str(len(AIDeck))
print "Deck length:" + str(len(deck))
The Deck file looks like this:
deck = [
'2_c',
'2_d',
'2_h',
'2_s',
I get that is has to do with the sequence (list is empty) but there is obviously still 26 cards in the original deck. I have tried changing when the while player_deck_count loop stops but with no luck. Thanks for the help in advance
P.S. just comment if you want the main loop.
I believe your problem is that you are relying on the function to set the value of AIDeck. When you attempt to set
AIDeck = deck
you are moving the reference of AIDeck to the reference of deck. When the function returns, AIDeck is restored to its original definition, which was the empty list. If you are doing choice(AIDeck) anywhere in your file, it is probably the cause of your error.
Related
I have a list that's been modified in one function, and I want it to go to another function in order to be read and modified further.
def get_cards_player():
deck = Deck()
deck.shuffle()
player1 = []
player2 = []
you_won = False #if u won, var is true, if u lose, var is false
for i in range(5):
player1_cards = deck.get_card()
player1.append(player1_cards.get_name())
player2_cards = deck.get_card()
player2.append(player2_cards.get_name())
print('Your Hand:',', '.join(player1))
print('Opponent Hand:',', '.join(player2))
return player1, player2
def calc_winner():
I want player1 and player2 lists in get_cards_player function to go to the calc_winner function so that I can read the list and do stuff with it.
Thanks.
calc_winner should take these lists as parameters. I purposely changed the names to highlight that parameters don't have to have the same name in different functions.
get_cards_player already creates and returns the lists, so no need to change. Again, to show the different ways you can do this, I'm remembering the tuple containing the two players and using that in the call.
def calc_winner(p1list, p2list):
print(p1list, p2list)
players = get_card_player()
calc_winner(players[0], players[1])
A function is overwitting a variable which is given it as an argument. Why?
What is this whole code supposed to do:
create a list (main deck) of objects representing cards
create an empty list for storage od the ids of cards already drawn from the main deck
choose randomly 5 cards from the main deck and add them to the list (player's deck)
return temp list of ints (ids of cards in the main deck) to a variable
add items from the temp list to the main list
import random
from common import cards
deck = cards.deck() # creates a list of 52 class objects representing cards
def main():
used_cards_ids = [] # this one is being overwritten in the next step, according to the debugger
players_deck, temp_used_cards_ids = generate_players_deck(used_cards_ids) # this is the "next step"
used_cards_ids.extend(temp_used_cards_ids) # adds id of the cards which were drawn from the main deck
print(used_cards_ids) # prints a double list of cards ids (i.e 1, 2, 3, 4, 5, 1, 2, 3, 4, 5)
def generate_players_deck(temp_used_cards_ids):
players_deck = []
counter = 0
while counter < 5: # until 5 cards were drawn
cards_id = random.randint(0, 51) # chooses a random card
if cards_id not in temp_used_cards_ids: # checks if the card with the same id weren't previously drawn
counter += 1
temp_used_cards_ids.append(cards_id) # adds card's id to the list of drawn cards
players_deck.append(deck[cards_id]) # adds card to the player's deck
else:
continue
return players_deck, temp_used_cards_ids # returns player's deck (list of cards objects) and list of ids of the drawn cards
main()
When you pass in used_cards_ids to generate_players_deck(), you are providing the body of generate_players_deck() to append data to used_cards_ids, which you've aliased to temp_used_cards_ids.
You then get the value back from the return statement of that function, which you store in the variable temp_used_cards_ids, and then you extend that temp_used_cards_ids, which is actually used_cards_ids, essentially altering the list you passed in twice.
When you pass a list as a function argument, you aren't passing the values of the list, you're passing a reference to the original list. That's probably where your confusion is coming from, or perhaps the switch between variable names and function argument aliasing.
This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 6 years ago.
Needless to say the following code does not work and the fault or problem seems to be that the function does not access or recognise the list [cards]. On the other hand if I place the list [cards] within the function, the code works perfectly. I had assumed that variables placed in the main code were global, and variables declared in a function were just local.
#!/usr/bin/python
import random
cards = ['A︎♣︎︎', '2︎♣︎︎', '3︎♣︎︎', '4︎♣︎︎', '5︎♣︎︎', '6︎♣︎︎', '7︎♣︎︎', '8︎♣︎︎', '9︎♣︎︎', '10︎♣︎︎', 'J︎♣︎︎', 'Q︎♣︎︎',
'K︎♣︎︎', 'A♠︎', '2♠︎', '3♠︎', '4♠︎', '5♠︎', '6♠︎', '7♠︎', '8♠︎', '9♠︎', '10♠︎', 'J♠︎',
'Q♠︎', 'K♠︎', 'A︎♥︎', '2︎♥︎', '3︎♥︎', '4︎♥︎', '5︎♥︎', '6︎♥︎', '7︎♥︎', '8︎♥︎', '9︎♥︎', '10︎♥︎',
'J︎♥︎', 'Q︎♥︎', 'K︎♥︎', 'A︎♦︎︎', '2︎♦︎︎', '3︎♦︎︎', '4︎♦︎︎', '5︎♦︎︎', '6︎♦︎︎', '7︎♦︎︎', '8︎♦︎︎', '9︎♦︎︎',
'10︎♦︎︎', 'J︎♦︎︎', 'Q︎♦︎︎', 'K︎♦︎︎']
# define function
def sort_cards(hand):
temp = []
for n in range(0, 7):
temp.append(cards.index(str(hand[n])))
# sort cards
temp.sort()
hand = []
# fetch card according to index and assign to hand
for c in temp:
hand.append(cards[c])
return hand
# copy cards list to working list
rem_cards = cards
# initiate players card list
player1 = []
player2 = []
player3 = []
# define variable
# 7 cards per player
deal = 7
while deal != 0:
# get a card from rem_cards and assign to player1
card = rem_cards[random.randint(0, len(rem_cards) - 1)]
player1.append(card)
# remove card from deck
rem_cards.remove(card)
card = rem_cards[random.randint(0, len(rem_cards) - 1)]
player2.append(card)
rem_cards.remove(card)
card = rem_cards[random.randint(0, len(rem_cards) - 1)]
player3.append(card)
rem_cards.remove(card)
deal -= 1
print(sort_cards(player1))
print(sort_cards(player2))
print(sort_cards(player3))
print("No of cards left in the deck is ", len(rem_cards))
Any suggestions or is my concept just wrong?
Take a look at your comments:
# copy cards list to working list
rem_cards = cards
This code does not make a copy of the list, it creates another name, under which the original list could be accessed. Whenever you modify rem_cards, cards is modified. Thus, rem_cards.remove(card) actually removes the card from cards!
If you want to copy the list, use copy.[deep]copy:
import copy
# copy cards list to working list
rem_cards = copy.deepcopy(cards) # if cards could contain other lists
rem_cards = copy.copy(cards) # create a simple shallow copy
rem_cards = cards[:] # you may create shallow copies without the copy module
This also will solve your problem without using copy.deepcopy
rem_cards = cards[:]
rem_cards = cards
does not copy the list, but just creates an alias. It should be
rem_cards = list(cards)
I would like to note that I'm using Discord.py and some of it's included libs.
So I'm trying to check if an index in a list exists but I keep getting the ValueError saying that the index does not exist in my list.
Here's my code:
def deal_card(self):
U = self.usedCards
randCard = randchoice(list(self.cards))
if not U: #check if it is empty
#if it is empty, just add the card to used cards
U.append(randCard)
elif U.index(randCard): #check if card is already in the list
#if it is, pick another one
randCard = randchoice(list(self.cards))
U.append(randCard)
else: #check if card is not in list
#if it is not, just add it to the used cards
U.append(randCard)
return randCard
self.cards is full of card names and self.usedCards is a list of cards alredy picked by randCard.
hand is my command and P4 is one of the cards in self.cards
I found some solutions saying that adding a try block will solve the problem but I don't know how to add it in the middle of my if statement.
Thanks in advance!
list.index() should be used for finding the index of a list's member. To check whether an item is in a list, simply use in:
if not U:
# do stuff
elif randCard in U:
# do other stuff
This is probably a terrible way to deal your cards, because then you have the cards both in your discard pile and in your deck.
Why not just move the cards around?
import random
cards = ['H{}'.format(val) for val in range(1, 11)]
print(cards)
discard_pile = []
while cards:
random.shuffle(cards)
card = cards.pop()
print('You drew a {}'.format(card))
discard_pile.append(card)
while discard_pile:
cards.append(discard_pile.pop())
# or
cards.extend(discard_pile)
discard_pile.clear()
You don't need to use the index function:
elif randCard in U:
If you would still like to use the .index function for some reason and not follow the above suggestions you could use the try statement as follows:
try:
c = U.index(randCard)
randCard = randchoice(list(self.cards))
U.append(randCard)
except ValueError:
U.append(randCard)
Write a function, deal(numhands, n=5, deck), that
deals numhands hands with n cards each.
import random # this will be a useful library for shuffling
from random import shuffle
# This builds a deck of 52 cards. If you are unfamiliar with this
# notation, check out Andy's supplemental video
# on list comprehensions (you can find the link in the
# Instructor Comments box below).
mydeck = [r+s for r in '23456789TJQKA' for s in 'SHDC']
def deal(numhands, n=5, deck=mydeck):
mynew = shuffle(deck)
if numhands*n > len(deck):
raise Exception('Not enough cards.')
hands = []
for i in range(0,numhands):
ncards = []
for j in range(0,n):
ncards.append(mynew.pop())
hands.append(ncards)
return hands
print deal(2)
I am not sure what is wrong with the function but it keeps telling me this error
in deal
ncards.append(mynew.pop())
AttributeError: 'NoneType' object has no attribute 'pop'
random.shuffle shuffles in place
it changes the original deck ... it does not return anything
so just use deck