Upload
elmer-sanderson
View
213
Download
0
Embed Size (px)
Citation preview
Cards
• 52 cards in a standard poker deck– Each card has a suit
• heart • spade • diamond • club
– and a rank• A, 2, 3, 4, 5, 6, 7, 8, 9, 10,
J, Q, K
Card Interface (Card.h)#import <Foundation/Foundation.h>
enum {HEART, SPADE, CLUB, DIAMOND};
enum {ACE=1, JACK=11, QUEEN=12, KING=13};
@interface Card : NSObject {
@private
int suit; // HEART, SPADE, DIAMOND, CLUB
int rank; // ACE, 2, 3, …, 10, JACK, QUEEN, KING
}
-(id)init;
-(id)initWithSuit:(int)s AndRank:(int)r;
-(int) suit;
-(int) rank;
@end
Card Implementation (Card.m)#import "Card.h"
@implementation Card
-(id)init {return [self initWithSuit:
SPADE AndRank: ACE];}
-(id)initWithSuit:(int)s AndRank:(int)r {
if ((self = [super init]) != nil) {
suit = s;
rank = r;
}
return self;
}
-(int)suit {return suit;}
-(int)rank {return rank;}
@end
-(id)initWithSuit:(int)s AndRank:(int)r {
if ((self = [super init]) != nil) {
suit = s;
rank = r;
}
return self;
}
Designated Initializer
• Most specialized (has most parameters)• Called by other initializers• Proper chaining of initializers:
– First call parent class’s designated initializer,– then initialize new instance variables
Accessors
• Note that instance variables are private.• A card’s suit and rank are retrieved via getter
methods – Usually have the same name as instance variable.
• Note that Card’s are immutable since we do not provide any setter methods.
-(int)suit {return suit;}
-(int)rank {return rank;}
Creating a new card
• We first send an alloc message to the Card class object which creates a new instance.
• Then we send an init message to this newly created instance.– It is important to capture the return value of the init method call, since it may return a different object then was created via alloc.
• The newly created card has a reference count of 1.
id card = [[Card alloc] init];
Black Jack Shoe
• In blackjack, a shoe is a device that can hold one to eight decks of cards from which the dealer can draw one card at time.
• When the shoe becomes sufficiently low, it is restocked and reshuffled.
Shoe.h#import <Foundation/Foundation.h>
@interface Shoe : NSObject {
@private
int numDecks;
id cards; // mutable array
}
-(id)initWithDeckCount:(int)n;
-(id)init;
-(void)dealloc;
-(void)shuffle;
-(id)deal;
-(int)cardsLeft;
-(void)reload;
@end
Shoe initialization(id)initWithDeckCount:(int)n {
if ((self = [super init]) != nil) {
numDecks = n;
cards = [[NSMutableArray alloc]
initWithCapacity: n*52];
[self reload];
}
return self;
}
Shoe destruction(void)dealloc {
[cards release];
[super dealloc];
}
• Release cards array.– Array releases each card
• Ends with call to superclass’s dealloc method.
Dealing cards from Shoe-(id)deal { if ([cards count] <= 0) return nil id card = [[cards lastObject] retain]; [cards removeLastObject]; return [card autorelease];}
• Note that we retain the last card before we release it!• We autorelease the card to safely perform the hand-off back to the caller!
Shuffling the Shoe
-(void)shuffle { const int n = [cards count]; for (int i = 0; i < n; i++) { int j = (int) (drand48()*n); if (i != j) [cards exchangeObjectAtIndex: i withObjectAtIndex: j]; }
}
Hand
• A hand is the set of cards held by a player.• A hand is valued by the sum of its cards:
– Aces worth 1 or 11– Face cards (Jack, Queen, King) are worth 10.
• A blackjack is a hand containing exactly two cards worth 21.
Hand.h#import <Foundation/Foundation.h>#import "card.h"
@interface Hand : NSObject {@private id cards;}-(id)init;-(void)dealloc;-(void)empty;-(void)insertCard:(Card *)card;-(unsigned)numCards;-(unsigned)softCount;-(unsigned)hardCount;-(unsigned)count;-(BOOL)busted;-(BOOL)blackjack;-(NSEnumerator *)cardEnumerator;@end
Hand init and dealloc-(id)init { self = [super init]; if (self != nil) { cards = [[NSMutableArray alloc] initWithCapacity: 10]; } return self;}
-(void)dealloc { [cards release]; [super dealloc];}
Inserting cards into and emptying a hand
-(void)insertCard:(Card *)card { [cards addObject: card];}
-(void)empty { [cards removeAllObjects];}
-(unsigned)numCards { return [cards count];}
Soft CountAces = 1
-(unsigned)softCount { NSEnumerator *e = [cards objectEnumerator]; id card; unsigned c = 0; while ((card = [e nextObject]) != nil) { int r = [card rank]; c += (r <= 10) ? r : 10; } return c;}
Hard CountAces = 11
-(unsigned)hardCount { NSEnumerator *e = [cards objectEnumerator]; id card; unsigned c = 0; while ((card = [e nextObject]) != nil) { int r = [card rank]; if (r == ACE) c += 11; else if (r <= 10) c += r; else // face card c += 10; } return c;}
Count closest to 21 without busting
-(unsigned)count { NSEnumerator *e = [cards objectEnumerator]; id card; unsigned c = 0; unsigned numAces = 0; while ((card = [e nextObject]) != nil) { int r = [card rank]; if (r == ACE) { c += 11; numAces++; } else c += (r <= 10) ? r : 10; } while (c > 21 && numAces > 0) { c -= 10; numAces--; } return c;}
Busted or Blackjack?-(BOOL)busted { return [self softCount] > 21;}
-(BOOL)blackjack { return [cards count] == 2 && [self hardCount] == 21;}
Player Hierarchy
NSObject
Player
DealerPlays by a fixed set of rules
HumanPlays using human I/O
CyborgPlays using AI
abstract base class
Player Base Classtypedef enum {HIT, STAY} Action;
@interface Player : NSObject {@protected int bank; id hand;}-(id)initWithBank:(int)amount;-(void)dealloc;-(int)betAmount;-(int)bank;-(void)bankCredit:(int)amount;-(void)bankDebit:(int)amount;-(Action)action;-(void)insertCard:(Card *)card;-(int)score;-(BOOL)busted;-(BOOL)blackjack;-(void)empty;-(NSEnumerator *) cardEnumerator;@end
Player init and dealloc
-(id)initWithBank:(int)amount { self = [super init]; if (self != nil) { bank = amount; hand = [[Hand alloc] init]; } return self;}
-(void)dealloc { [hand release]; [super dealloc];}
Default player strategy
-(int)betAmount {return bank;} // bet it all!
-(Action)action { // mimic dealer return ([hand hardCount] < 17) ? HIT : STAY;}
Other default behavior
-(int)bank {return bank;}-(void)bankCredit:(int)amount {bank += amount;}-(void)bankDebit:(int)amount {bank -= amount;}-(void)insertCard:(Card *)card { [hand insertCard: card];}-(int)score {return [hand count];}-(BOOL)busted {return [hand busted];}-(BOOL)blackjack {return [hand blackjack];}-(void)reset {[hand empty];}-(NSEnumerator *) cardEnumerator { return [hand cardEnumerator];}
The Dealer@interface Dealer : Player {@protected id shoe;}-(id)initWithDeckCount:(int)num;-(id)deal:(id)player;-(int)cardsLeft;-(void)reload;-(void)shuffle;@end
Dealer init and dealloc-(id)initWithDeckCount:(int)num { self = [super initWithBank: 0]; // has no bank if (self != nil) { shoe = [[Shoe alloc] initWithDeckCount: num]; } return self;}
-(void)dealloc { [shoe release]; [super dealloc];}
Dealer methods-(id)deal:(id)player { id card = [shoe draw]; if (player != nil) // player == nil => burn card [player insertCard: card]; return card;}
-(int)cardsLeft {return [shoe cardsLeft];}-(void)restock {[shoe restock];}-(void)shuffle {[shoe shuffle];}
// inherits action strategy (and other behavior) from Player
Table.mDealer and 1 to 7 Players
@interface Table : NSObject {@private id dealer; id players; // mutable array}-(id)initWithDeckCount:(int)num;-(void)dealloc;-(int)numPlayers;-(void)addPlayer:(id)player;-(void)removePlayer:(id)player;-(id)dealer;-(NSEnumerator *)playerEnumerator;@end
Cyborg.hAn Example Player AI
@interface Cyborg : Player {// no new instance vars}-(int)betAmount;-(Action)action;@end
Cyborg method overrides
-(int)betAmount { int amount = (int) (50*drand48()); if (amount > bank) amount = bank; return amount;}
-(Action)action { return ([hand softCount] < 18) ? HIT : STAY;}