High low card game class comparisons - python

I'm relatively knew to Python, but I decided to create a high low card game using classes. Ive got the classes all setup and everything, but the only issue I'm having is when I try to see if the card from the playerHand is bigger or smaller than the one from nextCard. playerHand and nextCard are both tied to classes, and the error that I am getting is: TypeError: '>' not supported between instances of 'Person' and 'NextCard'.
There 100% is a better way to do this, but this is what I've got so far:
import random
class Card(object):
def __init__(self, suit, value):
self.suit = suit
self.value = value
def show(self):
print ("{} of {}".format(self.value, self.suit))
class Deck(object):
def __init__(self):
self.cards = []
self.build()
def build(self):
for suit in ["Spades", "Clubs", "Diamonds", "Hearts"]:
for value in ["Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King"]:
self.cards.append(Card(suit, value))
def show(self):
for card in self.cards:
card.show()
def shuffle(self):
for n in range(len(self.cards)-1,0,-1):
r = random.randint(0, n)
self.cards[n], self.cards[r] = self.cards[r], self.cards[n]
def drawCard(self):
return self.cards.pop()
class Person(object):
def __init__(self):
self.hand = []
def draw(self, deck):
self.hand.append(deck.drawCard())
return self
def show(self):
for card in self.hand:
card.show()
class NextCard(object):
def __init__(self):
self.nextcard = []
def draw(self, deck):
self.nextcard.append(deck.drawCard())
return self
def show(self):
for card1 in self.nextcard:
card1.show()
deck = Deck()
deck.shuffle()
human = Person()
playerHand = human.draw(deck)
newcard = NextCard()
nextCard = newcard.draw(deck)
play = input("Do you want to play High/Low? Y or N? ")
while play.lower()== "y":
card = playerHand
print("The current card is: ", str(card.show()))
guess = input("Guess H for high or L for low." )
if guess.lower()=="h":
if card > nextCard:
print("Congratulations! You guessed correctly! The next card was ", card)
play = input("Play again? Y or N? ")
if card < nextCard:
print("You lost! The next card was ", nextCard)
play = input("Play again? Y or N? ")
if guess.lower()=="l":
if card > nextCard:
print("You lost! The next card was ", nextCard)
play = input("Play again? Y or N? ")
if card < nextCard:
print("Congratulations! You guessed correctly! The next card was ", nextCard)
else:
print("The game is over.")
Any solutions or workarounds to the compare between classes problem would be much appreciated. This was coded in python 3.

Are these playerHand and nextCard classes ?
To compare two classes with < operator you need to do operator overloading.
But that is advance level python
In here the fault is maybe that you are not creating object of classes
you are only aliasing the class playerHand
to make a object of it do
card = playerHand()
But it won't fix the problem (probably)
please give me a inner look of the class (edit your question in brief)

Now consider how the big boys do it
add a < and > operator over-loader in your classes that you are trying to compare
for < add a __lt__() method in your class
for > add a __gt__() method in your class
those __lt__() and __gt__() will do the overloading of operator
** (overloading means programming operators for custom use) **
In your code you need to add them in class Card and class Person
class Card(object):
def __init__(self, suit, value):
self.suit = suit
self.value = value
def __gt__(self, comparing_card):
# result is gonna be a boolean value
# the ace jack qween king will need some comparing basis
# work on it
result = self.value > comparing_card.value
return result
def __lt__(self, comparing_card):
result = self.value < comparing_card.value
return result
def show(self):
print ("{} of {}".format(self.value, self.suit))
and another class
class Person(object):
def __init__(self):
self.hand = []
def __gt__(self, comparing_obj):
# result is gonna be a boolean value
result = self.hand[-1] > comparing_obj.nextcard[-1]
return result
def __lt__(self, comparing_obj):
# result is gonna be a boolean value
result = self.hand[-1] < comparing_obj.nextcard[-1]
return result
def draw(self, deck):
self.hand.append(deck.drawCard())
return self
def show(self):
for card in self.hand:
card.show()
And this is the last fragment where you compare your class
# here we need oparator overloading
# this initially means '> sign' will call card.__gt__(nextCard)
# > sign will call card's ___gt__ method and pass nextCard as a parameter
# ___gt__(nextCard) returns a boolean value that we feed to the if statement down there
if card > nextCard:
# in here the print shows the class node
print("Congratulations! You guessed correctly! The next card was ", card)
# change card to card.show()
play = input("Play again? Y or N? ")
well this is a very deep topic (if its hard to comprehend) and intermediate python stuff. you can try some online stuff to know about it briefly.
try this geeks for geeks tutorial:
https://www.geeksforgeeks.org/operator-overloading-in-python/

