How to program blackjack scoring for an ace - python

I am trying to create a blackjack simulation so I can test various strategies and simulate them indefinitely. The biggest problem I have encountered is how to score an ace card. Ideally if you were dealt an ace, it would look at your score and it will give you 1 or 11 accordingly however I can't avoid if you were dealt a Five(5), Ace(11) and then a Six(6) to giving you a bust when you should have 12.
class Person:
wins = 0
def __init__(self, call):
self.call = call
self.hand = []
def deal(self, cards_dealt):
cards_in_deck = len(deck)
for card in range(0, cards_dealt):
card_position = (random.randint(0, cards_in_deck) - 1)
self.hand.append(deck[card_position])
deck.pop(card_position)
cards_in_deck -= 1
def total(self):
my_total = 0
for x in range(0, len(self.hand)):
if self.hand[x][0] > 10:
my_total += 10
if self.hand[x][0] == 1:
if self.total < 11:
my_total += 11
else:
my_total += 1
else:
my_total += self.hand[x][0]
return my_total
numbers_in_each_suit = 13
suits = ['Spades', 'Hearts', 'Diamonds', 'Clubs']
deck = []
for number in range(0, numbers_in_each_suit):
for suit in suits:
deck.append([(number + 1), suit])
cpu = Person(10)
cpu.deal(2)
cpu.total()

Just use 1 for number for creating ace, add 11 for every ace and count each ace, and then subtract 10 if you bust until you don’t or until you run out of aces to decrement.

Related

Creating the war(card) game using OOP in Python

I am trying to create the war card game where 2 players draw a card each on the table, and the player whose card has max value gets both the cards, if the card values are equal(called war condition) each player draws 5 cards, and the value of the last card among these 5 cards are compared and works similarly as above. A player wins when either the other player runs out of cards or if in war condition the other player has less than 5 cards.
My questions:
When I am running the game logic sometimes it runs but sometimes it gets stuck in an infinite loop. Why?
I can notice that when the total number of cards for both players at all times should be 52, but here it is decreasing. Why? (I can see that the cards are getting lost every time the game goes into war condition, but I am not able to understand why that is happening, since I am adding all the 10 cards to the player whose card has a greater value.)
I have tried another method where I assume that players are always at war and then approach it, which works. But I want to understand why, if I break it into steps which I am trying to do here, is it not working?
Code:
import random
suits = ['Hearts','Clubs','Spades','Diamonds']
ranks = ['Two','Three','Four','Five','Six','Seven','Eight','Nine','Ten','Jack','Queen','King','Ace']
values = {'Two': 2, 'Three': 3, 'Four': 4, 'Five': 5, 'Six' : 6 , 'Seven' :7, 'Eight': 8,'Nine':9,
'Ten':10,'Jack':11, 'Queen': 12,'King': 13,'Ace':14 }
classes:
class Card():
def __init__(self,suit,rank):
self.suit = suit
self.rank = rank
self.value = values[rank]
#string method
def __str__(self):
return self.rank + ' of ' + self.suit
class Deck():
def __init__(self):
self.all_cards = [] #list of objects
for suit in suits:
for rank in ranks:
#create card object
created_card = Card(suit,rank)
self.all_cards.append(created_card)
def shuffle(self): #method to shuffle the card
random.shuffle(self.all_cards)
def deal_one(self):
return self.all_cards.pop() #we want the last card from deck
class Player():
def __init__(self,name):
self.name = name
self.all_cards = []
def remove_one(self):
return self.all_cards.pop(0) #to remove card from beginning of the list
def add_cards(self,new_cards):
if type(new_cards) == type([]):
self.all_cards.extend(new_cards)
else:
self.all_cards.append(new_cards)
def __str__(self):
return f'Player {self.name} has {len(self.all_cards)} cards.'
And below is the final game logic:
#create 2 new instances of the player class
player1_name = input('Enter the name of Player1: ')
player2_name = input('Enter the name of Player2: ')
player1 = Player(player1_name)
player2 = Player(player2_name)
newdeck = Deck()
newdeck.shuffle()
#splitting the deck among the two players - alternate card from deck goes to each player respectively
for i in range(0,len(newdeck.all_cards)-1,2):
player1.add_cards(newdeck.all_cards[i])
player2.add_cards(newdeck.all_cards[i+1])
#for x in range(26):
# player1.add_cards(newdeck.deal_one())
#player2.add_cards(newdeck.deal_one())
print(player1)
print(player2)
game_status = True
round_num = 0
while game_status == True:
round_num +=1
print(f"Round {round_num}")
if len(player1.all_cards) == 0:
print('Player 1 out of cards'+ player2.name + 'Wins!')
game_status = False
break
if len(player2.all_cards) == 0:
print('Player 2 out of cards' + player1.name + 'Wins!')
game_status = False
break
else:
player_cards = []
player1_card = player1.remove_one()
player2_card = player2.remove_one()
player_cards.append(player1_card)
player_cards.append(player2_card)
print('player1_card_value: ',player1_card.value)
print('')
print('player2_card_value: ',player2_card.value)
print('')
print(player1)
print('')
print(player2)
at_war = True
if player1_card.value == player2_card.value:
while at_war == True:
player1_list = []
player2_list = []
card_list = []
if len(player1.all_cards) < 5:
print('Player 2 won')
game_status = False
at_war = False
break
elif len(player2.all_cards) <5:
print('Player 1 won')
game_status = False
at_war = False
break
if len(player1.all_cards) >= 5 and len(player2.all_cards) >= 5:
for i in range(5):
player1_list.append(player1.remove_one())
player2_list.append(player2.remove_one())
card_list.extend(player1_list)
card_list.extend(player2_list)
print("CARD LIST LEN", len(card_list))
if player1_list[0].value > player2_list[0].value:
player1.add_cards(card_list)
at_war = False
break
elif player1_list[0].value < player2_list[0].value:
player2.add_cards(card_list)
#player2.add_cards(player1_list)
at_war = False
break
else:
at_war = True
elif player1_card.value > player2_card.value:
player1.add_cards(player_cards)
#player1.add_cards(player2_cards)
#print('p1>p2', player1)
elif player2_card.value > player1_card.value:
player2.add_cards(player_cards)
print(player1)
print(player2)
if len(player1.all_cards) == 0:
print('Player 2 won')
elif len(player2.all_cards) == 0:
print('Player 1 won')
Output: When it was stuck in an infinite loop:(You can see the total number of cards is now 34 instead of 52.)

