Moving items around in a python list? - python

This is the final product. IF anyone else has any tips to cut it up, please let me know! Thanks a lot for the help!
def triple_cut(deck):
''' (list of int) -> NoneType
Modify deck by finding the first joker and putting all the cards above it
to the bottom of deck, and all the cards below the second joker to the top
of deck.
>>> deck = [2, 7, 3, 27, 11, 23, 28, 1, 6, 9, 13, 4]
>>> triple_cut(deck)
>>> deck
[1, 6, 9, 13, 4, 27, 11, 23, 28, 2, 7, 3]
'''
joker1 = deck.index(JOKER1)
joker2 = deck.index(JOKER2)
first = min(joker1, joker2)
first_cards = []
for cards in range(len(deck[:first])):
cards = 0
pop = deck.pop(cards)
first_cards.append(pop)
joker1 = deck.index(JOKER1)
joker2 = deck.index(JOKER2)
second = max(joker1, joker2)
second_cards = []
for cards in deck[second + 1:]:
pop = deck.pop(deck.index(cards))
second_cards.append(pop)
second_cards.reverse()
for card in second_cards:
deck.insert(0, card)
deck.extend(first_cards)
raah I need to type more because my post is mostly code: please add more details sss ss

A hint:
p = list('abcdefghijkl')
pivot = p.index('g')
q = p[pivot:] + p[:pivot]
List slicing is your friend.

answer to the second revision
when the function is finished, it won't mutate the deck.
The problem is that you didn't give the full code. I'm guessing it looks like this:
def triple_cut(deck)
…
deck = q
And according to your docstring you call it as
deck = […]
triple_cut(deck)
and have gotten confused that the assignment deck = q doesn't propagate out of triple_cut(). You can't modify the formal parameters of a method so the assignment remains local to triple_cut and does not affect the module level variable deck
The proper way to write this is
def triple_cut(cuttable)
…
return cuttable[first:] + cuttable[:first]
deck = […]
deck = triple_cut(deck)
where I changed the name of the argument to cuttable to for purposes of explanation. You could keep the argument name as deck but I wanted to show that when you thought you were assigning to deck you were really assigning to cuttable and that assignment wouldn't carry out of triple_cut().

Related

Issue with calculating score

I am trying to generate a blackjack game but I cannot get the values my_score and computers_score to update. They keep giving me value of 0. Can anyone advise?
Code is below. I am expecting the sums of the picked cards for my hand and computer's hand to correspond to the scores, but I am getting return values of 0.
import random
# Create the deck and two empty hands
cards = [11, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10]
my_hand = []
my_score = 0
computers_hand = []
computers_score = 0
# Choose two cards from deck randomly and place into each hand
def hand_builder(chosen_hand, chosen_score):
pick_card = random.choice(cards)
chosen_score = 0
chosen_hand.append(pick_card)
chosen_score += pick_card
for n in range(2):
hand_builder(my_hand,my_score)
hand_builder(computers_hand,computers_score)
print(my_hand)
print(my_score)
print(computers_hand)
print(computers_score)
You have to return your values:
import random
# Create the deck and two empty hands
cards = [11, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10]
my_hand = []
my_score = 0
computers_hand = []
computers_score = 0
# Choose two cards from deck randomly and place into each hand
def hand_builder(chosen_hand, chosen_score):
pick_card = random.choice(cards)
chosen_score = 0
chosen_hand.append(pick_card)
chosen_score += pick_card
return chosen_score
for n in range(2):
# save the output from the function
my_score += hand_builder(my_hand,my_score)
computers_score += hand_builder(computers_hand,computers_score)
print(my_hand)
print(my_score)
print(computers_hand)
print(computers_score)
The reason that the _hand variable is updated is because it is a list. One can update a list in a function without returning a value.
Please read for exmaple: https://www.mygreatlearning.com/blog/understanding-mutable-and-immutable-in-python/
Or use google to look into mutable and immutable variables.

How to update a counter from dictionary Python

