Poker Game Swapping Out Cards For Different Cards - python

Okay so, I'm onto the next step after dealing the cards to two players.
I need the program to be able to take the player's desired cards it wants to get rid of and exchange them for new random cards. The player will be questioned how many and which cards it wants to exchange. The code should be something like if the player inputs '1' for one throwaway card and then the player has the option to select which card to remove. So that card will then be removed from the hand or list in the code and replaced with 1 new one. This only happens once and then it should print both players' hands.
Every where I look, it's done in a more complicated way and I know it's simple coding but I really do suck at the most simplest things.
What I've got so far:
def poker():
import random
(raw_input('Welcome to a classic game of Poker! You will recieve 5 cards. You will have the option to exchange 1 to 3 cards from your hand for new cards of the same amount you exchanged. IF you have an Ace in your beginning hand, you may exchange that Ace for up to four new cards (three other cards including the ace). ~Press Enter~'))
(raw_input('S = Spades , H = Hearts , C = Clubs , D = Diamonds ~Press Enter~'))
deck = ['2S','2H','2C','2D','3S','3H','3C','3D','4S','4H','4C','4D','5S','5H','5C','5D','6S','6H','6C','6D','7S','7H','7C','7D','8S','8H','8C','8D','9S','9H','9C','9D','10S','10H','10C','10D','Jack(S)','Jack(H)','Jack(C)','Jack(D)','Queen(S)','Queen(H)','Queen(C)','Queen(D)','King(S)','King(H)','King(C)','King(D)', 'Ace(S)','Ace(H)','Ace(C)','Ace(D)']
new_cards = ''
player1 = []
player2 = []
random.shuffle(deck)
for i in range(5): player1.append(deck.pop(0)) and player2.append(deck.pop(0))
print player1
int(input('How many cards would you like to exchange? 1, 2, 3, or 4 IF you have an Ace.'))
#ignore this for now
int(input('Which card would you like to exchange? 1, 2, 3, 4, or 5? Note: The first card in your hand (or list in this case) is the number 1 spot. So if you want to exchange the first card, input 1. The same is for the other cards.'))
The card that was exchanged in the beginning hand also can't be accessible from the deck list after swapping. So like... ['8D','2S','Queen(H),'8S','Jack(H)']
If I wanted to remove 1 card, I choose to remove '2S', '2S' will no longer be in my hand and will be swapped out with a different card from the deck. '2S' will also not return to my hand for any reason because it can't be taken from the list a second time. So the output should be all the same cards EXCEPT the '2S' will be missing and a new card will be in it's place.
There is the standard removing up to 3 cards at once but you can also remove up to 4 cards IF you have an Ace in your beginning hand. But you should be rejected and then asked once more how many cards you want to get rid of if you don't provide an Ace to the question.

What could work is the following :
n_cards_to_exchange = int(input('How many cards would you like to exchange? 1, 2, 3, or 4 IF you have an Ace.'))
for i in range(n_cards_to_exchange):
print(player1)
card_text = ', '.join([str(j) for j in range(1,5-i)]) + f', or {5-i}?'
card_id = int(input(f'Which card would you like to exchange? {card_text} Note: The first card in your hand (or list in this case) is the number 1 spot. So if you want to exchange the first card, input 1. The same is for the other cards.')) - 1
deck.append(player1.pop(card_id))
random.shuffle(deck)
for i in range(n_cards_to_exchange):
player1.append(deck.pop(0))
The idea is that the player chooses the number of cards he wants to drop, and then chooses which cards he want to drop multiple times. Then he draws back cards from the deck. If you need any clarification, feel free to ask.

Related

I want to compare the permutations of decks