Related

Comparing a string to a user input - Class issue?

Okay so i'm having issues with comparing a user inputted value with that already printed into the command line.
The printing to the command line is controlled by the classes that are called and i believe that it's causing issues with the process!
fairly sure i need to use def but i'm new to all of this so i don't know where to start!
Thanks for any help ahead of time! Not sure if this is the best way to go about creating a card game as it's pretty convoluted let me know your thoughts!
Originally tried to convert the hand of cards (bob.showHand) into a string but because it's being generated by a class it doesnt work? It's not much code so i've dumped it all below hope that's fine!
print('Running')
import random
class Turn:
def __init__(self, start):
self.start = start
class Card:
def __init__(self, suit, val):
self.suit = suit
self.value = val
def show(self):
print('{} of {}'.format(self.value, self.suit))
class Deck:
def __init__(self):
self.cards = []
self.build()
def build(self):
for s in ['Spades', 'Clubs', 'Diamonds', 'Hearts']:
for v in range(1,14):
self.cards.append(Card(s, v))
def show(self):
for c in self.cards:
c.show()
def shuffle(self):
for i in range(len(self.cards) - 1, 0, -1):
r = random.randint(0, i)
self.cards[i], self.cards[r] = self.cards[r], self.cards[i]
def drawCard(self):
return self.cards.pop()
def draw(self, deck):
self.hand.append(deck,drawCard())
return self
class Player1:
def __init__(self, name):
self.name = name
self.hand = []
def draw(self, deck):
self.hand.append(deck.drawCard())
return self
def showHand(self):
for card in self.hand:
card.show()
class Player2:
def __init__(self, name):
self.name = name
self.hand = []
def draw(self, deck):
self.hand.append(deck.drawCard())
return self
def showHand(self):
for card in self.hand:
card.show()
print('generating deck')
deck = Deck()
print('shuffling deck')
deck.shuffle()
bob = Player1('bob')
ryan = Player2('ryan')
print('dealing deck')
for x in range(7):
bob.draw(deck)
for y in range(7):
ryan.draw(deck)
Turn.start = 0
if Turn.start == 0:
print('bob to act')
print("bob's hand below")
print(bob.showHand())
cardplay = input('Type the card to play it')
if cardplay == bob.showHand():
print('playing card!')
I'd expect the print of playing card to appear. However no matter how much i try i can't seem to get it too work!
Your showHand method does not create a string; it causes print to be used to display text in the terminal. input reads a string from the user, and stores it. The == comparison will never compare equal, because on one side you have a string, and on the other side you have the special value None.
You should not have the methods of any of your classes do any print calls. Instead, have them return the appropriate strings, which are then printed from outside.
Also, by using a special name for these methods - __str__ - we can make Python use it automatically when printing a class instance, or when converting to string using str. Consider the example:
class Card:
def __init__(self, suit, val):
self.suit = suit
self.value = val
def __str__(self):
return f'{self.value} of {self.suit}'
class Hand:
def __init__(self, cards):
self.cards = cards
def __str__(self):
return ' | '.join(str(card) for card in self.cards)
my_hand = Hand([Card('Spades', 'Ace'), Card('Diamonds', 'King')]) # blackjack!
print(my_hand) # we see: `Ace of Spades | King of Diamonds`
Your problem is that if cardplay == bob.showHand(): does not actually do what you think. showHand() returns None and that will never equal any input Card. You need to convert what the user inputs to a card and then compare that card to the cards the Player is currently holding.
To solve these issues and make your code do what you are trying to do, change your Card Class to the following:
class Card:
def __init__(self, suit, val):
self.suit = suit
self.value = val
def show(self):
print('{} of {}'.format(self.value, self.suit))
def __eq__(self, other):
if (other.suit == self.suit and other.value == self.value):
return True
else:
return False
and the last couple of lines to this:
Turn.start = 0
if Turn.start == 0:
print('bob to act')
print("bob's hand below")
bob.showHand()
cardplay = input('Type the card to play it')
picked = Card(cardplay.split()[2], int(cardplay.split()[0]))
for card in bob.hand:
if picked == card:
print('playing card!')
Then, you can enter any Card, exactly as it appears, on the input line and it will print
'playing card!'

class inheritance exercise using Old Maid card game as example

