Chapter 10 : Inheritance and Polymorphism: Blackjack

example 10.1 page no: 334

In [1]:
class Enemy:
    def __init__(self):
        self.m_Damage = 10

    def Attack(self):
        print "An enemy attacks and inflicts " , self.m_Damage , " damage points!";
        
    def __del__(self):
        print  "In Enemy destructor, deleting m_pDamage.\n";

class Boss(Enemy):
    def __init__(self):
        Enemy.__init__(self)
        self.m_DamageMultiplier = 3

    def SpecialAttack(self):
        print "A boss attacks and inflicts " , (self.m_DamageMultiplier * self.m_Damage),
        print " damage points!";

print "Creating an enemy.\n";
enemy1 = Enemy()
enemy1.Attack();
print "\nCreating a boss.\n";
boss1 = Boss()
boss1.Attack();
boss1.SpecialAttack();
Creating an enemy.

An enemy attacks and inflicts  10  damage points!

Creating a boss.

An enemy attacks and inflicts  10  damage points!
A boss attacks and inflicts  30  damage points!

example 10.2 page no : 338

In [2]:
class Enemy:
    def __init__(self):
        self.m_Damage = 10

    def Attack(self):
        print "Attack inflicts " , self.m_Damage , " damage points!";

class Boss(Enemy):
    def __init__(self):
        Enemy.__init__(self)
        self.m_DamageMultiplier = 3

    def SpecialAttack(self):
        print "Special Attack inflicts " , (self.m_DamageMultiplier * self.m_Damage),
        print " damage points!";

print "Creating an enemy.\n";
enemy1 = Enemy()
enemy1.Attack();
print "\nCreating a boss.\n";
boss1 = Boss()
boss1.Attack();
boss1.SpecialAttack();
Creating an enemy.

Attack inflicts  10  damage points!

Creating a boss.

Attack inflicts  10  damage points!
Special Attack inflicts  30  damage points!

example 10.3 page no : 343

In [3]:
class Enemy:
    def __init__(self,d=10):
        self.m_Damage = d

    def Attack(self):
        print "Attack inflicts " , self.m_Damage , " damage points!";

    def Taunt(self):
        print "The enemy says he will fight you.";
    __Attack = Attack    


class Boss(Enemy):
    def __init__(self,d=30):
        Enemy.__init__(self)
        self.m_DamageMultiplier = d

    def SpecialAttack(self):
        print "Special Attack inflicts " , (self.m_DamageMultiplier * self.m_Damage),
        print " damage points!";

    def Taunt(self): #override base class member function
        print "The boss says he will end your pitiful existence."

    def Attack(self): #override base class member function
        #call base class member function
        Enemy.Attack(self)
        print " And laughs heartily at you.\n";


print "Enemy object :";
enemy1 = Enemy()
enemy1.Taunt()
enemy1.Attack();
print "\n boss object.\n";
boss1 = Boss()
boss1.Taunt()
boss1.Attack();
Enemy object :
The enemy says he will fight you.
Attack inflicts  10  damage points!

 boss object.

The boss says he will end your pitiful existence.
Attack inflicts  10  damage points!
 And laughs heartily at you.

example 10.4 page no : 341,348

In [4]:
class Enemy:
    def __init__(self,d=10):
        self.m_Damage = d

    def Attack(self):
        print "Attack inflicts " , self.m_Damage , " damage points!";

    def __del__(self):
        print "In Enemy destructor, deleting m_pDamage.";
        
class Boss(Enemy):
    def __init__(self,d=30):
        Enemy.__init__(self)
        self.m_DamageMultiplier = d

    def SpecialAttack(self):
        print "Special Attack inflicts " , (self.m_DamageMultiplier * self.m_Damage),
        print " damage points!";

    def Taunt(self): #override base class member function
        print "The boss says he will end your pitiful existence."

    def Attack(self): #override base class member function
        #call base class member function
        Enemy.Attack(self)
        print " And laughs heartily at you.\n";

    def __del__(self):
        Enemy.__del__(self)
        print "In Boss destructor, deleting m_pMultiplier.";
        self.m_pMultiplier = 0;