The goal is to (dis)prove a concept by comparing permutations of decks of cards.
A deck contains a number of blue cards(b) and red cards(r). These can be any permutation of that amount of b and r. If it's a 3 card deck with two blue cards and one red, the possibilities would be:
bbr, brb, rbb
For phase 1, the fact that "b1" and "b2" could be in either position is irrelevant. Those permutations are the same, by comparison.
Therefore,
A 9 card deck with 4 blue cards and 5 red cards would have outcome X.
A 10 card deck with 4 blue cards and 6 red cards would have outcome Y.
If you start with the above 4b/6r deck and randomly remove 1 red card, you will have outcome Z.
The possible permutations of outcomes X and Y are, of course, different. The outcomes of X and Z should be equivalent. (I believe.)
Phase 2 would now consider the probabilities of each permutation. So, for outcomes X and Z, we want to know if the odds of each permutation are the same between X and Z. (I believe they are, again.)
My bit of searching on my own has led me to believe I want to be using itertools, but I am having trouble putting that into the context that I need it for this exercise.

Anomalous probability result for computed single pair probability when dealing seven card poker hands

BACKGROUND: Today I thought I'd begin a small project building a poker
simulator. The first task I set was to deal cards from a shuffled
deck, and check the various numerically generated probabilities
against accepted values. The first such probability I checked was
the single pair probability--that is, generating (numerically) the
probability of being dealt a single pair, given as inputs the number
of cards dealt and the number of hands dealt, where each hand
is dealt from a separate shuffled deck. Cards are dealt from the
top of the deck. Below I show the beginning of that program.
I first tested numerically generated single pair probability
for five card hands. The computed value comes to within
a tenth of a percent of the accepted single pair probability
for five card hands (but always high by about a tenth of a percent): https://en.wikipedia.org/wiki/Poker_probability
However, when I test the numerically generated single pair probability
for seven card hands, I find that I am off by 4% to 5% from the
accepted value (e.g., typical computed value = 0.47828; accepted value as per above = 0.438). I've run the numerical experiments up to ten
million hands dealt. The computed single pair probability for seven
card hands is stable, and remains off by 4% to 5% from the accepted value. It's not clear
why this is the case.
QUESTION: Why is this the case? I suspect that my code is not taking
something into account, but I cannot detect what. Python code follows . . .
NOTE: Issue 31381901 is similar to this one. But in the below code the issue of double counting is accounted for by converting the dealt hand to a set, which will eliminate duplicate values, thus reducing the size of the set (in the case of 7 card hands) from 7 to 6. That reduction indicates a single pair. If three-of-a-kind is present, then the size of the set would be 5, since two of the three cards in the three-of-a-kind would be eliminated by the set conversion.
from random import shuffle
def make_deck():
'''Make a 52 card deck of cards. First symbol
is the value, second symbol is the suit. Concatenate
both symbols together.
Input: None
Output: List
'''
value = ['A', '2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K']
suit = ['C','H','S','D']
deck = [j+i for j in value for i in suit]
return deck
def shuffle_deck(deck, times_to_shuffle=7):
'''Shuffle a deck of cards produced by make_deck().
Default: 7 times.
Input: list, int
Output: list (modified in-place)
'''
for n in range(times_to_shuffle):
shuffle(deck)
def test_for_single_pair(hand, cards_per_hand):
'''Tests for presence of a single pair in
a dealt hand by converting the hand to a set.
The set representation of a hand with a single
pair will have one less member than the original
hand.
Input: list, int
Output: int
'''
hand_values_lst = [card[0] for card in hand]
hand_values_set = set(hand_values_lst)
set_size = len(hand_values_set)
if set_size == (cards_per_hand - 1):
return 1
else:
return 0
def deal_series_of_hands(num_hands,cards_per_hand):
'''Deals a series of hands of cards and tests
for single pairs in each hand. Creates a deck
of 52 cards, then begins dealing loop. Shuffles
deck thoroughly after each hand is dealt.
Captures a list of the dealt hands that conform
to the spec (i.e., that contain one pair each),
for later debugging purposes
Input: int, int
Output: int, int, list
'''
deck = make_deck()
single_pair_count = 0
hand_capture = []
for m in range(num_hands):
shuffle_deck(deck)
hand = deck[0:cards_per_hand] #first cards dealt from the deck
pair_count = test_for_single_pair(hand, cards_per_hand)
if pair_count == 1:
single_pair_count += pair_count
hand_capture.append(hand)
return (single_pair_count, num_hands, hand_capture)
cards_per_hand = 7 #User input parameter
num_hands = 50000 #user input parameter
single_pair_count, num_hands_dealt, hand_capture = deal_series_of_hands(num_hands, cards_per_hand)
single_pair_probability = single_pair_count/ num_hands_dealt
single_pair_str = 'Single pair probability (%d card deal; poker hands): '%(cards_per_hand)
print(single_pair_str, single_pair_probability)
If the hand contains a single pair but also contains a higher-value unit such as a straight or a flush, your code still counts that as a pair, where the probability article does not.

