Games::Cards 1.45
Perl
module
-
Part of CPAN
distribution
Games-Cards 1.45.
Games::Cards -- Perl module for writing and playing card games
use Games::Cards;
my $Rummy = new Games::Cards::Game;
# Create the correct deck for a game of Rummy.
my $Deck = new Games::Cards::Deck ($Rummy, "Deck");
# shuffle the deck and create the discard pile
$Deck->shuffle;
my $Discard = new Games::Cards::Queue "Discard Pile";
# Deal out the hands
foreach my $i (1 .. 3) {
my $hand = new Games::Cards::Hand "Player $i" ;
$Deck->give_cards($hand, 7);
$hand->sort_by_value;
push @Hands, $hand;
}
# print hands (e.g. "Player 1: AS 2C 3C 3H 10D QS KH")
foreach (@Hands) { print ($_->print("short"), "\n") }
$Hands[1]->give_a_card ($Discard, "8D"); # discard 8 of diamonds
This module creates objects and methods to allow easier programming of card
games in Perl. It allows you to do things like create decks of cards,
have piles of cards, hands, and other sets of cards, turn cards face-up
or face-down, and move cards from one set to another. Which is pretty much
all you need for most card games.
Sub-packages include:
- Games::Cards::Undo
-
This package handles undoing and redoing moves (important for solitaire).
- and Games::Cards::Tk
-
This package allows you to write games that use a Tk graphical interface.
It's designed so that it will be relatively easy to write a game that uses
i<either> a GUI or a simple text interface, depending on the player's
circumstances (availability of Tk, suspicious boss, etc.). See
Games::Cards::Tk for more details on writing Tk games.
A GC::Game stores information like what cards are in the starting deck,
plus pointers to the various Cards and CardSets.
A GC::Card represents one playing card. Every Card must belong to one
(and only one) CardSet at every point during the game.
A GC::CardSet is mostly just a set of GC::Cards. A CardSet has a unique
name. Many also have short nicknames, which make it easier to write games
that move cards between the sets. (See Klondike or FreeCell, for example.)
There are many sorts of CardSet. The basic differentiation is Piles,
for which you only access the top or bottom card (or cards) and Hands,
where you might access any one of the cards in the Hand. Piles are
broken up into Stacks and Queues, and every game starts with a Deck of
cards (or more than one).
This class represents a certain game, like War, or Solitaire. This is
necessary to store the various rules for a given game, like the ranking
of the cards. (Or, for more exotic games, how many cards of what type are
in the deck.) Methods:
- current_game
-
Returns the current Game object. In almost every case, you'll only be
working with one at a time.
- set_current_game(GAME)
-
In theory, these subs let you handle multiple Games at once, as long
as you set_current_game to the right one. Note that Game->new automatically
sets the current Game to be that game, so in 99% of cases, you won't have to
call set_current_game.
- new(HASHREF)
-
creates a new game. HASHREF is a reference to a hash containing zero or more
of the keys "suits" and "cards_in_suit". "suits" is a list of the suits in a
deck, "cards_in_suit" is a reference to a hash whose keys are the names
of the cards in one suit and whose values are the values (or ranks) of those
cards. If "suits" is not given, the default suits (Clubs, Diamonds, Hearts,
Spades) are used. If "cards_in_suit" is not given, the default cards
(Ace, 2..10, Jack, Queen, King with values 1..13) are used.
For example, war would require "Ace"=>14.
- get_cardset_by_name(NAME)
-
Returns the CardSet with name NAME
- get_cardset_by_nickname(NAME)
-
Returns the CardSet with nickname NAME
- get_card_by_truename(NAME)
-
Returns the Card with truename NAME
A deck is a deck of cards. The number of cards and identities of the cards in
the deck depend on the particular Game for which the deck is used.
- new (GAME, NAME)
-
creates an unshuffled deck of cards. For each card in the deck it creates
a name, suit, value, and suit value. GAME is the GC::Game this deck
belongs to, and it stipulates the number of cards in the deck, etc. NAME is the
name to give the deck, e.g. "Deck".
A Queue (cf. computer science terminology, or the C++ stdlib) is a first-in
first-out pile of cards. Cards are removed from the top of the pile, but new
cards are added to the bottom of the pile. This might represent, say, a pile
of face-down cards, like the player's hand in War.
A stack (cf. computer science terminology, or the C++ stdlib) is a last-in
first-out pile of cards. Cards are removed from the top of the pile, and new
cards are also added to the top of the pile. This would usually represent a
pile of cards with its top card (and perhaps all cards) face up.
A Pile is a pile of cards. That is, it is a CardSet where we will only access
the beginning or end of the set. (This may include the first N cards in the
set, but we will never reference the 17'th card.) This is a super class of
Queue and Stack, and those classes should be used instead, so that we know
whether the cards in the pile are FIFO or LIFO. Methods:
- give_cards(RECEIVER, NUMBER)
-
Transfers NUMBER cards from the donor (the object on which this method was
called) to the CardSet RECEIVER. This method can used for dealing cards from
a deck, giving cards to another player (Go Fish), putting cards on the table
(War), or transferring a card or cards between piles in solitaire.
If NUMBER is "all", then the donor gives all of its cards.
Returns 1 usually. If the donor has too few cards, it returns 0 and does not
transfer any cards.
- top_card
-
Returns the top Card in the CardSet (or 0 if CardSet is empty)
A Hand represents a player's hand. Most significantly, it's a CardSet which
is different from a Pile because the Cards in it are unordered. We may
reference any part of the CardSet, not just the top or bottom.
Methods:
- give_a_card(RECEIVER, DESCRIPTION)
-
Transfers Card described by DESCRIPTION from the donor (the Hand on which
this method was called) to the CardSet RECEIVER. This method can used for
discarding a card from a hand, e.g.
If DESCRIPTION matches /^-?\d+$/, then it is the index in the cards array of the
Card to give. Otherwise, DESCRIPTION is passed to Hand::index.
Returns 1 usually. If the donor does not have the card, it returns 0 and does
not transfer anything.
- move_card(DESCRIPTION, INDEX)
-
Rearrange a Hand by putting Card described by DESCRIPTION at index INDEX.
If DESCRIPTION matches /^-?\d+$/, then it is the index in the cards array of the
Card to give. Otherwise, DESCRIPTION is passed to Hand::index.
Returns 1 usually. If the donor does not have the card, it returns 0 and does
not transfer anything.
- index(DESCRIPTION)
-
Given a card description DESCRIPTION return the index of that Card
in the Hand, or undef if it was not found. DESCRIPTION may be a Card or
a string (like "8H" or "KC").
A CardSet is just an array of cards (stored in the "cards" field). It could be
a player's hand, a deck, or a discard pile, for instance. This is a super class
of a number of other classes, and those subclasses should be used instead.
- new(GAME, NAME, NICKNAME)
-
create a new (empty) CardSet. GAME is the Game object that this set belongs
to. NAME is a unique string that e.g. can be output when you print the CardSet.
Optionally, NICKNAME is a (unique!) short name that will be used to reference
the set.
- shuffle
-
shuffles the cards in the CardSet. Shuffling is not undoable.
- sort_by_value
-
Sorts the Set by value. This and other sort routines will probably be used
mostly on Hands, which are "ordered sets", but you might want to reorder a deck
or something. Sorting is not undoable.
- sort_by_suit
-
Sorts the Set by suit, but not by value within the suit.
- sort_by_suit_and_value
-
Sorts the Set by suit, then by value within the suit.
- clone(GAME, NAME, NICKNAME)
-
Create a copy of this CardSet. That is, create an object with the same class
as arg0. Then make a copy of each Card in the CardSet (true copy, not a
reference). arg1 is the Game that the set belongs to. arg2 is the name to give
the new CardSet. arg3 (optional) is the nickname.
- face_down
-
Makes a whole CardSet face down
- face_up
-
Makes a whole CardSet face up
- print(LENGTH)
-
Returns a string containing a printout of the Cards in the CardSet. Prints
a long printout if LENGTH is "long", short if "short" (or nothing).
The CardSet is printed out in reverse order, so that the top card of the set is
printed first.
- name
-
Returns the name of the Set
- nickname
-
Returns the nickname of the Set (or undef if there is none)
- cards
-
Returns a reference to the array of Cards in the set
- size
-
Tells how many cards are in the set
A Card is a playing card. Methods:
- new(GAME, HASHREF)
-
creates a new card. GAME is the Game this card is being created in. HASHREF
references a hash with keys "suit" and "name".
- clone(GAME)
-
makes a copy of the Card (not just a reference to it).
- print(LENGTH)
-
returns a string with the whole card name ("King of Hearts") if LENGTH is
"long", otherwise a short version ("KH").
- truename
-
Gives a unique description of this card, i.e., you're guaranteed that no
other card in the Game will have the same description.
- suit(LENGTH)
-
Returns the suit of the card. Returns the long version ("Diamonds") if LENGTH
is "long", else a short version ("D").
- color
-
Is the card "red" or "black"? Returns the color or undef for unknown color.
- value
-
Calculates the value of a card
- suit_value
-
Returns the suit_value of a card (1..number of suits)
- is_face_up
-
Returns true if a card is face up
- is_face_down
-
Returns true if a card is face down
- face_up
-
Makes a card face up
- face_down
-
Makes a card face down
- owning_cardset
-
Returns the CardSet which this Card is a part of
- set_owning_cardset(SET_OR_NAME)
-
Makes the Card a part of a CardSet. Arg0 is either an actual CardSet ref, or
the name of a CardSet.
An implementation of Klondike (aka standard solitaire) demonstrates how to use
this module in a simple game. Other card game examples are included as well.
The Games::Cards README should list them all.
So you want to write a card game using Games::Cards (or even
Games::Cards::Tk)? Great! That's what the module is for.
Here are some tips about how to write a game.
- Steal code
-
Laziness applies in Games::Cards just like in the rest of Perl. It will
be much easier if you start with an existing game.
- Stack vs. Queue
-
Think carefully about whether the Piles in your game are Stacks (LIFO)
or Queues (FIFO). As a general rule, piles of cards that are usually face
down will be Stacks; face up will be Queues. CardSets where you want to
access specific cards (i.e., not just the first or last) will be Hands.
- GUI games
-
I've tried to design Games::Cards::Tk and the games that use it so that
the Tk game is very similar to the text game. This allows the most code
reuse. GUI games may involve clicking, dragging, and a different way to
display the game; but the underlying game is still the same. Also note
that serious timewasters may prefer to use the keyboard to play GUI
games. See Games::Cards::Tk for more details.
This module contains a bunch of methods. The public methods are documented
here. That means any method not documented here is probably private, which
means you shouldn't call it directly.
There are also a bunch of classes. Most private classes are not documented
here. A couple private classes are mentioned, since they have methods which
public classes inherit. In that case, the privateness is mentioned.
See the TODO file in the distribution
Computer AI and GUI display were left as exercises for the reader. Then
Michael Houghton wrote a Tk card game, so I guess the readers are doing their
exercises.
You betcha. It's still alpha.
test.pl doesn't work with MacPerl, because it uses backticks. However,
(as far as I know) the games released with Games::Cards do work.
Amir Karger
Andy Bach wrote a Free Cell port, and gets points for the first submitted
game, plus some neat ideas like CardSet::clone.
Michael Houghton herveus@Radix.Net wrote the initial Tk Free Cell (two
days after Andy submitted his Free Cell!) I changed almost all of the code
eventually, to fit in with Games::Cards::Tk, but he gave me the initial push
(and code to steal).
Copyright (c) 1999-2000 Amir Karger
This program is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
perl(1), Tk(1)
|