print "Calling Attack() on Boss object through pointer to Enemy:"
pBadGuy = Boss();
pBadGuy.Attack();
print "\nDeleting pointer to Enemy:\n";
pBadGuy = 0;
Calling Attack() on Boss object through pointer to Enemy:
Attack inflicts  10  damage points!
 And laughs heartily at you.


Deleting pointer to Enemy:

In Enemy destructor, deleting m_pDamage.
In Boss destructor, deleting m_pMultiplier.

example 10.5 page no : 353

In [5]:
class Creature :
    def __init__(self,h=100):
        self.m_Health = h
        
    def Greet(self): # pure virtual member function
        pass

    def DisplayHealth(self):
        print "Health: " , self.m_Health


class Orc(Creature):
    def __init__(self,h=120):
        Creature.__init__(self,h)

    def Greet(self):
        print "The orc grunts hello.\n";

pCreature =  Orc();
pCreature.Greet();
pCreature.DisplayHealth();
The orc grunts hello.

Health:  120

example 10.6, page no : 361-379

In [*]:
ACE = 1
TWO = 2
THREE = 3
FOUR = 4
FIVE = 5
SIX = 6
SEVEN = 7
EIGHT = 8
NINE = 9
TEN = 10
JACK = 11
QUEEN = 12
KING = 13

CLUBS = 0
DIAMONDS = 1
HEARTS = 2
SPADES = 3

   
class Card:
    def __init__(self,r = ACE,s = SPADES,ifu = True): #returns the value of a card, 1 - 11
        self.m_Rank = r
        self.m_Suit = s
        self.m_IsFaceUp =ifu

    def GetValue(self):
        #if a cards is face down, its value is 0
        value = 0;
        if (m_IsFaceUp):
            #value is number showing on card
            value = m_Rank;
            #value is 10 for face cards
            if (value > 10):
                value = 10;
        return value;

    def Flip(self):
        self.m_IsFaceUp = not (self.m_IsFaceUp);

class Hand:
    def __init__(self):
        self.m_Cards = []

    def __del__(self):
        self.Clear()    

    def Add(self,pCard):
        self.m_Cards.append(pCard);

    def Clear(self):
        #iterate through vector, freeing all memory on the heap
        self.m_Cards = []

    def GetTotal(self):
        #if no cards in hand, return 0
        if (self.m_Cards.empty()):
            return 0;
        #if a first card has value of 0, then card is face down; return 0
        if (self.m_Cards[0].GetValue() == 0):
            return 0;
        #add up card values, treat each ace as 1
        total = 0;
        for i in self.m_Cards:
            total += i.GetValue()
        #determine if hand contains an ace
        containsAce = False;
        for i in self.m_Cards:
            if i.GetValue() == Card.ACE:
                containsAce = True;

        #if hand contains ace and total is low enough, treat ace as 11
        if (containsAce and total <= 11):
            #add only 10 since we've already added 1 for the ace
            total += 10;
        return total;


class GenericPlayer(Hand):
    def __init__(self,name):
        self.m_Name = name

    def __del__(self):
        pass

    def IsBusted(self):
        return (self.GetTotal() > 21);

    def Bust(self):
        print self.m_Name , " busts.";

class Player(GenericPlayer):
   def _init_(self,name):
       GenericPlayer.__init__(self,name)
   
   def _del_(self):
       pass

   def IsHitting(self):
       print self.m_Name , ", do you want a hit? (Y/N): ",
       response = raw_input()
       return (response == 'y' or response == 'Y');

   def Win(self):
       print self.m_Name , " wins.";

   def Lose(self):
       print self.m_Name , " loses.";

   def Push(self):
       print self.m_Name , " pushes.";

class House(GenericPlayer):
    def __init__(self,name="House"):
        GenericPlayer.__init__(self,name)

    def __del__(self):
        pass

    def IsHitting(self):
        return (self.GetTotal() <= 16)

    def FlipFirstCard(self):
        if (not self.m_Cards):
            self.m_Cards[0].Flip();
        else:
            print "No card to flip!";
        