I am currently learning about class inheritance in python. In the example below, the goal is to remove card pairs(any 2 cards with the same value and color, e.g 3 of hearts and 3 of diamonds) in a single hand containing 13 distinct, random cards.
It seems the error is at line 127: if match in self.cards: . This statement always returns true even if match is not in self.cards . The error is ValueError: list.remove(x): x not in list. Anyone has any idea how to achieve the intended goal? Thanks.
p.s learning through: How to Think Like a Computer Scientist.
class Card:
"""represents a card found in a standard deck with 52 cards."""
suits = ["Clubs", "Diamonds", "Hearts", "Spades"]
ranks = ["narf", "Ace", "2", "3", "4", "5", "6", "7",
"8", "9", "10", "Jack", "Queen", "King"]
def __init__(self, suit=0, rank=0):
self.suit = suit
self.rank = rank
def __str__(self):
return (self.ranks[self.rank] + ' of ' + self.suits[self.suit])
def cmp(self, other):
if self.suit > other.suit:
return 1
if self.suit < other.suit:
return -1
if self.rank < other.rank:
return 1
if self.rank < other.rank:
return -1
return 0
def __eq__(self, other):
return self.cmp(other) == 0
def __le__(self, other):
return self.cmp(other) <= 0
def __lt__(self, other):
return self.cmp(other) < 0
def __ge__(self, other):
return self.cmp(other) >= 0
def __gt__(self, other):
return self.cmp(other) > 0
def __ne__(self, other):
return self.cmp(other) != 0
class Deck:
"""Contains a list of cards as attribute and generates the 52 cards"""
def __init__(self):
self.cards = []
for suit in range(4):
for rank in range(1, 14):
self.cards.append(Card(suit, rank))
def __str__(self):
s = ""
for i in range(len(self.cards)):
s = s + " " * i + str(self.cards[i]) + "\n"
return s
def print_deck(self):
for card in self.cards:
print(card)
def shuffle(self):
"""shuffles the deck of cards randomly."""
import random
rng = random.Random()
rng.shuffle(self.cards)
def remove(self, card):
"""Removes a single specified card from the deck."""
if card in self.cards:
self.cards.remove(card)
return True
else:
return False
def pop(self):
"""Select a single card from the deck"""
return self.cards.pop()
def is_empty(self):
if self.cards == []:
return True
return False
def deal(self, hands, num_cards=52):
"""Deals cards from the deck to a list of hands.
If number of card to deal is not specified, the entire deck is dealt."""
for i in range(num_cards):
if self.cards == []:
break
card = self.pop()
hand = hands[i % len(hands)]
hand.add(card)
class Hand(Deck):
def __init__(self, name=''):
Deck.__init__(self)
self.cards = []
self.name = name
def __str__(self):
string = "The Hand " + self.name
if self.is_empty():
string += 'is empty.\n'
else:
string += ' contains:\n'
return string + Deck.__str__(self)
def add(self, card):
self.cards.append(card)
class CardGame:
def __init__(self):
self.deck = Deck()
self.deck.shuffle()
class OldMaidHand(Hand):
"""Creates a hand for a single player to play a game of Old Maid."""
def remove_matches(self):
cards = self.cards[:]
for card in cards:
match = Card(3 - card.suit, card.rank)
if match in self.cards:
self.cards.remove(card)
self.cards.remove(match)
print('Hand {0} removed {1} and {2}.'
.format(self.name, card, match))
game = CardGame()
player1 = OldMaidHand('test')
game.deck.deal([player1], 13)
player1.print_deck()
player1.remove_matches()

BlackJack - class solution incorrect?

Im working through a blackjack game as an assignment for a python course I purchased on udemy and I believe I've found an issue with the class's provided solution. I made a change to the code myself to make it work, but I'd like to ask the stackoverflow community 2 questions: 1) Will someone please explain exactly why the solution doesn't work? I will make a few guesses below but as a beginner I'd like to understand exactly whats wrong for my own benefit. 2) Is the way I fixed the problem a good solution? If not, what are some other ways I could code this?
This is the given solution (I'm only showing the 3 classes of: Card, Hand and Deck - problem is within Deck, specifically Deck's str function)
# Let's start with defining our suits, ranks and values
suits = ('H','D','C','S')
ranking = ('A','2','3','4','5','6','7','8','9','10','J','Q','K')
card_val = {'A':1,'2':2,'3':3,'4':4,'5':5,'6':6,'7':7,'8':8,'9':9,'10':10,'J':10,'Q':10,'K':10}
class Card(object):
# card needs a suit and rank
def __init__(self, suit, rank):
self.suit = suit
self.rank = rank
def __str__(self):
return self.suit + self.rank
def get_suit(self):
return self.suit
def get_rank(self):
return self.rank
def draw(self):
print (self.suit + self.rank)
class Hand(object):
# A hand needs 2 cards and a total value
def __init__(self):
self.hand = []
self.value = 0
self.ace = False
def __str__(self):
hand_comp = ''
for card in self.hand:
card_name = card.__str__
hand_comp += " " + card_name
return 'The hand has %s' %hand_comp
def card_add(self, card):
self.hand.append(card)
# Check for Aces
if card.rank == 'A':
self.ace = True
self.value += card_val[card.rank]
def calc_val(self):
# calculate the value of the hand, make aces an 11 if they don't bust
if(self.ace == True and self.value < 12):
return self.value + 10
else:
return self.value
def draw(self, hidden):
if hidden == True and playing == True:
#Don't show first hidden card
starting_card = 1
else:
starting_card = 0
for x in range(starting_card, len(self.hand)):
self.hand[x].draw()
class Deck(object):
def __init__(self):
self.deck = []
for s in suits:
for r in ranking:
self.deck.append(Card(s,r))
def shuffle(self):
random.shuffle(self.deck)
def deal(self):
single_card = self.deck.pop()
return single_card
def __str__(self):
deck_comp = ''
for card in self.hand:
deck_comp += " " + deck_comp.__str__()
return "The deck has " + deck_comp
My problem is with the def str function under class Deck. The solution asks the program to run a for loop over... self.hand (which is under class Hand). I don't see why this would work at all. self.hand doesn't have anything to do with getting a full deck returned to me. Secondly, is deck_comp += " " + deck_comp.str() good code? I find my program freezes up if I only changed the loop to self.deck. I created a new variable called cards_name and assign it to cards.str() to get each card's suit and rank instead.
this is what I corrected the code to:
def __str__(self):
deck_comp = ''
for card in self.deck:
cards_name = card.__str__()
deck_comp += " " + cards_name
return "The deck has " + deck_comp

Python Game "House of Cards" help needed

I am currently a python newbie and am using python to create some games. I have written a game "House of Cards", and basically I am trying to use what I learn in OOP to do it. The rules are very simple -- you need the largest card to win. Players would compare the numbers first, then the suit of the card -- the person with the largest card wins. I have written the following code:
import itertools
import random
class Card (object):
def __init__ (self):
self.suit = ["Cubs", "Diamonds", "Hearts", "Spades"]
self.value = ["2","3","4","5","6","7","8","9","10", "J", "Q", "K", "A"]
self.deck = []
for card in itertools.product(self.value, self.suit):
self.deck.append(card)
class Player(object):
def __init__ (self, name, card = None):
self.name = name
self.carddeck = Card()
self.card_available = self.carddeck.deck
def draw_a_card(self):
self.card = random.choice(self.card_available)
print "%s has gotten a %s" %(self.name, self.card)
def __cmp__(self, other):
if self.card_available.index(self.card) > self.card_available.index(other.card):
print "%s wins!" %(self.name)
elif self.card_available.index(self.card) < self.card_available.index(other.card):
print "%s wins!" %(other.name)
player_1= Player("Player 1")
player_2 = Player("Player 2")
player_3 = Player("Player 3")
player_1.draw_a_card()
player_2.draw_a_card()
player_3.draw_a_card()
cards_deck = Card()
player_1.__cmp__(player_2)
After a lot of effort, I have successfully compared the cards between players 1 and 2, but I don't know how to include player 3 into the comparison.
the cmp function is to override comparisons so you can do things like
if player1 > player2: print "Player1 beat player2!"
not so you can print some message inside the function ... by not returning anything you are essentially saying they are equal(I think in python not returning anything from cmp is roughly equivelent to returning 0), or even worse perhaps raising an error if you try a normal comparison...
class Player(object):
def __init__ (self, name, card = None):
self.name = name
self.carddeck = Card()
self.card_available = self.carddeck.deck
def draw_a_card(self):
self.card = random.choice(self.card_available)
print "%s has gotten a %s" %(self.name, self.card)
def __cmp__(self, other):
if self.card_available.index(self.card) > self.card_available.index(other.card):
return 1
elif self.card_available.index(self.card) < self.card_available.index(other.card):
return -1
return 0
print max([player1,player2,player3]), "Wins!"
print min([player1,player2,player3]), "Loses!!!"
is the easiest way to do it ...
really you are missing several aspects of OOP design here
class Card:
def __init__(self,val,suite):
self.val = val
self.suite = suite
def __int__(self):
return self.val
def __str__(self):
card_name = ["2","3","4","5","6","7","8","9","10", "J", "Q", "K", "A"][self.val]
suite_name = ["Clubs","Spades","Diamonds","Hearts"][self.suite]
return card_name + " of " + suite_name
def __cmp__(self,other):
return cmp(int(self),int(other))
print Card(1,3)
print Card(4,2) < Card(3,2)
notice that card has nothing to do with a deck ... it belongs in a deck
deck = [Card(i,j) for i in range(13) for j in range(4)]
random.shuffle(deck.shuffle)
As Joran said .__cmp__() is an operator overloading function so you could just call player1 > player2 rather than player_1.__cmp__(player_2) you could also store the players in a list and sort the list after every turn. you would still be able to reference players in the normal way. For example:
player_1= Player("Player 1")
player_2 = Player("Player 2")
player_3 = Player("Player 3")
exampleList = [player1,player2,player3]
player_1.draw_a_card()
player_2.draw_a_card()
player_3.draw_a_card()
exampleList.sort()
winner = exampleList[0]
For more info on list sorting: https://wiki.python.org/moin/HowTo/Sorting

