class inheritance exercise using Old Maid card game as example - python

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

Related

builtins.TypeError: __init__() takes 1 positional argument but 2 were given

its my first question there, Im receiving TypeError. I think I changed everything I could, but the result didn't change. Since I'm a newbie, I think the error may be very obvious. I will be especially grateful to anyone who points out other mistakes to me
it seems that the init function of the BJ_game class gets 2 arguments, but the trace says that 1, please explain why
Traceback (most recent call last):
File "G:/СОБСТВЕННОСТЬ А. С/Black - Djack/Black - Djack.py", line 255, in <module>
main()
File "G:/СОБСТВЕННОСТЬ А. С/Black - Djack/Black - Djack.py", line 246, in <module>
game = BJ_Game(names)
File "G:/СОБСТВЕННОСТЬ А. С/Black - Djack/Black - Djack.py", line 174, in <module>
player = BJ_Player(name)
builtins.TypeError: __init__() takes 1 positional argument but 2 were given
#!/usr/bin/env python
# -*- coding: utf8 -*-
class CARD(object):
#объявляем масти и ранги
Ranks = ['2','3','4','5','6','7','8','9','10','J','Q','K','A',]
Suits = ['tre','pik','che','bub']
def __init__(self, rank, suit, face_up = True):
self.rank = rank
self.suit = suit
self.is_face_up = face_up
def __str__(self):
#"собирает" карту из масти и ранга
if self.is_face_up:
rep = self.rank + self.suit
else:
rep = 'XX'
return rep
def flip(self):
self.is_face_up = not self.is_face_up
class Hand(object): #стандартная рука игрока
def __init__(self):
self.cards = []
def __str__(self):
#спец. метод, собирает карты в строку
if self.cards:
rep = ""
for card in self.cards:
rep += str(card) + "\t"
else:
rep = '<none>'
return rep
def clear_hand(self):
self.cards = []
def add_card(self, card):
self.cards.append(card)
def give(self, other_hand, card):
self.cards.remove(card)
other_hand.add_card(card)
class Deck (Hand): #класс колоды
def populate(self):
#перебирает комбинации мастей и рангов, создавая колоду
for suit in CARD.Suits:
for rank in CARD.Ranks:
self.add_card(CARD(rank, suit))
def shuffle(self):
import random
random.shuffle(self.cards)
def deal(self, hands, per_hand = 1):
#раздача карт
for rounds in range(per_hand):
for hand in hands:
if self.cards:
#берет верхнюю карту и добавляет ее на руку
top_card = self.cards[0]
self.give(hand, top_card)
else:
print('больше нет карт!')
class Player():
def _init_(self, name, score = 0):
self.name = name
self.score = score
def __str__ (self):
rep =self.name + ":\t" + str(self.score)
return rep
def ask_yes_no(question):
response = None
while response not in ("у", "n"):
response = input(question).lower()
return response
def ask_number(question, high, low):
response = None
while response not in range(low, high):
response = int(input(question))
return response
class BJ_Card(CARD):
#карта для игры в Блек - джек
Ace_value = 1
#property
def value(self):
if self.is_face_up:
v = BJ_Card.Ranks.index(self, rank) + 1
if v > 10:
v = 10
else:
v = None
return v
class BJ_Deck(Deck):
def populate(self):
for suit in BJ_Card.Suits:
for rank in BJ_Card.Ranks:
self.cards.append(BJ_Card(rank. suit))
class BJ_Hand(Hand):
def _init_(self, name):
super(BJ_Hand. self).__init__()
self.name = name
def __str__(self):
rep = self.name + ":\t" + super(BJ_Hand, self).__str__()
if self.total:
rep += "(" + str(self.total) + ")"
return rep
def total(self):
#если у одной из карт value равно None. то и все свойство равно None
for card in self.cards:
if not card.value:
return None
#суммируем очки. считая каждый туз за 1 очко
t = о
for card in self.cards:
t += card.value
#определяем. есть ли туз на руках у игрока
contains_ace = False
for card in self.cards:
if card.value == BJ_Card.ACE_VALUE:
contains_асе = True
# если на руках есть туз и сумма очков не превышает 11. будем считать туз за 11
if contains_асе and t <= 11:
# прибавить нужно лишь 10. потому что единица уже вошла в общую сумму
t += 10
return t
def is_busted(self):
return self.total > 21
class BJ_Player(BJ_Hand):
def is_hitting(self):
response = games_module.ask_yes_no("\n" + self.name +" будете брать еще карты?(Y/N): ")
return response == "у"
def bust(self):
print(self.name, "перебрал.")
self.lose()
def lose(self):
print (self. name, "проиграл.")
def win(self):
print(self.name, "выиграл.")
def push(self):
print(self.name, "сыграл вничью.")
class BJ_Dealer(BJ_Hand):
def is_hitting(self):
return self.total < 17
def bust(self):
print (self. name, 'перебрал. ')
def flip_first_card(self):
first_card = self.cards[O]
first_card.flip()
class BJ_Game():
def __init__(self,names = 'Player1'):
self.players = []
for name in names:
player = BJ_Player(name)
self.players.append(player)
self.dealer = BJ_Dealer('dealer')
self.deck = BJ_Deck()
self.deck = populate()
self.deck = Shuffle()
#property
def still_playing(self):
sp =[]
for player in self.players:
if not player.is_busted():
sp.attend(player)
return sp
def __addittional_cards(self, player):
while not player.is_busted() and player.is_hitting():
self.deck.deal([player])
print(player)
if player.is_busted():
player.bust()
def game_process(self):
#раздача всем по 2 карты
self.deck.deal(self.players+[self.dealer], per_hand = 2)
#первая карта дилера скрывается
self.dealer.flip_first_card()
for player in self.players:
print(player)
print(self.dealer)
#раздача доп. карт игрокам
for player in self.players:
self.__additional_cards(player)
#раскрытие первой карты дилера
self.dealer.flip_first_card()
#если все перебрали показываем руку дилера
if not self.still_playing:
print(self.dealer)
else:
#даем доп карты дилеру
print(self.dealer)
self.__additional_cards(self.dealer)
#если дилер перебрал, побеждают оставшиеся игроки
if self.dealer.is_busted():
for players in self.still_playing:
player.win()
#сравниваем очки у игроков и дилера
else:
for player in self.still_playing:
if player.total > self.dealer.total:
player.win()
elif player.total < self.dealer.total:
player.lose()
else:
рlayer.push()
#удаляем карты из игры
for player in self.players:
player.clear()
self.dealer.clear()
#основная часть
def main():
print("\t\tДoбpo пожаловать за игровой стол Блек-джека!\n")
names = []
number = Player.ask_number("Cкoлькo всего игроков? (1 - 7): ", low = 1, high= 8)
for i in range(number):
name = input ('введите имя игрока: ')
names.append(name)
print()
game = BJ_Game(names)
again = None
while again != "n":
game.game_process()
again = Player.ask_yes_no("\nXoтитe сыграть еще раз? ")
main()
iпрut("\n\пНажмите Enter. чтобы выйти.")
main()
the error is coming from
player = BJ_Player(name) line 174
in BJ_Player class you have not defined __init__ function so by default it takes
def __init__(self)
which has only self as one variable but when you are creating the object you are passing another variable name that is why it is giving you error that you are passing 2 variables while 1 is needed.
define __init__ function in your BJ_Player class and other classes in which you are passing data on object creation. __init__ works as a constructor for the class.
for example BJ_Player should be like:
class BJ_Player(BJ_Hand):
def __init__(self,name):
self.name = name
edit : juanpa suggested you have init defined in Player function but it has a typo thats why default init is being called with 1 positional argument. no need to define it explicitly here
The fixed class hierarchy below.
There was an issue with BJ_Hand __init__ method. (wrong name of the method)
class Hand: # стандартная рука игрока
def __init__(self):
self.cards = []
class BJ_Hand(Hand):
def __init__(self, name):
super(BJ_Hand, self).__init__()
self.name = name
class BJ_Player(BJ_Hand):
def __init__(self, name):
super(BJ_Player, self).__init__(name)
def is_hitting(self):
return True
def bust(self):
print(self.name, "перебрал.")
self.lose()
def lose(self):
print(self.name, "проиграл.")
def win(self):
print(self.name, "выиграл.")
def push(self):
pass
p = BJ_Player('jack')
print(p.name)

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