class Deck(Hand):
    def __init__(self):
        self.m_Cards = []
        self.Populate();
    
    def __del__(self):
        pass
        
    def Populate(self):
        self.Clear();
        #create standard deck
        for s in range(CLUBS,SPADES+1):
            for r in range(ACE,KING+1):
                self.Add(Card(r,s))

    def Shuffle(self):
        pass

    def Deal(self, aHand):
        if (not self.m_Cards):
            aHand.Add(self.m_Cards[-1]);
            self.m_Cards.pop();
        else:
            print "Out of cards. Unable to deal.";

    def AdditionalCards(self,aGenericPlayer):
        print ''
        #continue to deal a card as long as generic player isn't busted and
        #wants another hit
        while ( not (aGenericPlayer.IsBusted()) and aGenericPlayer.IsHitting() ):
            self.Deal(aGenericPlayer);
            print  aGenericPlayer
            if (aGenericPlayer.IsBusted()):
                aGenericPlayer.Bust();
        

class Game:
    def __init__(self,names):
        #create a vector of players from a vector of names
        self.m_Players = []
        for i in names:
            self.m_Players.append(Player(i))
        self.m_Deck = Deck()
        self.m_House = House()
        self.m_Deck.Populate();
        self.m_Deck.Shuffle();

    def __del__(self):
        pass
        
    def Play(self):
        # deal initial 2 cards to everyone
        for i in range(2):
            for pPlayer in self.m_Players:
                self.m_Deck.Deal(pPlayer);
            self.m_Deck.Deal(self.m_House);
        #hide house's first card
        self.m_House.FlipFirstCard();
        for pPlayer in self.m_Players:
            print pPlayer 

        print self.m_House
        #deal additional cards to players
    
        for pPlayer in self.m_Players:
            self.m_Deck.AdditionalCards(pPlayer);

        #reveal house's first card
        self.m_House.FlipFirstCard();
        print self.m_House;
        #deal additional cards to house
        self.m_Deck.AdditionalCards(m_House);
        if (self.m_House.IsBusted()):
            #everyone still playing wins
            for pPlayer in self.m_Players:
                if ( not (pPlayer.IsBusted()) ):
                    pPlayer.Win();
        else:
            #compare each player still playing to house
            for pPlayer in self.m_Players:
                if ( not (pPlayer.IsBusted()) ):
                    if (pPlayer.GetTotal() > self.m_House.GetTotal()):
                        pPlayer.Win();
                    elif (pPlayer.GetTotal() < self.m_House.GetTotal()):
                        pPlayer.Lose();
                    else:
                        pPlayer.Push();

        #remove everyones cards
        for pPlayer in self.m_Players:
            pPlayer.Clear();

        self.m_House.Clear();

print "\t\tWelcome to Blackjack!\n";
numPlayers = 0;
while (numPlayers < 1 or numPlayers > 7):
    print "How many players? (1 - 7): ";
    numPlayers = int(raw_input())

names = []
name = ''
for i in range(numPlayers):
    print "Enter player name: ";
    name = raw_input()
    names.append(name);  

print ''
#the game loop
aGame = Game(names);
again = 'y'
while (again != 'n' and again != 'N'):
    aGame.Play();
    print "\nDo you want to play again? (Y/N): ",
    again = raw_input()

#overloads << operator so Card object can be sent to cout
def print_(aCard):
    RANKS = ["0", "A", "2", "3", "4", "5", "6", "7", "8", "9","10", "J", "Q", "K"]
    SUITS = ["c", "d", "h", "s"]
    if (aCard.m_IsFaceUp):
        print RANKS[aCard.m_Rank] , SUITS[aCard.m_Suit];
    else:
        print "XX";
    

def print__(aGenericPlayer):
    print aGenericPlayer.m_Name
    pCard = []
    if (not aGenericPlayer.m_Cards):
        for pCard in aGenericPlayer.m_Cards:
            print pCard
    
    if (aGenericPlayer.GetTotal() != 0):
        print "(" , aGenericPlayer.GetTotal() , ")";
    else:
        print "<empty>";
        
# Note : this example is just for concept purpose. i.e. Inheritance example. it has errors so do not run it        
		Welcome to Blackjack!

How many players? (1 - 7): 
In [ ]: