calling function multiple times with new results - python

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

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.

my list value changing incorrectly - python

im trying to generate mastercard card number.
requirements :
first element must be 5
second element must be between 1 and 5
last element must be lcheck digit returned from luhn algorithm.
i have check digit function with luhn algorithm, so far everything is okay.
but when i give parameter my card number to generateCheckDigit function in generateMasterCard function, my card number is returned as multiplied by 2, one element apart during the luhn algorithm.
sorry for my bad english
here is the codes:
def generateCheckDigit(numbers):
if len(numbers)%2 == 1:
for i in range(0,len(numbers),2):
numbers[i] *= 2
else:
for i in range(1,len(numbers),2):
numbers[i] *= 2
check_digit = (sum(numbers)*9) % 10
return check_digit
def generateMasterCard():
card_number = [5, rd.randint(1,5)]
for i in range(13):
card_number.append(rd.randint(0,9))
print(f"first number : {card_number}")
check_digit = generateCheckDigit(card_number)
card_number.append(check_digit)
return card_number
output :
first number : [5, 4, 1, 4, 0, 8, 4, 8, 0, 4, 2, 8, 8, 2, 9]
[10, 4, 2, 4, 0, 8, 8, 8, 0, 4, 4, 8, 16, 2, 18, 4]
You can import copy and use generateCheckDigit(copy.copy(card_number)) as
Alexey Larionov sais in comments "In Python if you pass to a function some complicated value, like class instance, list, dictionary, etc, then your function can freely modify it. In your case, you do operation numbers[i] *= 2 and it changes the list you passed". Passing a copy allows you to avoid this.

How to get a function to run twice dynamically

This is a function.
def cut_dk():
a = []; b = []
random.shuffle(deck__)
slice = deck__[:2]
a.append(slice[0])
b.append(slice[1])
return a,b
c = cut_dk()
p1 = c[0]
p2 = c[1]
I have this function at the top of the program along with other functions.
It draws from a predefined list.
When calling this function dynamically in the program it returns the same variables.
It's the cutting of a card deck (two cards, highest wins the draw), when the cards are equal it needs to draw again (this is the problem, a second draw), a new selection from the list, yet it just repeats the variables it has in memory.
Calling the function again in a conditional statement just returns the same initial variables acquired on the first run, so I am unable to repeat the cut dynamically as part of the game play.
I would manage my deck as an object here with a class. This would allow us to define a deck, which is stored as an object and perform multiple functions against the deck whilst retaining the state changes from different functions.
class deck:
"""
Class designed to manage deck including iterations of changes.
Shuffling the deck will retain shuffle changes
"""
def __init__(self):
self.deck = [1, 2, 3, 4, 5, 6, 7, 8, 9, 'J', 'Q', 'K', 'A']
self.original = self.deck[:]
def shuffle(self):
"""
Shuffle deck in-place. self.deck will be modified
"""
random.shuffle(self.deck)
def cut(self):
"""
Shuffles deck and draws the two top-most cards
Returns: tuple(2) two cards from top of the deck
"""
self.shuffle()
a, b = self.deck[:2]
return a, b
def highest_draw(self):
"""
Calls self.cut() to shuffle and retrieve 2x top-most cards.
If cards match the deck is shuffled and cut again.
Returns: 2 Unique cards from top of the deck
"""
a, b = self.cut()
while a == b:
a, b = self.cut()
return a, b
def reset(self):
self.deck = self.original[:]
game = deck()
game.deck
#[1, 2, 3, 4, 5, 6, 7, 8, 9, 'J', 'Q', 'K', 'A']
game.shuffle()
game.deck
#['A', 7, 5, 9, 8, 'J', 'K', 6, 4, 3, 1, 'Q', 2]
game.reset()
game.deck
#[1, 2, 3, 4, 5, 6, 7, 8, 9, 'J', 'Q', 'K', 'A']
game.cut()
#('A', 'Q')
game.highest_draw()
#('J', 2)
You would still need to define how you determine the "highest" card, however this is dependant on your deck, which you have left out of the question.
It sounds as if a generator function would be useful here. You call the function once to set up your iterator and then 'draw' cards from that iterator (in this case the iterator is 'cards'). Notice you have to catch the case where you run the whole deck and it's tied throughout. I've sprinkled print statements through this to make it easier to understand how generators work.
import random
deck__ = list(range(3))*2
def draw_from_shuffled():
random.shuffle(deck__)
print(f'Deck after shuffling: {deck__}')
for c in deck__:
yield c
cards = draw_from_shuffled() #cards is now an iterator
while True:
try:
a = next(cards)
b = next(cards)
except StopIteration:
print(f'End of deck!')
cards = draw_from_shuffled()
continue
print(f'Drew {a} and {b}')
if a != b:
break
print('Hand done.')
Sample output:
Deck after shuffling: [2, 2, 1, 1, 0, 0]
Drew 2 and 2
Drew 1 and 1
Drew 0 and 0
End of deck!
Deck after shuffling: [0, 0, 2, 2, 1, 1]
Drew 0 and 0
Drew 2 and 2
Drew 1 and 1
End of deck!
Deck after shuffling: [0, 2, 1, 0, 1, 2]
Drew 0 and 2
Hand done.
More on generators: https://realpython.com/introduction-to-python-generators/