How to create a hand with 13 playing cards in it

I was given a project in computer science, however I can't figure out how to get 13 cards into my hand. There is a memory error in the hand class, but I can't figure out why, it isn't putting 13 cards in each hand. Here is my code so far:
#Keshav Ramesh
#Project 8
import random
class card:
def __init__(self, suit, value):
self.suit=suit
self.value=value
#methods
def printer(self):
print("{0} {1}".format(self.suit, self.value))
def __lt__(self, other):
if(self.value == other.value):
return self.suit < other.suit
elif (self.value != other.value):
return self.value < other.value
def __gt__(self, other):
return not(self<other)
def __str__(self):
return "Suit: " + str(self.suit) + " value: " + str(self.value)
class deck:
def __init__(self):
self.x=[]
self.load()
random.shuffle(self.x)
def load(self):
for i in range(1, 5):
for j in range(2, 14):
self.x.append(card(i, j))
def deal(self):
return self.x.pop()
p = deck()
class hand:
def __init__(self):
self.x=[]
self.hand_count=0
while len(self.x) != 13:
self.x.append(p.deal())
def accept(self, a):
self.x.append(a)
self.hand_count= self.hand_count + 1
def play(self):
self.hand_count = self.hand_count - 1
return self.x.pop()
def handPrinter(self):
while len(self.x) != 0:
result = (self.pop())
print("{0} {1}".format(result.suit, result.value))
When you do
result = (self.pop())
in the handPrinter method maybe you meant to do
result = (self.x.pop())
That was causing an error when executing your code. Also, in the __init__ method of Card class you should ident self.suit = suit and self.value = value.
Other than that, by adding
h = hand()
h.handPrinter()
at the end, everything seems to be working fine to me.

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 Blackjack Graphics Game - my card image won't import

I'm making a Blackjack game and still early process. When I run my program, I get the error
im = Image(Point(350, 250), "playingcards/" + suit + str(rank) + ".gif")
NameError: name 'suit' is not defined
Which I'm pretty sure it's because im = ___ is in my def main(): part of my function, even though the suit is being defined within my code.
It's basically seems like my program is ignoring all of my code and going straight to the def main(), which is probably an ordering error on my part, but can someone explain where it's supposed to go so that it reads all my class functions before the main?
Here's my code:
from random import *
from graphics import *
class PlayingCard:
def __init__(self, rank, suit):
self.rank = rank
self.suit = suit
def getRank (self):
return self.rank
def getSuit(self):
return self.suit
def BJValue (self):
if self.rank == 'Ace':
return 1
elif self.rank == 'Jack' or self.rank == 'Queen' or self.rank == 'King':
return 10
else:
return int(self.rank)
def __str__(self):
suit_name= {'S':'Spades', 'C':'Clubs', 'D':'Diamonds', 'H':'Hearts'}
rank_name=[None, 'Ace','2','3','4','5','6','7','8','9','10','Jack','Queen','King']
return '%s of %s' % (Card.rank_names[self.rank], Card.suit_names[self.suit])
from random import *
from playingcards import *
class Deck:
def __init__(self):
self.cards = []
x = eval(input("How many cards shall be dealt?"))
for suit in range(x):
for rank in range(1, 14):
card = Card(suit, rank)
self.cards.append(card)
def shuffle(self):
random.shuffle(self.cards)
def DealCard(self):
return self.deck.pop(0)
def CardsLeft(self):
return len(self.deck)
class Blackjack:
def __init__(self, dHand=[], pHand=[]):
self.dHand = PlayingCard
self.pHand = PlayingCard
self.deck = Deck()
Deck.shuffle(self.Blackjack)
def initDeal(self,gwin,xposD,yposD,xposP,yposP):
self.DealCard.dHand = [2]
self.DealCard.pHand = [2]
# PlayingCard.draw(win)
dealtCard = self.deck.DealCard()
suit = dealtCard.getSuit()
rank = dealtCard.getRank()
#import(file=image_
def hit(self, gwin, xPos, yPos):
print('hi')
def evaluateHand(self, hand):
print('hi')
def dealerPlays(self, gwin, xPos, yPos):
print('hi')
def main():
win = GraphWin("BlackJack", 800, 800)
im = Image(Point(350, 250), "playingcards/" + suit + str(rank) + ".gif")
im.draw(win)
if __name__ == "__main__":
main()

Categories