Psuedo-random generation: is this more or less random?

I'm curious about how this works out mathematically, but I'm not smart enough to figure it out myself. (I tried)
If you generate a list of 1000 psuedo-random numbers, such as:
random_numbers = []
for i in range(1,1000):
random_numbers.append(random.randrange(1000,9999))
Then generate another psuedo-random number to use as an index for the list:
final_value = random_numbers[rand.randrange(1,1000)]
Intuitively, this seems like it would be more random than simply generating 1 psuedo-random value like this:
number = random.randrage(1000,9999)
However, I know there's often a lot of gotchas with randomness so I figured I'd ask you guys.
Funny enough, it's the same!
While it seems intuitive that you'd end up with a more random number because you're "adding more randomness" to your pick by running the random number generator repeatedly - because randrange approximates a uniform distribution your sample space ends up being identical between the two options. Let's take a look at a simpler example of this:
Say that you've got a standard deck of 52 cards. You pick 10 cards from this list at random while allowing yourself to pick duplicate cards (ie. you could end up picking the same card multiple times). The chance that you'll pick any card in particular is equal to:
10 * 1/52 = 10/52
Because the odds of you picking the card each time is 1/52 and you repeat that 10 times. Now, let's assume that we've picked our card in the first group: how likely is it going to be that we're going to pick it from the second group? Well we'll have a 1 in 10 chance to pick it now!
The probability that we'll pick any particular card in the first pick and then the second pick is:
10/52 * 1/10 = 1/52
Which is the exact same probability as picking any old card in the first place!

Pick Up Sticks / Intelligent AI / Python