How do you print values in lists with their index number in Python 2.7?

I am trying to make a Blackjack game in python. I ran into a problem because I am trying to use the random module with my game. I used the random module to get a number that coordinates with the index number in my list. The list I made consisted of card face values. I don't know how to print these values using the random index number, though. Here is my code:
# this is a blackjack game made in python
import random
import time
# make a list full of the card values
cards = (["A", "K", "Q", "J", 2, 3, 4, 5, 6, 7, 8, 9, 10])
indexNum1 = random.randint(0,12)
indexNum2 = random.randint(0,12)
indexNum3 = random.randint(0,12)
indexNum4 = random.randint(0,12)
indexNum5 = random.randint(0,12)
for card in cards:
print card(indexNum1)
print card(indexNum2)
print card(indexNum3)
print card(indexNum4)
print card(indexNum5)
I hope someone can help me solve this problem. Thanks!
You can index cards directly, e.g.:
print(cards[indexNum1])
But if you want in a loop you should iterate over the indexes:
for cardidx in (indexNum1, indexNum2, indexNum3, indexNum4, indexNum5):
print(cards[cardidx])
But you are making this much harder than you need to, because currently your code could return 5 Aces - which I assume you don't want:
cards = ["A", "K", "Q", "J", 2, 3, 4, 5, 6, 7, 8, 9, 10]
hand = random.sample(cards, k=5)
for card in hand:
print(card)
If you want to properly simulate a deck of cards, you'll have to do this:
import random
def clean_deck():
return list("AJQK234567890") * 4
def draw_cards(deck, n):
return [deck.pop() for _ in range(n)]
deck = clean_deck()
random.shuffle(deck)
for card in draw_cards(deck, 5):
print(card)
This keeps track of the deck of cards, literally shuffles them, which is conveniently a random function, and then "draws" from the deck (pops). You have to keep track of the deck so you could, for example, draw 4 aces but then there wouldn't be any more left. This approach is also persistent across card-drawings - when you draw cards from the deck, they are actually removed, so you also can't draw more than 4 aces in an entire game. It will crash if you try to draw from an empty deck, although you could put an if statement in draw_cards to refill the deck if needed, but you should be aware that this would happen if the deck ran out - it could lead to weird things like 5 aces in a game.
I've changed all your digits to strings, as there's no use for them as integers if some cards aren't integers. (An alternative is to keep them all as integers, which you can do with the range function - at a guess range(13), or if you want to go from 2, range(2, 15)). I've also changed 10 to 0 as 0 was unused and that made it a lot more concise. It should be easy enough to change back should you wish.
The difference between this and the other approaches is that the other approaches never remove cards (pop). They just randomly pick cards and then put them back, although they've been drawn.
If you want to randomly choose k cards without repetition and keep the indices, this may helps:
import random
cards = (["A", "K", "Q", "J", 2, 3, 4, 5, 6, 7, 8, 9, 10])
indices = random.sample(range(len(cards)), k=5)
print 'Indices are:', indices, '\nCards chosen are:',[cards[index] for index in indices]

Moving items around in a python list?

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().

Categories