Non-iterable value self.hand is used in an iterating context

I'm working on a Discord bot that can be used to play blackjack (Python). The following code is supposed to calculate the values ​​of the respective hands:
class Player(object):
def __init__(self, id=''):
self.id = id
self.hand = None
self.status_text = ''
self.bet = 0
self.value = 0
self.score = 0
self.wins = 0
self.no_response = 0
self.request_leave = False
self.playing = False
def calculate_value(self):
"""Calculates value of player's hand"""
if not self.hand:
return 0
num_aces = 0
total_value = 0
for card in self.hand:
if pydealer.const.DEFAULT_RANKS['values'][card.value] == 13:
num_aces += 1
total_value += 11
elif pydealer.const.DEFAULT_RANKS['values'][card.value] >= 10:
total_value += 10
else:
total_value += int(card.value)
while num_aces > 0 and total_value > 21:
total_value -= 10
num_aces -= 1
return total_value
Unfortunately I get at
for card in self.hand:
if pydealer.const.DEFAULT_RANKS['values'][card.value] == 13:
num_aces += 1
total_value += 11
the error Non-iterable value self.hand is used in an iterating context is displayed.
I hope someone can help! Greetings and thank you very much.
Your self.hand is initialized to be None.
So do make sure your self.hand gets set to an iterable object before you run stuff with it.

How do I swap which function runs at the beginning of my while loop?