Classes: I don't really understand them [closed]

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 9 years ago.
I am currently working through the book "How to think like a computer scientist"
Now I got this piece of code that I did out of the book
class Card:
suitList = ["Clubs", "Diamonds", "Hearts", "Spades"]
rankList = ["narf", "Ace", "2", "3", "4", "5", "6", "7",
"8", "9", "10", "Jack", "Queen", "King"]
def __init__(self, suit=0, rank=0):
self.suit = suit
self.rank = rank
def __str__(self):
return (self.rankList[self.rank] + " of " + self.suitList[self.suit])
def __cmp__(self, other):
#check the suits
if self.suit > other.suit: return 1
if self.suit < other.suit: return -1
#suits are the same... check ranks
if self.rank > other.rank: return 1
if self.rank < other.rank: return -1
#ranks are the same... it's a tie
return 0
class Deck:
def __init__(self):
self.cards = []
for suit in range(4):
for rank in range(1, 14):
self.cards.append(Card(suit, rank))
def printDeck(self):
for card in self.cards:
print card
def __str__(self):
s = ""
for i in range(len(self.cards)):
s = s + " "*i +str(self.cards[i]) + "\n"
return s
def shuffle(self):
import random
nCards = len(self.cards)
for i in range(nCards):
j = random.randrange(i, nCards)
self.cards[i], self.cards[j] = self.cards[j], self.cards[i]
def removeCard(self, card):
if card in self.cards:
self.cards.remove(card)
return 1
else:
return 0
def popCard(self):
return self.cards.pop()
def isEmpty(self):
return (len(self.cards) == 0)
def deal(self, hands, nCards=999):
nHands = len(hands)
for i in range(nCards):
if self.isEmpty(): break
card = self.popCard()
hand = hands[i % nHands]
hand.addCard(card)
class Hand(Deck):
def __init__(self, name=""):
self.cards = []
self.name = name
def addCard(self,card):
self.cards.append(card)
def __str__(self):
s = "Hand " + self.name
if self.isEmpty():
return s + "is empty\n"
else:
return s + " contains\n" + Deck.__str__(self)
class CardGame:
def __init__(self):
self.deck = Deck
self.deck.shuffle()
deck = Deck()
deck.shuffle()
hand = Hand("frank")
deck.deal([hand], 5)
print hand
Now I understand the self bit but I don't understand where the
self.deck.shuffle()
comes from and why it is in the __init__ function. What I need is a good explanation of classes and some everyday uses that will explain it to me.
The __init__ function does what the name implies: initialize an instance of the class.
A class is to a cookie cutter as objects are to cookies: it's a blueprint for creating and interacting with instances in memory.
What are classes and objects good for? They encapsulate data and functions together into one unit.
Every language in computer science attempts to help you with one thing: managing complexity. It encapsulates details and hides them from users so they only need to think about how that class maps onto their real life experience in order to use it effectively.
Here's another idea for you: don't use classes. Python is a nice hybrid of object-oriented and functional programming. If you don't understand classes, write Python without them. Continue to study until you see the light, then start incorporating them into your designs.

Categories