The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Games::Cards -- Perl module for writing and playing card games

SYNOPSIS

    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

DESCRIPTION

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.

Quick Overview of Classes

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

Class Games::Cards::Game

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

Games::Cards::Deck

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".

Class Games::Cards::Queue

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.

Class Games::Cards::Stack

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.

Class Games::Cards::Pile

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)

Class Games::Cards::Hand

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").

Class Games::Cards::CardSet

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

Class Games::Cards::Card

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.

name(LENGTH)

prints the name of the card. The full name ("King") if LENGTH is "long"; otherwise a short version ("K");

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.

EXAMPLES

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.

NOTES

How to write your own game

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.

Public and Private

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.

TODO

See the TODO file in the distribution

Not TODO

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.

BUGS

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.

AUTHORS

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

Copyright (c) 1999-2000 Amir Karger

LICENSE

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

SEE ALSO

perl(1), Tk(1)

3 POD Errors

The following errors were encountered while parsing the POD:

Around line 268:

You forgot a '=back' before '=head2'

Around line 488:

You forgot a '=back' before '=head2'

Around line 645:

You forgot a '=back' before '=head2'