I have just starting learning Python and I am writing a rudimentary Blackjack game. I have got the basic stuff working but I want to add a little bit of finesse here and there. I am looking for a way in which my introduction function at the beginning of my while loop is substituted for my new_round function.
My idea was that I could have a round counter running at the top which would dictate which function would run through and if/elif statement.
Suffice it to say, it doesn't work. Firstly, I would like to know why it doesn't and secondly would like a way to do it!
import random
suits = ('Hearts', 'Diamonds', 'Spades', 'Clubs')
ranks = ('Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight', 'Nine', 'Ten', 'Jack', 'Queen', 'King', 'Ace')
values = {'Two':2, 'Three':3, 'Four':4, 'Five':5, 'Six':6, 'Seven':7, 'Eight':8, 'Nine':9, 'Ten':10, 'Jack':10, 'Queen':10, 'King':10, 'Ace':11}
player_name = ''
playing = True
class Card:
def __init__(self,suit,rank):
self.suit = suit
self.rank = rank
def __str__(self):
return f'{self.rank} of {self.suit}'
class Deck:
def __init__(self):
self.deck = []
for suit in suits:
for rank in ranks:
self.deck.append(Card(suit,rank))
def __str__(self):
deck_comp = ''
for card in self.deck:
deck_comp += '\n '+card.__str__()
return 'The deck has:' + deck_comp
def shuffle(self):
random.shuffle(self.deck)
def deal(self):
single_card = self.deck.pop()
return single_card
class Hand:
def __init__(self):
self.cards = []
self.value = 0
self.aces = 0
def add_card(self,card):
self.cards.append(card)
self.value += values[card.rank]
if card.rank == 'Ace':
self.aces += 1
def adjust_for_ace(self):
#if value of players hand is over 21 and includes an ace then the player will automatically have the ace value reduced to 1
#also track ace counter will revert to 0
while self.value > 21 and self.aces > 0:
self.value -= 10
self.aces -= 1
class Chips:
def __init__(self,total):
self.total = total
self.bet = 0
def win_bet(self):
self.total += self.bet
def lose_bet(self):
self.total -= self.bet
def take_bet(chips):
while True:
try:
player_chips.bet = int(input('How many chips would you like to bet?: '))
except ValueError:
print('\nSorry, the number of chips must be a number!')
else:
if player_chips.bet > player_chips.total:
print(f"\nSorry guy, your bet can't exceed {player_chips.total} chips.")
else:
print(f"\nYour bet of {player_chips.bet} chips has been accepted - good luck!")
break
def introduction():
global player_name
print("\nWelcome to BlackJack! Get as close to 21 as you can without busting.\n\nThe Dealer will hit up to 17, Face cards count as 10 and Aces are 1/11.")
player_name=input("The first round is about to begin, what is your name friend?: ")
def next_round():
global player_name
print("Hey ho, let's go another round!")
def chip_count():
global player_name
print(f"{player_name}, your current chip count stands at {player_chips.total}")
def play_again():
global player_name
global playing
while True:
replay = input(f"{player_name}, would you like to play another round?: ").upper()
if replay[0] == 'Y':
return True
elif replay[0] == 'N':
print(f"\nThanks for playing - you leave the table with {player_chips.total} chips.")
break
else:
print("Sorry, I don't understand what you are saying, do you want to play the next round, or not? Y or N!: ")
continue
def total():
global player_name
while True:
try:
total = int(input(f'Hello {player_name}, how many chips will you be using this game?: '))
except ValueError:
print('\nSorry, the number of chips must be a number!')
else:
return total
print(f"\nWelcome to the table - you currently have {total} chips to play with.")
def hit(deck,hand):
#run the add card function within the Hand Class with the card argument being generated by the deal function within the Deck Class.
hand.add_card(deck.deal())
hand.adjust_for_ace()
def hit_or_stand(deck,hand):
global player_name
global playing
while True:
response = input(f"{player_name}, Would you like to hit or stand?: ")
if response[0].upper() == 'H':
hit(deck,hand)
elif response[0].upper() == 'S':
print(f"{player_name} stands. It is the Dealer's turn")
playing = False
else:
print("\nI can't understand what you are saying - are you hitting or standing?!")
continue
break
def show_some(player,dealer):
print("\nDealer's Hand:")
print("<card hidden>")
print(dealer.cards[1])
print("\nPlayer's Hand: ",*player.cards, sep='\n')
print("Value of your cards: ",player.value)
def show_all(player,dealer):
print("\nDealer's Hand: ",*dealer.cards, sep='\n')
print("Dealer's Hand = ",dealer.value)
print("\nPlayer's Hand: ",*player.cards, sep='\n')
print("Player's Hand = ",player.value)
def player_busts(player,dealer,chips):
global player_name
print(f"{player_name} busts!")
chips.lose_bet()
def player_wins(player,dealer,chips):
global player_name
print(f"{player_name} wins the round!")
chips.win_bet()
def dealer_busts(player,dealer,chips):
print("Dealer busts!")
chips.win_bet()
def dealer_wins(player,dealer,chips):
print("Dealer wins!")
chips.lose_bet()
def push(player,dealer,chips):
print("You have tied with the Dealer! It's a push, your chips have been refunded.")
############################################################################################################################################################
while True:
counter = 0
if counter > 0:
next_round()
elif counter == 0:
introduction()
#Create & shuffle the deck, deal 2 cards to each player.
deck = Deck()
deck.shuffle()
player_hand = Hand()
player_hand.add_card(deck.deal())
player_hand.add_card(deck.deal())
dealer_hand = Hand()
dealer_hand.add_card(deck.deal())
dealer_hand.add_card(deck.deal())
#Set up Player's chips
player_chips = Chips(total())
#Prompt the Player for their bet
take_bet(player_chips)
#Show cards (keep one dealer card hidden)
show_some(player_hand,dealer_hand)
while playing == True:
#Prompt for player hit or stand
hit_or_stand(deck,player_hand)
#show cards (keep one dealer card hidden)
show_some(player_hand,dealer_hand)
#if player's hand exceeds 21, player busts - break loop
if player_hand.value > 21:
player_busts(player_hand,dealer_hand,player_chips)
break
#if player hasn't bust, play dealer's hand until dealer reaches 17 or busts.
if player_hand.value <= 21:
while dealer_hand.value < 17:
hit(deck,dealer_hand)
#show all cards
show_all(player_hand,dealer_hand)
#run different winning scenarios
if dealer_hand.value > 21:
dealer_busts(player_hand,dealer_hand,player_chips)
elif dealer_hand.value > player_hand.value:
dealer_wins(player_hand,dealer_hand,player_chips)
elif dealer_hand.value < player_hand.value:
player_wins(player_hand,dealer_hand,player_chips)
else:
push(player_hand,dealer_hand,player_chips)
#inform player of their current chip count.
chip_count()
counter += 1
#play another round?
if play_again() == True:
continue
else:
break
You are resetting counter to 0 at the start of every loop.
You probably meant to set it to 0 before the loop started, then have it increase every loop.
Instead of:
while True:
counter = 0
if counter > 0:
try:
counter = 0
while True:
if counter > 0:
The issue in your code is that each time you loop through your While True: loop, you are setting the variable counter back to zero.... So even though you increment counter at the end of your loop, it is then immediately set back to zero as the loop restarts.
A different way to accomplish what you are looking for would be to run your introduction() function just before your While True: loop, and then edit the final lines of your code to call the next_round() function, as such:
if play_again() == True:
next_round()
continue

