Python - Referencing lists in functions [duplicate] - python

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)

Related

How to pass a list between two functions?

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])

How do i avoid getting a list inside of a list

I am making a blackjack simulator with python and are having problems with when the player want another card. To begin with the player gets a random sample of two numbers from a list and then get the option to take another card or not to. When the answer is yes another card is added to the random sample but it gets added as a list inside of the list.
This is is the line when the answer is yes to another card.
if svar == "JA":
handspelare.append(random.sample(kortlek,1))
print(handspelare)
This returns, [5, 10, [13]] and it is this list inside of the list i want to get rid of so i can sum the numbers, any suggestions on how i can get rid of this?
random.sample(kortlek,1)
random.sample returns a list, so you end up appending a list to handspelare (which creates the sublists).
You could change append to extend, but random.sample(..., 1) is just random.choice, so it makes more sense to use handspelare.append(random.choice(kortlek)).
you should create a deck then shuffle it
deck = [52 cards]
deck.shuffle()
then just draw off it like a normal deck in the real world
hand.append(deck.pop())
if len(deck) < 15: # or something
deck = [52 cards]
deck.shuffle()
Use list concatenation rather than append.
handspelare += random.sample(kortlek,1)
append will not unbundle its argument
a = [1]
a.append([2]) # [1, [2]]
a = [1]
a += [2] # [1, 2]

Why is my function overwriting a variable, when it's theoretically not supposed to? (Python 3.8)

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.

Python - Copying lists in a loop [duplicate]

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.
I'm kinda new to python... So I've been strugling with a problem for a while and after doing a huge research I did not find solution so I decided to ask here :).
So the code that is explaining my problem:
test = []
solutions = []
i = 0
while i < 100:
for i in range(0, 64):
pos = random.randrange(0, 64)
test.append(pos)
solutions.append(test)
test.clear()
i += 1
So I want to add a copy of a table to another table everytime the loop goes and then clean the table named test. The problem is I don't know how to create a copy of list each time the loop goes. So I'm getting list of empty lists :(
I tried with copy.copy or copy.deepcopy but that didn't work.
That is my first question here so sorry for any "errors" also I'm not native english speaker but I hope you will be able to understand me.
You can append duplicates by calling the list constructor
solutions.append(list(test))
You can do copy the list like:
solutions.append(test[:])
And to empty it, since there is no empty method, you can just reassign it to a new empty list:
test = []
Like Zaphod mentioned, your while loop never finished, since you were never updating the value of i, plus is was being assigned in the inner for loop anyway. Why not use two nested for loops? (the underscore is just a var placeholder signifying the value is not used)
import random
test = []
solutions = []
for _ in range(0, 100):
for i in range(0, 64):
pos = random.randrange(0, 64)
test.append(pos)
solutions.append(test[:])
test = []
print solutions
if you want clean simply dont use test.clear()
use:
test = []
you should remove the test.clear(), and change <100 of while because is infinite
import random
test = []
solutions = []
i = 0
while i < 100:
for i in range(0, 64):
pos = random.randrange(0, 64)
test.append(pos)
solutions.append(test)

Random choice function

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.

Categories

Resources