BACKGROUND INFO, DON'T HAVE TO READ IF YOU'D JUST LIKE TO VIEW THE PROBLEM WITH CODE BELOW:
I hope everyone is familiar with the game of sticks or "nim." If not, you set a starting amount of sticks (between 10 and 50) and draw (1-3 sticks) until there aren't any sticks left, declaring the one who pulled the last stick the loser. In my programming class we've also included the option of playing against the AI. But, the AI is no longer a dummy who randomly picks a number 1-3. Now he learns from each of his turns.
Implementation:
The AI has a bucket for each of the number of sticks left. There is a bucket for 1 stick
left, 2 sticks, 3 sticks, etc.
At the beginning of the game each bucket has 3 balls in it. Each marked with the choice
1, 2 or 3. These represent the AI’s choice of picking up 1, 2 or 3 sticks.
During the AI’s turn, it takes a random ball from the bucket representing the number of
sticks left. It reads the ball and removes that number of sticks from the pile. It then
places the ball in front of the bucket.
If the AI wins the game, then it goes through all of its choices and puts two balls back for
the chosen number for each choice it made. Increasing its chances of choosing that ball
the next time it’s faced with a choice with the given number of sticks.
If the AI loses, then it throws the ball away next to the buckets. However, if the chosen
ball is the last choice then it puts it back into the bucket. The bucket must contain at
least one of each number. So if the user chose a ball that had a number of sticks to
pick from a bucket, and it was the last ball of that choice, then if the AI loses, it must put
that ball back. It can never remove any of the choices completely from the buckets.
As more games are played the AI will reinforce good choices with extra balls for winning
sticks picked up."
Here's the code I'm working with right now.
choice=random.randint(1,maxchoice) #computer picks a random number
bucketnum=sticks #bucket to take ball from
pullnum=choice #ball to take
for i in bucket:
for bucket[bucketnum] in i:
bucketnum.pop(pullnum)
print(bucket[bucketnum])
The bucket that I'd be taking the ball out of would essentially be the number of sticks left, I'm just having trouble finding a specific bucket in the bucket list and taking out the ball. Right now I get an error message saying that bucketnum.pop(pullnum) - 'int' object has no attribute to 'pop'? This is the bucket code (lists within a list):
bucket=[]
for j in range(51):
bucket.append([1,2,3])
I may be totally confusing but if anybody has any advice or even questions for clarification, please do reply. Thanks all.
EDIT:
Here's some more code, sorry, stupid of me to refrain from adding the definitions of variables, etc.
if option==2:
sticks=""
while True:
try:
sticks=int(input("Enter the number of sticks to begin with: "))
if sticks>=10 and sticks<=50:
print("Alright, there are",sticks,"sticks in the pile.")
break
else:
print("You mut enter an integer. (10-50)")
except ValueError:
print("You must enter an integer.")
player1=True
while sticks>0:
maxchoice=min(3,sticks)
choice=-1
countbucket=0
if player1:
while choice<1 or choice>maxchoice:
try:
choice=int(input("Player 1, how many sticks would you like to take? (1-3): "))
if choice>=1 and choice<=3:
sticks-=choice
print("There are",sticks,"sticks remaining.")
else:
print("You must enter an integer from 1-3.")
except ValueError:
print("You must enter an integer.")
player1=not player1
else:
choice=random.randint(1,maxchoice)
bucketnum=sticks
pullnum=choice
for i in bucket:
for bucket[bucketnum] in i:
bucketnum.pop(pullnum)
print(bucket[bucketnum])
sticks-=1
print("Computer drew",choice,"stick(s). There are",sticks,"sticks remaining.")
player1=not player1
if player1==False:
print("Player 1 took the last stick.\nComputer wins!")
else:
print("Player 1 wins!")
This is option 2 in my program, as option 1 is Player 1 vs. Player 2. Obviously I haven't gotten very far with the implementation of the AI intelligence, it's a bit tricky.
-----> Fred S., I'm just getting started and having issues getting the mental wheel spinning. What's excerpted isn't all of the code. I'm not asking how to complete the assignment at this point, though tips on executing this new intelligent AI code would be helpful, but in this case it's more a focus on figuring out list indexing.
It looks like you're assigning the variable in the inner for loop to 'bucket[bucketnum]'. Which surprises me that that's not a syntax error, but I don't think that's what you're trying to actually do.
If you're dealing with a nested list, and the position in the list corresponds to the number of sticks left, then you want to index that list by the position in order to get that bucket, instead of iterating over that list to find it.
If you think of it like this:
buckets = [[1,2,3], ..., ..., ...]
Then the bucketnum is the position of the bucket in the list of buckets. So, in your case, if you want to grab the bucket for '26' sticks, you would access it by indexing buckets by that number.
buckets[25] # 25 since you're counting from 0+
At this point, you have the bucket in question, and can pop the choice from it.
bucket = buckets[25]
bucket.pop(pullnum)
You didn't define option
You didn't import the random library.

Speed up Risk wargame dice rolling simulation