Go Fish in Python 3

Next Python question...
So I have a student who is working on a self playing game of Go Fish game in Python 3 and is having an issue with the card draw. The problem is that the program deals the same card to each player, in order, ie: Player 1 gets 4 of Spades, 2 of Diamonds, 8 of Hearts, etc, Player 2 gets same, Player 3 gets same, etc).
We're not sure how to get it to re-loop through the randomizing portion of the code for each draw, for each player.
Thanks!
First here is the deck module and posted second is the game code.
import random
def MakeDeck():
deck = []
c = 0
values = ["Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King"]
suits = ["Hearts", "Spades", "Diamonds", "Clubs"]
for v in values:
for s in suits:
deck.append([v,s])
random.shuffle(deck)
return deck
Now, the game code...
import deck, random, time
fish_deck = deck.MakeDeck()
#for i in fish_deck:
# print(i[0]+" of "+i[1])
class fisherman():
name = ""
hand = []
sets = []
def ask(player1, player2):
pause = random.randint(2,5)
has = []
choose = randint(0,len(player1.hand)-1)
value = player1.hand[choose][0]
for card in player2.hand:
if card[0] == value:
has.append(card)
for card in has:
player2.hand.remove(card)
for card in has:
player1.hand.append(card)
return_string = player1.name+" asked "+player2.name+" for "+value+"s. "
print(return_string)
return_string = player2.name+" had "+str(len(has))+". "
print(return_string)
if len(has) == 0:
draw(player1)
return_string = player1.name+" had to go fish."
print(return_string)
def draw(player):
card = fish_deck.pop()
player.hand.append(card)
def set_check(player):
amount = {}
for card in player.hand:
if card[0] not in amount.keys():
amount[card[0]] = 1
if card[0] in amount.keys():
amount[card[0]] += 1
for count in amount.keys():
if amount[count] == 4:
print(player.name+" got a set of "+count+"s.")
player.sets.append(count)
player.hand[:] = [card for card in player.hand if card[0] == count]
john = fisherman()
john.name = "John"
tim = fisherman()
tim.name = "Tim"
sara = fisherman()
sara.name = "Sara"
kris = fisherman()
kris.name = "Kris"
def play(player1, player2, player3, player4, deck):
turn = 0
size = 7
dealt = 0
order = [player1, player2, player3, player4]
random.shuffle(order)
while dealt < size:
draw(order[0])
draw(order[1])
draw(order[2])
draw(order[3])
dealt += 1
while len(deck) != 0:
for player in order:
count = 0
hand = player.name+"'s hand: "
for card in player.hand:
if count < len(player.hand)-1:
hand += card[0]+" of "+card[1]+", "
count += 1
elif count == len(player.hand)-1:
hand += card[0]+" of "+card[1]+"."
print(hand)
count = 0
sets = player.name+"'s sets: "
for set in player.sets:
if count < len(player.sets)-1:
sets += set+"s, "
elif count == len(player.sets)-1:
sets += set+"s."
print(sets)
other_player = turn
while other_player == turn:
other_player = random.randint(0,3)
ask(order[turn], order[other_player])
set_check(order[turn])
if turn >= 3:
turn = 0
else:
turn += 1
time.sleep(10)
print("=========================================")
play(john, tim, sara, kris, fish_deck)
class fisherman():
name = ""
hand = []
sets = []
All of your fisherman instances will share identical hand references, because these variables are class variables. If you want them to be individual instance variables, create them inside an __init__ method.
class fisherman():
def __init__(self):
self.name = ""
self.hand = []
self.sets = []

