I am currently trying to program a mathematical card trick, which asks the user what pile their random card is in. However, the second time it runs (the 'trick phase' has to occur 3 times for the trick to work) the list index becomes out of range. I am unsure where exactly the problem lies and will attach the current version so you can try to run it to see clearer. Thanks!
import random
def makedeck():
listy = []
cardsindeck = 0
while cardsindeck != 21:
suit = random.randint(1,4)
if suit == 1:
suit = "D"
elif suit == 2:
suit = "H"
elif suit == 3:
suit = "S"
else:
suit = "C"
cardtype = random.randint(1,13)
if cardtype == 1:
card = "A"
elif cardtype == 2:
card = "2"
elif cardtype == 3:
card = "3"
elif cardtype == 4:
card = "4"
elif cardtype == 5:
card = "5"
elif cardtype == 6:
card = "6"
elif cardtype == 7:
card = "7"
elif cardtype == 8:
card = "8"
elif cardtype == 9:
card = "9"
elif cardtype == 10:
card = "10"
elif cardtype == 11:
card = "J"
elif cardtype == 12:
card = "Q"
else:
card = "K"
cardandsuit = (card + suit)
if cardandsuit not in listy:
listy.append(cardandsuit)
cardsindeck = cardsindeck + 1
return listy
def dealdeck(listy):
list1 = []
list2 = []
list3 = []
for i in range(len(listy)):
if i % 3 == 0:
list1.append(listy[i])
elif i % 3 == 1:
list2.append(listy[i])
else:
list3.append(listy[i])
return[list1, list2, list3]
def makepiles(pile1,pile2,pile3):
print("Pile 1\t\tPile 2\t\t Pile 3\t\t")
for i in range(7):
print(pile1[i],"\t\t",pile2[i],"\t\t",pile3[i],"\t\t")
def usercardpile():
userinput = input("What pile is your card in?")
if userinput == "1" or userinput.title() == "One":
return 1
elif userinput == "2" or userinput.title() == "Two":
return 2
elif userinput == "3" or userinput.title() == "Three":
return 3
else:
print("Please only write 1, 2 or 3")
return usercardpile()
listy = makedeck()
pile1, pile2, pile3 = dealdeck(listy)
for i in range(1,4):
newlisty = makepiles(pile1,pile2,pile3)
userspile = usercardpile()
if userspile == 1:
newlisty = (pile2,pile1,pile3)
elif userspile == 2:
newlisty = (pile1,pile2,pile3)
else:
newlisty = (pile1,pile3,pile2)
pile1, pile2, pile3 = dealdeck(newlisty)
print("Your card is",newlisty[10])
One issue is with this line of code:
newlisty = makepiles(pile1, pile2, pile3)
You're expecting makepiles to return 3 lists, whereas it returns None (no explicit item returned).
I imagine if you were to return the piles from that function, it'd work.
The other thing is, You are doing this:
newlisty = (pileX, pileY, pileZ)
This will create a tuple of lists, and you will iterate over the entire lists rather than the individual cards. I believe you want
newlisty = pile1 + pile3 + pile2`
This'll create a composite list of 21 elements by linearly combining the smaller piles.
Other comments:
Consider storing your decktype and card type in dicts. That way, you can quickly lookup and generate your piles without having to write a long set of if statements. Example:
You can reduce
cardtype = random.randint(1,13)
if cardtype == 1:
card = "A"
elif cardtype == 2:
card = "2"
elif cardtype == 3:
card = "3"
elif cardtype == 4:
card = "4"
elif cardtype == 5:
card = "5"
elif cardtype == 6:
card = "6"
elif cardtype == 7:
card = "7"
elif cardtype == 8:
card = "8"
elif cardtype == 9:
card = "9"
elif cardtype == 10:
card = "10"
elif cardtype == 11:
card = "J"
elif cardtype == 12:
card = "Q"
else:
card = "K"
To...
cardtype_lookup = { 1 : 'A', 2 : '2', 3 : '3', .... 12 : 'K' }
card = cardtype_lookup[random.randint(1, 13)]
...And so on.
I think you are hitting a few issues with your code beyond just the final iterations. Below are some suggestions along with comments that I believe accomplishes your purpose.
from random import shuffle
# Function for generating 21 random cards
def makedeck():
# Create 52 cards by suit and cardtype
listy = [card + suit for card in ['A','2','3','4','5','6','7','8','9','10','J','Q','K'] for suit in ['D','H','S','C']]
# Shuffle the list
shuffle(listy)
# Choose only the first 21 items of that list
listy = listy[:21]
return listy
# Function for dividing 21-card deck into 3 equally-sized piles
def dealdeck(listy):
# Iterate over listy, stepping by 3, starting with the first, second, and third item
list1 = listy[::3]
list2 = listy[1::3]
list3 = listy[2::3]
# Return the three lists as three items to correspond to the three piles of the call
return list1, list2, list3
# This works
def makepiles(pile1,pile2,pile3):
print("Pile 1\t\tPile 2\t\t Pile 3\t\t")
for i in range(7):
print(pile1[i],"\t\t",pile2[i],"\t\t",pile3[i],"\t\t")
# This works
def usercardpile():
userinput = input("What pile is your card in?")
if userinput == "1" or userinput.title() == "One":
return 1
elif userinput == "2" or userinput.title() == "Two":
return 2
elif userinput == "3" or userinput.title() == "Three":
return 3
else:
print("Please only write 1, 2 or 3")
return usercardpile()
listy = makedeck()
pile1, pile2, pile3 = dealdeck(listy)
for i in range(1,4):
# Because this function does not return anything, it should be run on its own, and not assigned to a variable
makepiles(pile1,pile2,pile3)
userspile = usercardpile()
# Now you want to re-order the piles based on user input. Because these are lists, you can simply add them together in a new order to create a newly arranged list
if userspile == 1:
newlisty = pile2 + pile1 + pile3
elif userspile == 2:
newlisty = pile1 + pile2 + pile3
else:
newlisty = pile1 + pile3 + pile2
# Now you create new piles based on the re-sorted list and re-iterate
pile1, pile2, pile3 = dealdeck(newlisty)
# Uses .format method instead
print("Your card is {}".format(newlisty[10]))
Related
I am working on a RPi blackjack project. Before I add the Pi into the mix, I want to get the Python code working by itself. The problem is mainly the Ace. I can't figure out a way to get it to switch to a "low ace" if, after hitting, the total goes over 21.
I believe that it might actually be switching, but when added up, the cards still go over. I think it has something to do with my overflow() function.
import random
alt = {"A(l)" : 1}
nums = {
"A" : 11,
"2" : 2,
"3" : 3,
"4" : 4,
"5" : 5,
"6" : 6,
"7" : 7,
"8" : 8,
"9" : 9,
"10": 10,
"J" : 10,
"Q" : 10,
"K" : 10
}
suits = ["D", "H", "S", "C"]
playerCards = []
dealerCards = []
def overflow(cards):
try:
ace = cards.index("A")
except:
ace = -1
if sum([nums[card] for card in cards]) > 21:
if ace != -1:
cards[ace] = "A(l)"
else:
return True
else:
return False
while True:
winner = "none"
playerCards.clear()
dealerCards.clear()
playerCards.append(random.choice(list(nums.keys())))
playerCards.append(random.choice(list(nums.keys())))
dealerCards.append(random.choice(list(nums.keys())))
print("Player:")
print(" ".join(playerCards), ":", sum([nums[card] for card in playerCards]))
print("Dealer:")
print(" ".join(dealerCards))
print()
while True:
if not overflow(playerCards):
hitStand = input("'hit' or 'stand'?: ")
if(hitStand == "hit"):
playerCards.append(random.choice(list(nums.keys())))
print(" ".join(playerCards), ":",
sum([nums[card] for card in playerCards]))
print()
else:
break
else:
winner = "dealer"
print()
print("Dealer wins")
print("-----------")
break
while sum([nums[card] for card in dealerCards]) < 17 and winner == "none":
print()
print("Dealer:")
if not overflow(dealerCards):
dealerCards.append(random.choice(list(nums.keys())))
print(" ".join(dealerCards), ":", sum([nums[card] for card in dealerCards]))
else:
winner = "player"
print()
print("Player wins")
print("-----------")
break
if winner == "none":
if(sum([nums[card] for card in playerCards]) ==
sum([nums[card] for card in dealerCards])):
print()
print("Tie")
print("-----------")
break
elif (sum([nums[card] for card in playerCards]) >
sum([nums[card] for card in dealerCards]) or overflow(dealerCards)):
winner = "player"
print()
print("Player wins")
print("-----------")
continue
else:
winner = "dealer"
print()
print("Dealer wins")
print("-----------")
continue
It doesn't have to be that complicated.
def overflow(cards):
val = sum([nums[card] for card in cards)
if val > 21 and 'A' in cards:
val -= 10
return val > 21
Notice that this condition is traditionally called "bust", not "overflow".
I would probably do two functions:
def score(cards):
val = sum([nums[card] for card in cards)
if val > 21 and 'A' in cards:
val -= 10
return val
def overflow(cards):
return score(cards) > 21
I'm writing a casino-based game and I'm having some trouble with coding blackjack, I run into a problem where you only have the option to "hit" once, and I'm not sure how to make it loop. Once you've "hit" it just settles with your score as if it was final even tho you might still be far under 21. Every time I try to fix it some other part of the code just breaks.
(keep in mind this is not the full code but just the blackjack part)
import os
import random
deck = [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]*4
bal = 100
balstr = str(bal) + "$"
def clear():
os.system('cls')
def deal(deck):
hand = []
for i in range(2):
random.shuffle(deck)
card = deck.pop()
if card == 11:card = "J"
if card == 12:card = "Q"
if card == 13:card = "K"
if card == 14:card = "A"
hand.append(card)
return hand
def newRound():
again = input("Do you want to play again? (Y/N): ").lower()
if again == "y":
blackjack()
else:
#takes you back to main menu in the full code, just ignore this
position()
def total(hand):
total = 0
for card in hand:
if card == "J" or card == "Q" or card == "K":
total+= 10
elif card == "A":
if total >= 11:
total+= 1
else: total+= 11
else:
total += card
return total
def hit(hand):
card = deck.pop()
if card == 11:
card = "J"
if card == 12:
card = "Q"
if card == 13:
card = "K"
if card == 14:
card = "A"
hand.append(card)
return hand
def currentHands(dealerHand, playerHand):
clear()
print(("The dealer has a ") + str(dealerHand) + " for a total of " + str(total(dealerHand)))
print(("You have a ") + str(playerHand) + " for a total of " + str(total(playerHand)))
def score(dealerHand, playerHand, usrbetint):
global bal
if total(playerHand) == 21 or total(dealerHand) > 21 or total(playerHand) > total(dealerHand) and total(playerHand) < 21:
currentHands(dealerHand, playerHand)
bal += usrbetint
print("Congratulations, you win!\n \nYour new balance is {}$".format(bal))
else :
currentHands(dealerHand, playerHand)
bal -= usrbetint
print("Sorry, you lose.\n \nYour new balance is {}$".format(bal))
def blackjack():
choice = 0
clear()
print("Let's play blackjack!\n")
userbet = input("(for help type help) How much money do you want to use: ").upper()
if userbet == "HELP" :
if userbet == "HELP" :
print("Instructions")
else :
print("Something went wrong")
pass
else :
usrbetint = int(userbet)
dealerHand = deal(deck)
dealerHandShow = [dealerHand[0]]
dealerHandShow = total(dealerHandShow)
playerHand = deal(deck)
print(("The dealer is showing a ") + str(dealerHand[0]) + " for a total of " + str(dealerHandShow))
print(("You have a ") + str(playerHand) + " for a total of " + str(total(playerHand)))
choice = input("Do you want to [H]it or [S]tand?: ").lower()
clear()
if choice == "h":
hit(playerHand)
while total(dealerHand) < 17:
hit(dealerHand)
score(dealerHand, playerHand, usrbetint)
newRound()
elif choice == "s":
while total(dealerHand) < 17:
hit(dealerHand)
score(dealerHand, playerHand, usrbetint)
newRound()
blackjack()
i assume the fix would be somewhere around the last 20 lines of the "blackjack" function but didnt know how to explain everything without sending the clump of code.
If someone please could give me tips on where to change stuff i'd really appreciate that and ignore the "global bal" part, it was the only way i knew to add a truly global variable.
Since you don't know how many times you'll be looping (it is based on user input), you probably want a while loop. Your current code mixes the dealer behavior into the player handling, you you'll need to separate that out, since we don't want to loop it.
print("You have a " + str(playerHand) + " for a total of " + str(total(playerHand)))
choice = input("Do you want to [H]it or [S]tand?: ").lower()
while choice == "h":
clear()
hit(playerHand)
print("You have a " + str(playerHand) + " for a total of " + str(total(playerHand)))
choice = input("Do you want to [H]it or [S]tand?: ").lower()
while total(dealerHand) < 17:
hit(dealerHand)
score(dealerHand, playerHand, usrbetint)
You might want to add an additional condition to stop asking the player if they want to hit when they've already busted.
I've recently gotten into coding, so I don't know a lot, which is why I am coming here for help. I am currently coding a game using python (Not a complicated game based off of what I am thinking of making) it's basically just a card game one of my friends made up. My only problem so far is one of my variables are returning wrong, and right at the same time?
This is the code that's being wonky:
Card = "Nothing"
def Draw_Card():
Rank = random.randint(1, 13)
print(Rank)
Card = str(Rank)
print(Card)
if Rank == 11:
Card = "J"
elif Rank == 12:
Card = "Q"
elif Rank == 13:
Card = "K"
Suit = random.randint(1, 4)
if Suit == 1:
Card = Card + "D"
elif Suit == 2:
Card = Card + "C"
elif Suit == 3:
Card = Card + "H"
elif Suit == 4:
Card = Card + "S"
Top()
Help()
Top()
print("And the game begins!")
time.sleep(2)
Top()
Card = "Nothing"
Draw_Card()
print(Card)
ignore the Top() functions and other functions, all that matters is the Draw_Card() and the print(Card) Running through this code will return
7,
7,
Nothing
assuming that 7 is the random value generated. Card is being printed right, when in the Draw_Card() function, but not when its outside the function. I dont understand why this is happening, and would apreciate some help
also another thing is the Card = "Nothing" doesnt work inside the function, it returns as Card is undefines, but thats besides the point
Inside Draw_Card, the name Card refers to a local variable. How about returning it?
At the end of the function, add
return Card
And outside the function, do:
Card = Draw_Card()
Another option would be to declare the name to be from the global scope:
def Draw_Card():
global Card
Rank = random.randint(1, 13)
print(Rank)
...
But I would generally avoid global and nonlocal if at all possible.
Assuming you want to print the suit and the card when you call the Draw_Card function (i.e. 7D), then you can move the print(card) to the bottom of the Draw_Card function.
Also in order to change the Card variable outside the function, you'd need to place global Card at the top of the function.
import random
Card = "Nothing"
def Draw_Card():
global Card
Rank = random.randint(1, 13)
Card = str(Rank)
if Rank == 11:
Card = "J"
elif Rank == 12:
Card = "Q"
elif Rank == 13:
Card = "K"
Suit = random.randint(1, 4)
if Suit == 1:
Card = Card + "D"
elif Suit == 2:
Card = Card + "C"
elif Suit == 3:
Card = Card + "H"
elif Suit == 4:
Card = Card + "S"
print(Card)
print("And the game begins!")
Card = "Nothing"
Draw_Card()
print(Card)
Your function just needs to return, you should focus on using return and then print the values returned
def Draw_Card():
Rank = random.randint(1, 13)
Card = str(Rank)
if Rank == 11:
Card = "J"
elif Rank == 12:
Card = "Q"
elif Rank == 13:
Card = "K"
Suit = random.randint(1, 4)
if Suit == 1:
Card = Card + "D"
elif Suit == 2:
Card = Card + "C"
elif Suit == 3:
Card = Card + "H"
elif Suit == 4:
Card = Card + "S"
return Card
print("And the game begins!")
Card = "Nothing"
Card = Draw_Card()
print(Card
And the game begins!
QS
I've been trying to create a program that deals 21 cards into 3 piles. The user is then asked to think of a card and tell the program in which pile is their card. this step is repeated 4 more times until the card is found exactly in the middle of the 21 cards. The program the is supposed to go to the end() function where it prints the users card, the problem is, everything works fine but it prints the statement in the end() function 5 times. I know it is probably something really stupid but I can't think of a solution. Thanks in advance.
import random
cards = []
count = 0
def end():
print("Your card is: ", cards[10])
def split():
def choice():
global count
while True:
if count >=0 and count <= 3:
global cards
user = input("Think of a card. Now to which pile does your card belong to?: ")
count = count + 1
if user == "1":
del cards[:]
cards = (pile_2 + pile_1 + pile_3)
print(cards)
split()
elif user == "2":
del cards[:]
cards = (pile_1 + pile_2 + pile_3)
print(cards)
split()
elif user == "3":
del cards[:]
cards = (pile_1 + pile_3 + pile_2)
print(cards)
split()
else:
print("Invalid input")
main()
elif count == 4:
end()
break
pile_1 = []
pile_2 = []
pile_3 = []
counter = 0
sub_counter = 0
while True:
if sub_counter >= 0 and sub_counter <= 20:
for item in cards:
if counter == 0:
pile_1.append(item)
counter = counter + 1
elif counter == 1:
pile_2.append(item)
counter = counter + 1
elif counter == 2:
pile_3.append(item)
counter = 0
sub_counter = sub_counter + 1
elif sub_counter == 21:
False
break
print()
print("first pile: ", pile_1)
print("second pile: ", pile_2)
print("third pile: ", pile_3)
choice()
def main():
file = open('cards.txt.', 'r')
for line in file:
cards.append(line)
file.close
random.shuffle(cards)
print(cards)
split()
main()
You've got recursive calls. split() calls choice() which then calls split() again, which can calls main() which again calls split().
By the time you get to the elif count == 4 line, count will always be 4. That's why. I got a hunch it could work if you changed the order:
...
if count == 4:
end()
break
elif count >= 0 and count <=3:
...
However, it would be even nicer if you could write it without global variables. Instead of global variables you have local ones that are passed over to the next function as arguments. Like this:
import random
def end(cards):
print("Your card is: ", cards[10])
def choice(count,pile_1,pile_2,pile_3):
while True:
user = input("Think of a card. Now to which pile does your card belong to?: ")
if user == "1":
cards = (pile_2 + pile_1 + pile_3)
print(cards)
split(count+1, cards)
break
elif user == "2":
cards = (pile_1 + pile_2 + pile_3)
print(cards)
split(count+1, cards)
break
elif user == "3":
cards = (pile_1 + pile_3 + pile_2)
print(cards)
split(count+1, cards)
break
else:
print("Invalid input")
def split(count,cards):
if count == 4:
end(cards)
return
pile_1 = []
pile_2 = []
pile_3 = []
for i in range(0,21,3):
pile_1.append(cards[i])
pile_2.append(cards[i+1])
pile_3.append(cards[i+2])
print()
print("first pile: ", pile_1)
print("second pile: ", pile_2)
print("third pile: ", pile_3)
choice(count,pile_1,pile_2,pile_3)
def main():
cards = []
file = open('cards.txt.', 'r')
for line in file:
cards.append(line.strip())
file.close
random.shuffle(cards)
print(cards)
split(0, cards)
main()
I have found a solution:
It was just a matter of an ident,
instead of:
elif count == 4:
end()
break
I put the break statement on the same line as elif:
elif count == 4:
end()
break
which seems to solve it
I was given a task to write a program in a pretty basic python style. The program is supposed to ask the user whether they want to 1. Flip a coin, or 2. Pick a card.
Then uses an IF to check what the user picked. If it was one, it's supposed to randomly generate heads or tails and print what it got.
If the choice was 2, it asks the user to choose a suit, then generates a number between 1 and 13 (ace to king) and prints 'You picked [value] of [suit]'
import random
print('1. Flip a coin')
print('2. Pick a card')
choice = int(input('Enter a coice :'))
if choice == 1:
Hort = ''
HorT == random.randint(0,1)
if HorT == "0":
print('You got Heads')
elif HorT == "1":
print('You got Tails')
elif choice == 2:
print()
print('1. Hearts')
print('2. Clubs')
print('3. Diamonds')
print('4. Spades')
print()
suitno = ''
suitno ==int(input('Choose a suit'))
if suitno == "1":
suit == "Hearts"
elif suitno == '2':
suit == 'Clubs'
elif suitno == '3':
suit == 'Diamonds'
elif suitno == '4':
suit == 'Spades'
value = ''
value == random.randint(1,13)
print()
print('You picked', value, 'of', suit)
as you can see, it's basic but I was asked to follow the pseudo-code as closely as I could. It stops right at the beginning. I enter then number for the choice, and it just ends.
EDIT: I have amended the code to show what I have changed.
You have 2 problems:
choice = int(input('Enter a coice :'))
if choice == '1':
Here you are comparing integer choice and string '1' values.
And the second problem that you have a lot of constructions that looks like:
if a == '1':
some_statement
elif a == '2:
some statement
...
Such switch can be formed in python with dictionaries:
import random
coin_sides = {
'1': 'Heads',
'2': 'Tails'
}
card_suits = {
'1': 'Hearts',
'2': 'Clubs',
'3': 'Diamonds',
'4': 'Spades'
}
print('1. Flip a coin')
print('2. Pick a card')
choice = input('Enter a coice :')
if choice == '1':
side = random.randint(0,1)
print 'You got {0}'.format(coin_sides.get(side))
elif choice == '2':
print()
print('1. Hearts')
print('2. Clubs')
print('3. Diamonds')
print('4. Spades')
print()
suitno = input('Choose a suit')
suit = card_suits.get(suitno)
value = random.randint(1,13)
print()
print('You picked', value, 'of', suit)
Since other answers quite adequately critique your card-picking design, I'll only post the bit I had about your coin flip.
Flip a Coin
The outcome of this program is a statment:
You got {heads|tails}.
Thus, we are only interested in the strings 'heads' or 'tails'. Since explicit is better than implicit:
outcomes = ('heads', 'tails')
print('You got {}.'.format(random.choice(outcomes)))
is all you need.
Common mistakes:
== used for comparison and not for assignment e.g 4 == 4 is True
variable of int type will never be equal to string e.g 4 == '4' is False. This is the reason why your if statements didn't execute.
There's no need in variable initialization before getting input().
It usually better to have else if you have elif.
Dirty, but complete fix:
import random
print('1. Flip a coin')
print('2. Pick a card')
choice = int(input('Enter a coice: '))
if choice == 1:
HorT = random.randint(0,1)
if HorT == 0:
print('You got Heads')
else:
print('You got Tails')
elif choice == 2:
print()
print('1. Hearts')
print('2. Clubs')
print('3. Diamonds')
print('4. Spades')
print()
suitno = int(input('Choose a suit: '))
if suitno == 1:
suit = "Hearts"
elif suitno == 2:
suit = 'Clubs'
elif suitno == 3:
suit = 'Diamonds'
else:
suit = 'Spades'
value = random.randint(1, 13)
print()
print('You picked', value, 'of', suit)
It could be written more concisely, but it is pretty basic python style program :)
#Two-Bit Alchemist - #vaultah version:
import random
print('1. Flip a coin')
print('2. Pick a card')
choice = int(input('Enter a choice: '))
if choice == 1:
outcomes = ('heads', 'tails')
print('You got {}.'.format(random.choice(outcomes)))
else:
suits = ('Hearts', 'Clubs', 'Diamonds', 'Spades')
print()
for index, element in enumerate(suits, start=1):
print('{}. {}'.format(index, element))
suitno = int(input('Choose a suit: '))
value = random.randint(1, 13)
print('\nYou picked', value, 'of', suits[suitno-1])
Here's another restructured version:
from random import choice
COINS = ["Heads", "Tails"]
FACES = ["Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King"]
SUITS = ["Hearts", "Clubs", "Diamonds", "Spades"]
def get_int(prompt, lo=None, hi=None):
while True:
try:
value = int(input(prompt))
if (lo is None or lo <= value) and (hi is None or value <= hi):
return value
except ValueError:
pass
def do_menu(prompt, options):
print("")
for i,option in enumerate(options, 1):
print("{:>3}. {}".format(i, option))
return get_int(prompt, 1, len(options)) - 1
def main():
while True:
option = do_menu("> ", ["Flip a coin", "Pick a card", "Quit"])
if option == 0:
print("\nYou flipped {}.".format(choice(COINS)))
elif option == 1:
suit = SUITS[do_menu("Pick a suit: ", SUITS)]
print("\nYou picked {} of {}".format(choice(FACES), suit))
else:
print("\nGoodbye!")
break
if __name__=="__main__":
main()