I'm new to Python and coding in general and am trying to create a blackjack game in Python but I'm having trouble getting the point counter point_selection to update based on the card values in the player's hand:
deck_points = {2 : 2, 3 : 3, 4 : 4, 5 : 5, 6 : 6, 7 : 7, 8 : 8, 9 : 9, 10 : 10, 'J' : 10, 'Q'
: 10, 'K' : 10, 'A' : 11 }
dealer_hand = []
player_hand = []
dealer_points = 0
player_points = 0
def deal_initial_cards(hand, point_selection):
for i in range(2):
i = random.choice(list(deck_points))
hand.append(i)
for card in hand:
point_selection += deck_points[card]
deal_initial_cards(dealer_hand, dealer_points)
print(dealer_points)
Using the above code, the counter never updates past '0' and I'm not sure what I'm doing wrong. Any help is appreciated.
Here's a more Pythonic solution that fixes your main bug about your function deal_initial_cards() operating on a copy of its (immutable) int argument point_selection then throwing away the result, since it doesn't have a return point_selection (or store the result in a class member self.points). (Also, I made all your dict keys strings: '2','3',.... It's usually customary to represent '10' as 'T' to make all cards a single letter).
But since you're essentially declaring a Hand class, then instantiating two objects of it (dealer_hand, player_hand). deal_initial_cards() is essentially a Hand._init__() in disguise, so we have a data member cards (best not to also call it hand). See how simple and clean ph = Hand() is; no need for globals. Moreover, we could statically compute points inside the __init__() function and return it (or, better, store it in self.points inside each hand object), but that would be a bad decomposition, since if we subsequently add cards to self.cards, points wouldn't get updated. So, much more Pythonic is to make points a property of the class. We then access it
without parentheses: dh.points, not dh.points(). Last, note the use of a list comprehension (instead of a for-loop-append) to generate self.hand. And inside points(), note the use of a generator expression deck_points[card] for card in self.cards, again more Pythonic than for-loop counter. So this small example is a great showcase of Python idiom and decomposition. We can add a __str__() method to Hand. (You could also have a Card class, but really that would be overkill.)
import random
deck_points = {'2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9, 'T': 10, 'J' : 10, 'Q'
: 10, 'K' : 10, 'A' : 11 }
# No globals, so no need to initialize anything
class Hand:
def __init__(self):
self.cards = [random.choice(list(deck_points)) for _ in range(2)]
#property
def points(self):
return sum(deck_points[card] for card in self.cards)
def __str__(self, join_char=''):
return join_char.join(card for card in self.cards)
#deal_initial_cards(dealer_hand, dealer_points)
ph = Hand()
dh = Hand()
print('Dealer: ', end='')
print(dh.points)
print('Player: ', end='')
print(ph.points)
Python ints are immutable, this means dealer_points isn't updated. Initialy they have the same id(use id()), but when you change the variable inside the function it creates a new variable. To fix your code you need to do something like
deck_points = {2 : 2, 3 : 3, 4 : 4, 5 : 5, 6 : 6, 7 : 7, 8 : 8, 9 : 9, 10 : 10, 'J' : 10, 'Q'
: 10, 'K' : 10, 'A' : 11 }
dealer_hand = []
player_hand = []
dealer_points = 0
player_points = 0
def deal_initial_cards(hand, point_selection):
for i in range(2):
i = random.choice(list(deck_points))
hand.append(i)
for card in hand:
point_selection += deck_points[card]
return point_selection
dealer_points = deal_initial_cards(dealer_hand, dealer_points)
print(dealer_points)
whereas a list, which you probably noticed, is mutable. This means the list inside the function stays the same(keeps its id) even when its edited.

calling function multiple times with new results

I wanted to create a poker simulation that creates a certain number of 5-card poker hands, to see how many times hands I need to play till I get the royal flush...
I wrote a function that generates 5 cards but when i run the function multiple times it won't work --> i get 5*x cards instead of multiple hands with each 5 cards
import random
d = []
h = []
def cards():
l1 = ["Herz", "Karo", "Pik", "Kreuz"]
l2 = [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
for i in range(10):
d.append([])
for k in range(10):
d[k].append(l1[random.randint(0, (len(l1) - 1))])
d[k].append(l2[random.randint(0, (len(l2) - 1))])
for a in d:
if a not in h:
h.append(a)
if len(h) == 5:
break
else:
continue
return h
for i in range(2):
print(cards())
When I run the code, I get the following:
[['Karo', 8], ['Herz', 5], ['Pik', 13], ['Herz', 12], ['Karo', 3]]
[['Karo', 8, 'Karo', 5], ['Herz', 5, 'Karo', 6], ['Pik', 13, 'Herz',
4], ['Herz', 12, 'Herz', 5], ['Karo', 3, 'Pik', 3], ['Karo', 8,
'Kreuz', 3], ['Karo', 9, 'Kreuz', 3], ['Pik', 13, 'Herz', 10], ['Pik',
6, 'Karo', 11], ['Karo', 2, 'Pik', 13], []]
Your code currently has global lists that it keeps appending to. This is almost certainly not what you want.
I would suggest creating a deck of cards, and sampling them without replacement to get a hand of five. You can get up to 10 such hands from a deck of 52 cards. A better way might be to create the deck and shuffle it, picking off 5 cards at a time until it contains fewer than 5 cards.
In either case, you could then pass each hand through a function that tests if it is a flush or whatever else you want.
All the tools you will need for this (until you use numpy), are in the itertools and random modules.
First create a global deck. There is no need to do this multiple times because it will slow you down to no purpose. The deck of cards won't change, only their order will:
rank = [str(x) for x in range(2, 11)] + list('JQKA')
suit = list('♠♥♦♣')
deck = list(''.join(card) for card in itertools.product(rank, suit))
Now you can use this deck to generate from 1 to 10 hands at a time with no repeating cards between them. The key is that shuffling the deck is done in place. You don't have to regenerate the deck every time:
def make_hands(cards=5, hands=None):
if hands is None:
hands = len(deck) // cards
if cards * hands > len(deck):
raise ValueError('you ask for too much')
if cards < 1 or hands < 1:
raise ValueError('you ask for too little')
random.shuffle(deck)
result = [deck[cards * i:cards * i + cards] for i in range(hands)]
You can change the desired number of cards per hand and hands per deck with this function. Let's say that you also have a function to check if a hand is a flush or not called isflush. You could apply it like this:
def how_many():
shuffles = 0
hands = 0
while True:
shuffles += 1
cards = make_hands()
for hand in cards:
hands += 1
if isflush(hand):
return shuttles, hands
shuffles, hands = how_many()
print(f'It took {hands} hands with {shuffles} reshuffles to find a flush')

Python List, taking one item from one to another

(newbie) I have looked for answers, however, other examples are not sufficient for what I am looking for. As the title states, I am simply trying to take one item, or in this case card , from one list to another. The two lists are called 'deck' and 'hand.'
Once you pull from one list, it goes into the other, and gets deleted from its original.
Edit made more specific:
deck = [cat, cat, cat, cat, cat, cat, cat, dog, dog, dog, dog, dog, dog, bird, bird, shark, shark, shark]
hand = []
new_deck = []
def startUpCards():
if len(deck) >= 7:
hand = random.sample(deck, 7)
new_deck = [item for item in deck if item not in hand]
deck = list(new_deck)
elif len(deck) < 7:
hand = random.sample(deck, len(deck))
new_deck = [item for item in deck if item not in hand]
deck = list(new_deck)
So above is what you start out with, and everything comes out correct as intended. However, this is where my problem comes in, although no error occurs:
def addNewCard():
if len(deck) > 0:
hand.extend(random.sample(deck, 1))
new_deck = [item for item in deck if item not in hand]
deck = list(new_deck)
else:
sleep(2)
print ("You don't have any more cards in your deck!")
startUpCards()
cardChosen = input("Which card do you want to draw?")
def rmv_hand():
hand.remove(cardChosen)
addNewCard()
`print(hand)`
The issue that I am finding is that after the first draw, hand is shortened by 1, possibly meaning it didn't draw from deck, right?
I also see that my print string ("You don't have any more cards in your deck!") is printing waaay before I expect it to! What's going on?
You're going through far too much work. Use randrange to select a card by position. Use pop to remove that element from the deck, and immediately append it to the receiving hand. Here is a simple example:
import random
deck = [1, 2, 3, 4, 5]
hand = [11, 12, 13, 14, 15, 16, 17]
# Choose a random card from the deck *by position*
draw_pos = random.randrange(len(deck))
print "Pulling card #", draw_pos, "from deck to hand"
hand.append(deck.pop(draw_pos))
print deck
print hand
Sample output:
Pulling card # 2 from deck to hand
[1, 2, 4, 5]
[11, 12, 13, 14, 15, 16, 17, 3]
Does that get you going?

Why wont my function add lists properly?

This is the function i wrote for a program, its supposed to move a value a spot down a list.
def moveCard(deck):
index = deck.index(27)
deck.pop(index)
left = deck[:index+1]
right = deck[index+1:]
left.append(27)
print (left + right)
deck = left + right
however it doesn't properly add the two lists unless i print it within the function it self.
running the funtion using text list cards = [24, 27, 2, 5, 8, 11] prints out the proper list, being [24, 2, 27, 5, 8, 11]. However if i then simply ask for the value of cards after running the method i get
[24, 2, 5, 8, 11]. Any ideas why this is happening?
EDIT
this is my function:
def move_joker_1(deck):
index = deck.index(JOKER1)
deck.pop(index)
left = deck[:index+1]
right = deck[index+1:]
left.append(JOKER1)
deck = left + right
print(left + right)
print(dec
This is what i type into shel/results:
cards = [24, 27, 2, 5, 8, 11]
move_joker_1(cards)
[24, 2, 27, 5, 8, 11]
[24, 2, 27, 5, 8, 11]
print(cards)
[24, 2, 5, 8, 11]
I think your problem is this:
Inside the moveCard function, you've got a parameter named deck. First you do this:
deck.pop(index)
That's modifying the actual list that was passed in, so the caller is going to see that.
Then, later:
deck = left + right
That isn't modifying anything; it's creating a new list, left + right, and changing the local variable deck to be a name for that new list instead of for the old one.
What you probably want to do here is return the new list, so the caller can store it wherever he wants. But in that case, you don't want to mutate the original list with pop.
Alternatively, you could modify the list in-place both times, e.g., by writing deck[:] = left + right.
From your edit: you are not modifying the cards list. You should put a return statement in your function and then call the function as follows: cards = move_joker_1(cards).

Categories