Trouble giving values to deck of cards

(Cards numbered 2-10 should be valued from 2-10, respectively. J,Q, and K should be 10, and A should be either 1 or 11, depending on the value of the hand).
How do I assign the deck these values? Also, the game needs to be 3 rounds. The way I did it is only one round. How do I make the game go three times, while keeping track of the players wins/losses?
Could someone please explain how I can do this a simple way?
here is a complete implementation for you
look at hand.Score
import random
class Card:
def __init__(self,rank,suite):
self.rank = rank
self.suite = suite
def Rank(self):
return "Ace Two Three Four Five Six Seven Eight Nine Ten Jack Queen King".split()[self.rank]
def Suite(self):
return "Hearts Spades Clubs Diamonds".split()[self.suite]
def __str__(self):
#print "Get Self:",type(self)
#print "Dir:",dir(self)
#return "OF"
return self.Rank()+" of "+ self.Suite()
class Hand:
def __init__(self):
self.cards = []
def Score(self):
aces_ct = 0
score = 0
for c in self.cards:
if c.rank == 0:
aces_ct += 1
score += 11
if 0 < c.rank < 9:
score += c.rank+1
else:
score += 10
while score > 21 and aces_ct > 0:
score -= 10
aces_ct -= 1
return score
def add(self,card):
self.cards.append(card)
def Show(self,show_only=None):
if not show_only:
for k in self.cards:
print "%s"%k
else:
if isinstance(show_only,int):
print "%s"%self.cards[show_only]
elif isinstance(show_only,(list,tuple)):
for idx in show_only:
print "%s"%self.cards[idx]
class deck:
def __init__(self):
self.cards = []
for i in range(4):
for j in range(13):
self.cards.append(Card(j,i))
random.shuffle(self.cards)
def shuffle(self):
random.shuffle(self.cards)
def pop(self):
return self.cards.pop()
if __name__ == "__main__":
d = deck()
player_hand = Hand()
dealer_hand = Hand()
player_hand.add(d.pop())
dealer_hand.add(d.pop())
player_hand.add(d.pop())
dealer_hand.add(d.pop())
print "Player Score :",player_hand.Score()
player_hand.Show()
print "\n\nDealer Score :",dealer_hand.Score()
dealer_hand.Show()
You can represent cars as tuples: a character indicating suit, and a number indicating value. I would also add a third value to the tuple, its blackjack value (e.g. a king and a queen both count as a 10).
card = ('D', 11, 10) # card is queen of diamonds
You could also make your own class to represent cards.
class Card(object):
def __init__(self, suit, number):
self.suit = suit
self.number = number
self.value = (number if 2 <= number <= 9 else 10)
You will have to special-case the value of the ace, of course.
You should probably calculate the total dynamically. Also, you need some kind of way to store the money of each individual player. Right now, there is no way of knowing the distribution of money since you only have one total.

Categories