Friends and I were wondering what the % chance of victory was in various situations in the board game, Risk, which involves a world war over an Earth-like board divided into territories.
For those unfamiliar with Risk:
In each turn of the game an attacker can decide to invade a defender's country on the board. The attacker and defender choose how many dice to use for the battle. For example the attacker can in some situations decide to attack with 3 dice and the defender might choose to defend with 2 dice.
Attacker rolls 3 dice and gets 6,4,1
Defender rolls 2 dice and gets 6,3
If the same number is rolled, defender always wins, so in this situation,
we compare the attacker's two highest rolls against the defender's.
The defender's 6 beats the attacker's 6 and
the attacker's 4 beats the defender's 3.
In this case each side loses 1 army. This could continue with more dice rolls until the attacker stops attacking or runs out of armies, but at this point I am only interested in the frequency of wins on single tosses of the dice.
So I wrote a batch to simulate many times rather than entering the counterintuitive world of probabilities. I'm fairly new to coding so I'm looking for tips on efficiency. I am yet to fathom multiprocessing so we'll leave that out for now if that's ok.
I was surprised at how long it took to do one million simulations (around 20 seconds) and was wondering if there's something I'm doing wrong or if this is the sort of time you might expect from such a routine.
Here's the simulation part:
from random import randint
# Pass in number of each dice and number of sim's
def simulate(attDice,defDice,rolls):
attLosses = 0
defLosses = 0
for roll in rolls: # Number of simulations
attRolls = [] # List holding attack dice 'scores'
for die in range(attDice): # Number of attack dice rolled
attRolls.append(randint(1,6))
defRolls = [] # List holding defence dice 'scores'
for die in range(defDice): # Number of defence dice rolled
defRolls.append(randint(1,6))
while len(attRolls) and len(defRolls): # For each
if max(attRolls) > max(defRolls): # Att's must beat def's
defLosses += 1
else:
attLosses += 1
# Delete the highest number from each list
del(attRolls[attRolls.index(max(attRolls))]) # This seems clumsy
del(defRolls[defRolls.index(max(defRolls))]) # which is what makes me
# think there's a better way
return attLosses,defLosses
# We then go and work out percentages etc.
Lots of handwaving, totally unrigorous answer.
I'm not surprised with ~20s for one million rounds. I've done similar experiments/simulations in Python with the same experience. Granted, those experiments are not really time critical so I did not optimize.
And Python isn't really known for speed. Maybe you're used to lower-level languages. If you did the same experiment in Java, I would be surprised if it took you as long.
(If you really want to speed this up, maybe some context in your question will help? Your purpose seems casual so aside from some constant-time speed-ups and maybe some micro-optimizations, I see little to change.)
Since you are in effect sorting the dice lists, it is better to use python's sort function which is fast.
Generating random numbers is also relatively slow. By only generating one number for all the dice you can accelerate it somewhat.
This runs in ~5s on my computer for a million rolls if attDice and defDice are smallish (<=5). (With PyPy it runs in 1s.)
def freqs(attDice, defDice, rolls):
m = min(attDice, defDice)
freq = [0]*(m+1)
for i in range(rolls):
ar = random.randrange(6**attDice)
dr = random.randrange(6**defDice)
ad = [(ar / 6**j) % 6 for j in range(attDice)]
ad.sort(reverse=True)
dd = [(dr / 6**j) % 6 for j in range(defDice)]
dd.sort(reverse=True)
aws = sum(j > k for j, k in zip(ad, dd))
freq[aws] += 1
return freq
It returns a frequency table of attacker wins.
Here's the start of a numpy implementation for 1,000,000 rolls.
I've marked this community wiki if someone wants to expand it, edit away.
3 attack dice, 2 defend dice
import numpy
A = numpy.random.randint(1,6,size=(1000000,3)).sort()
D = numpy.random.randint(1,6,size=(1000000,2)).sort()
Ahigh = A[:,2]
Dhigh = D[:,2]
Awins1st = (Ahigh > Dhigh)
A2nd = A[:,1]
D2nd = D[:,1]
Awins2nd = (A2nd > D2nd)
# needed: tabulate results, remove smelly repeating code, generalize
Awins1st and Awins2nd are 1000000 element true/false arrays, indicating whether the attacker won the 1st or 2nd "battle" from comparing the 3 A dice to the 2 D dice.

Categories

Resources