Playing cards

From Rosetta Code
Revision as of 18:19, 3 November 2009 by rosettacode>IanOsgood (Logo)
Task
Playing cards
You are encouraged to solve this task according to the task description, using any language you may know.

Create a data structure and the associated methods to define and manipulate a deck of playing cards. The deck should contain 52 unique cards. The methods must include the ability to make a new deck, shuffle (randomize) the deck, deal from the deck, and print the current contents of a deck. Each card must have a pip value and a suit value which constitute the unique value of the card.

Ada

Here is the package specification for a deck of playing cards. <lang ada> package Playing_Cards is

  pragma Elaborate_Body(Playing_Cards);
  type Card is private;
  procedure Print(The_Card : Card);
  type Deck is private;
  procedure Print(the_Deck : Deck);
  procedure Deal(From : in out Deck; The_Card : out Card);
  procedure Shuffle(The_Deck : in out Deck);
  function New_Deck return Deck;
  Deck_Empty : exception;

private

  type Pips is (Two, Three, Four, Five, Six, Seven,
     Eight, Nine, Ten, Jack, Queen, King, Ace);
  type Suits is (Diamonds, Spades, Hearts, Clubs);
  type Card is record
     Pip : Pips;
     Suit : Suits;
  end record;
  type Index is range 1..53;
  subtype Deck_Index is Index range 1..52;
  type Deck_Reference is array(Deck_Index) of Deck_Index;
  type Deck is record
     Next_Card : Index;
     Deck_Offsets : Deck_Reference;
  end record;

end Playing_Cards; </lang> Here is the package body for that same playing card package. This implementation stores one array of cards in sorted order. Each deck contains an array of indices into that one array of cards. Shuffling the deck actually results in randomizing the order of those indices into the array of cards. This approach maximizes shuffling efficiency by only exchanging indices. It also maximizes memory efficiency since an array of cards requires more memory than an array of indices. <lang ada> with Ada.Numerics.Discrete_Random; With Ada.Text_IO;

package body Playing_Cards is

  type Internal_Deck is array(Deck_Index) of Card;
  Base_Deck : Internal_Deck;
  Base_Index : Index;
  ----------
  -- Deal --
  ----------
  procedure Deal (From : in out Deck; The_Card : out Card) is
  begin
     if From.Next_Card not in Deck_Index then
        raise Deck_Empty;
     end if;
     The_Card := Base_Deck(From.Deck_Offsets(From.Next_Card));
     From.Next_Card := From.Next_Card + 1;
  end Deal;
  --------------
  -- New_Deck --
  --------------
  function New_Deck return Deck is
     Temp : Deck;
  begin
     for I in Base_Deck'range loop
        Temp.Deck_Offsets(I) := I;
     end loop;
     Temp.Next_Card := 1;
     return Temp;
  end New_Deck;
  -----------
  -- Print --
  -----------
  
  procedure Print(The_Card : Card) is
     package Pip_Io is new Ada.Text_Io.Enumeration_Io(Pips);
     use Pip_Io;
     package Suit_Io is new Ada.Text_Io.Enumeration_Io(Suits);
     use Suit_Io;
  begin
     Put(Item => The_Card.Pip, Width => 1);
     Ada.Text_Io.Put(" of ");
     Put(Item => The_Card.Suit, Width => 1);
     Ada.Text_Io.New_Line;
  end Print;
  
  -----------
  -- Print --
  -----------
  
  procedure Print(The_Deck : Deck) is
  begin
     for I in The_Deck.Next_Card..Deck_Index'Last loop
        Print(Base_Deck(The_Deck.Deck_Offsets(I)));
     end loop;
  end Print;
  
  -------------
  -- Shuffle --
  -------------
  procedure Shuffle (The_Deck : in out Deck) is
     procedure Swap(Left, Right : in out Deck_Index) is
        Temp : Deck_Index := Left;
     begin
        Left := Right;
        Right := Temp;
     end Swap;
     Swap_Index : Deck_Index;
  begin
     for I in Deck_Index'First..Deck_Index'Pred(Deck_Index'Last) loop
        declare
           subtype Remaining_Indices is Deck_Index range I..Deck_Index'Last;
           package Rand_Card is new Ada.Numerics.Discrete_Random(Remaining_Indices);
           use Rand_Card;
           Seed : Generator;
        begin
           Reset(Seed);
           Swap_Index := Random(Seed);
           Swap(The_Deck.deck_Offsets(I), The_Deck.Deck_Offsets(Swap_Index));
        end;
     end loop;
     The_Deck.Next_Card := 1;
  end Shuffle;
  

begin

  Base_Index := 1;
  for Suit in Suits'range loop
     for Pip in Pips'range loop
        Base_Deck(Base_Index) := (Pip, Suit);
        Base_Index := Base_Index + 1;
     end loop;
  end loop;

end Playing_Cards; </lang>

ALGOL 68

The scoping rules of ALGOL 68 tend to make object oriented coding in ALGOL 68 difficult. Also as invoking PROC is done before members of a STRUCT are extracted the programmer one quickly finds it is necessary to use numerous brackets.

e.g. compare "(shuffle OF deck class)(deck)" with python's simple "deck.shuffle()"

For further details:

<lang cpp>MODE CARD = STRUCT(STRING pip, suit); # instance attributes #

  1. class members & attributes #

STRUCT(

 PROC(REF CARD, STRING, STRING)VOID init, 
 FORMAT format,
 PROC(REF CARD)STRING repr,
 []STRING suits, pips

) class card = (

  1. PROC init = # (REF CARD self, STRING pip, suit)VOID:(
   pip OF self:=pip;
   suit OF self :=suit
 ),
  1. format = # $"("g" OF "g")"$,
  2. PROC repr = # (REF CARD self)STRING: (
   HEAP STRING out; putf(BOOK out,(format OF class card,self)); out
 ),
  1. suits = # ("Clubs","Hearts","Spades","Diamonds"),
  2. pips = # ("2","3","4","5","6","7","8","9","10","Jack","Queen","King","Ace")

);

MODE DECK = STRUCT(REF[]CARD deck); # instance attributes #

  1. class members & attributes #

STRUCT(

 PROC(REF DECK)VOID init, shuffle, 
 PROC(REF DECK)STRING repr, 
 PROC(REF DECK)CARD deal

) class deck = (

  1. PROC init = # (REF DECK self)VOID:(
   HEAP[ UPB suits OF class card * UPB pips OF class card ]CARD new;
   FOR suit TO UPB suits OF class card DO
     FOR pip TO UPB pips OF class card DO
       new[(suit-1)*UPB pips OF class card + pip] :=
          ((pips OF class card)[pip], (suits OF class card)[suit])
     OD
   OD;
   deck OF self := new
 ),

  1. PROC shuffle = # (REF DECK self)VOID:
   FOR card TO UPB deck OF self DO
     CARD this card = (deck OF self)[card];
     INT random card = random int(LWB deck OF self,UPB deck OF self);
     (deck OF self)[card] := (deck OF self)[random card];
     (deck OF self)[random card] := this card
   OD,

  1. PROC repr = # (REF DECK self)STRING: (
   FORMAT format = $"("n(UPB deck OF self-1)(f(format OF class card)", ")f(format OF class card)")"$;
   HEAP STRING out; putf(BOOK out,(format, deck OF self)); out
 ),

  1. PROC deal = # (REF DECK self)CARD: (
   (shuffle OF class deck)(self);
   (deck OF self)[UPB deck OF self]
 )

);

  1. associate a STRING with a FILE for easy text manipulation #

OP BOOK = (REF STRING string)REF FILE:(

 HEAP FILE book;
 associate(book, string);
 book

);

  1. Pick a random integer between from [lwb..upb] #

PROC random int = (INT lwb, upb)INT:

 ENTIER(random * (upb - lwb + 1) + lwb);

DECK deck; (init OF class deck)(deck); (shuffle OF class deck)(deck); print (((repr OF class deck)(deck), new line))</lang> Example output:
((King OF Clubs), (6 OF Hearts), (7 OF Diamonds), (Ace OF Hearts), (9 OF Spades), (10 OF Clubs), (Ace OF Spades), (8 OF Clubs), (4 OF Spades), (8 OF Hearts), (Jack OF Hearts), (3 OF Clubs), (7 OF Hearts), (10 OF Hearts), (Jack OF Clubs), (Ace OF Clubs), (King OF Spades), (9 OF Clubs), (7 OF Spades), (5 OF Spades), (7 OF Clubs), (Queen OF Clubs), (9 OF Diamonds), (2 OF Spades), (6 OF Diamonds), (Ace OF Diamonds), (Queen OF Diamonds), (5 OF Hearts), (4 OF Clubs), (5 OF Clubs), (4 OF Hearts), (3 OF Diamonds), (4 OF Diamonds), (3 OF Hearts), (King OF Diamonds), (2 OF Clubs), (Jack OF Spades), (2 OF Diamonds), (5 OF Diamonds), (Queen OF Spades), (10 OF Diamonds), (King OF Hearts), (Jack OF Diamonds), (Queen OF Hearts), (8 OF Spades), (2 OF Hearts), (8 OF Diamonds), (10 OF Spades), (9 OF Hearts), (6 OF Clubs), (3 OF Spades), (6 OF Spades))

BASIC

Most BASICs aren't object-oriented (or anything even resembling such) and can't do a deck of cards as a single cohesive unit -- but we can fake it. <lang qbasic> DECLARE SUB setInitialValues (deck() AS STRING * 2) DECLARE SUB shuffle (deck() AS STRING * 2) DECLARE SUB showDeck (deck() AS STRING * 2) DECLARE FUNCTION deal$ (deck() AS STRING * 2)

DATA "AS", "2S", "3S", "4S", "5S", "6S", "7S", "8S", "9S", "TS", "JS", "QS", "KS" DATA "AH", "2H", "3H", "4H", "5H", "6H", "7H", "8H", "9H", "TH", "JH", "QH", "KH" DATA "AC", "2C", "3C", "4C", "5C", "6C", "7C", "8C", "9C", "TC", "JC", "QC", "KC" DATA "AD", "2D", "3D", "4D", "5D", "6D", "7D", "8D", "9D", "TD", "JD", "QD", "KD"

RANDOMIZE TIMER

REDIM cards(51) AS STRING * 2 REDIM cards2(51) AS STRING * 2

setInitialValues cards() setInitialValues cards2() shuffle cards() PRINT "Dealt: "; deal$(cards()) PRINT "Dealt: "; deal$(cards()) PRINT "Dealt: "; deal$(cards()) PRINT "Dealt: "; deal$(cards()) showDeck cards() showDeck cards2()

FUNCTION deal$ (deck() AS STRING * 2)

   'technically dealing from the BOTTOM of the deck... whatever
   DIM c AS STRING * 2
   c = deck(UBOUND(deck))
   REDIM PRESERVE deck(LBOUND(deck) TO UBOUND(deck) - 1) AS STRING * 2
   deal$ = c

END FUNCTION

SUB setInitialValues (deck() AS STRING * 2)

   DIM L0 AS INTEGER
   RESTORE
   FOR L0 = 0 TO 51
       READ deck(L0)
   NEXT

END SUB

SUB showDeck (deck() AS STRING * 2)

   FOR L% = LBOUND(deck) TO UBOUND(deck)
       PRINT deck(L%); " ";
   NEXT
   PRINT

END SUB

SUB shuffle (deck() AS STRING * 2)

   DIM w AS INTEGER
   DIM shuffled(51) AS STRING * 2
   DIM L0 AS INTEGER
   FOR L0 = 51 TO 0 STEP -1
       w = INT(RND * (L0 + 1))
       shuffled(L0) = deck(w)
       IF w <> L0 THEN deck(w) = deck(L0)
   NEXT
   FOR L0 = 0 TO 51
       deck(L0) = shuffled(L0)
   NEXT

END SUB </lang>

Sample output:

Dealt: 7D
Dealt: 6D
Dealt: KD
Dealt: 8S
5D QH JC JH KC 3S QD 4D 9H 2C JD KH 7H 4H AD 7S 3D 2H 3H 5C 4S AS TD 7C QS 9S 9D
 KS 8H 4C 6H 5H 5S 8D TC AH TS 9C 3C 8C TH 2D QC 6C AC 2S JS 6S
AS 2S 3S 4S 5S 6S 7S 8S 9S TS JS QS KS AH 2H 3H 4H 5H 6H 7H 8H 9H TH JH QH KH AC
 2C 3C 4C 5C 6C 7C 8C 9C TC JC QC KC AD 2D 3D 4D 5D 6D 7D 8D 9D TD JD QD KD

C

(The code lacks some checking, and I have not deeply tested it yet) <lang c>#include <stdio.h>

/* fits into a .h */

  1. include <stdlib.h>
  2. include <string.h>
  1. define N_SUITS 4
  2. define N_PIPS 13
  3. define N_CARDS (N_SUITS*N_PIPS)

enum cardsuit {

 CLUBS, HEARTS, SPADES, DIAMONDS

}; enum cardpip {

 TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT,
 NINE, TEN, JACK, QUEEN, KING, ACE

}; enum decktype {

 EMPTY_DECK, FULL_DECK

};

struct deckcard {

 enum cardsuit suit;
 enum cardpip pip;

}; typedef struct deckcard card_t;

struct deck {

 card_t *refcards[N_CARDS];
 card_t *cards[N_CARDS];
 int icards[N_CARDS];
 int n;

}; typedef struct deck deck_t; /* end of .h */


const char *suits[N_SUITS] = {

 "clubs", "hearts", "spades", "diamonds"

}; const char *pips[N_PIPS] = {

 "2", "3", "4", "5", "6", "7", "8", "9", "10",
 "jack", "queen", "king", "ace"

};

static int rrand(int m) {

 return (int)((double)m * ( rand() / (RAND_MAX+1.0) ));

}

card_t *new_card(enum cardpip p, enum cardsuit s) {

 card_t *c;
 c = malloc(sizeof(card_t));
 c->suit = s; c->pip = p;
 return c;

}

void destroy_card(card_t *c) {

 if ( c != NULL ) free(c);

}

void print_card(card_t *c) {

 printf("(%s,%s)", pips[c->pip], suits[c->suit]);

}

static void generate_fullset(card_t **cset) {

 int suit, pip;
 for(suit=0; suit < N_SUITS; suit++) {
   for(pip=0; pip < N_PIPS; pip++) {
     cset[suit*N_PIPS + pip] = new_card(pip, suit);
   }
 }

}

deck_t *new_deck(enum decktype t) {

 deck_t *d;
 int i;
 d = malloc(sizeof(deck_t));
 if ( d != NULL ) {
   generate_fullset(d->refcards);
   switch(t) {
   case EMPTY_DECK:
     for(i=0; i < N_CARDS; i++) d->cards[i] = NULL;
     d->n = 0;
     break;
   case FULL_DECK:
     for(i=0; i < N_CARDS; i++) {

d->cards[i] = d->refcards[i]; d->refcards[i] = NULL; d->icards[i] = i;

     }
     d->n = N_CARDS;
     break;
   default:
     fprintf(stderr, "hm?\n");
   }
 }
 return d;

}

void destroy_deck(deck_t *d) {

 int i;
 for(i=0; i < N_CARDS; i++) {
   if ( d->refcards[i] != NULL ) free(d->refcards[i]);
   if ( d->cards[i] != NULL ) free(d->cards[i]);
 }
 free(d);

}

void shuffle_deck(deck_t *d) {

 int i, t, r;
 for(i=0; i < d->n; i++) {
   r = rrand(d->n);
   t = d->icards[i];
   d->icards[i] = d->icards[r];
   d->icards[r] = t;
 }

}

card_t *deck_deal(deck_t *d) {

 int c;
 card_t *uc;
 if ( d->n == 0 ) return NULL;
 d->n--;
 c = d->icards[d->n];
 d->refcards[c] = d->cards[c];
 d->cards[c] = NULL;
 /* make a copy for the user */
 uc = new_card(d->refcards[c]->pip, d->refcards[c]->suit);
 return uc;

}

void deck_addcard(deck_t *d, card_t *c) {

 int r;
 int p, s;
 if ( d->n == N_CARDS ) {
   if ( c != NULL ) free(c);
   return;
 }
 if ( c == NULL ) {
   /* add a random card */
   do {
     r=rrand(N_CARDS);
   } while ( d->refcards[r] == NULL );
   d->cards[r] = d->refcards[r];
   d->refcards[r] = NULL;
   d->icards[d->n++] = r;
 } else {
   p = c->pip;
   s = c->suit;
   if ( d->cards[s*N_PIPS + p] == NULL ) {
     d->cards[s*N_PIPS + p] = d->refcards[s*N_PIPS + p];
     d->refcards[s*N_PIPS + p] = NULL;
     d->icards[d->n++] = s*N_PIPS + p;
   }
   free(c);
 }

}

void print_deck(deck_t *d) {

 int i;
 for(i=0; i < d->n; i++) {
   print_card(d->cards[d->icards[i]]);
   printf("\n");
 }

}

/* testing */ int main() {

 deck_t *a_deck;
 card_t *a_card;
 a_deck = new_deck(FULL_DECK);
 shuffle_deck(a_deck);
 a_card = deck_deal(a_deck);
 printf("picked a ");
 print_card(a_card);
 printf("\n\n");
 free(a_card);
 print_deck(a_deck);
 destroy_deck(a_deck);
 return 0;

}</lang>

C++

Works with: g++ version 4.1.2 20061115 (prerelease) (SUSE Linux)

Since all the functions are quite simple, they are all defined inline <lang cpp>#ifndef CARDS_H_INC

  1. define CARDS_H_INC
  1. include <deque>
  2. include <algorithm>
  3. include <ostream>
  4. include <iterator>

namespace cards {

 class card
 {
 public:
   enum pip_type { two, three, four, five, six, seven, eight, nine, ten,
                   jack, queen, king, ace };
   enum suite_type { hearts, spades, diamonds, clubs };
   // construct a card of a given suite and pip
   card(suite_type s, pip_type p): value(s + 4*p) {}
   // construct a card directly from its value
   card(unsigned char v = 0): value(v) {}
   // return the pip of the card
   pip_type pip() { return pip_type(value/4); }
   // return the suit of the card
   suite_type suite() { return suite_type(value%4); }
 private:
   // there are only 52 cards, therefore unsigned char suffices
   unsigned char value;
 };
 char const* const pip_names[] =
   { "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten",
     "jack", "queen", "king", "ace" };
 // output a pip
 std::ostream& operator<<(std::ostream& os, card::pip_type pip)
 {
   return os << pip_names[pip];
 };
 char const* const suite_names[] =
   { "hearts", "spades", "diamonds", "clubs" };
 // output a suite
 std::ostream& operator<<(std::ostream& os, card::suite_type suite)
 {
   return os << suite_names[suite];
 }
 // output a card
 std::ostream& operator<<(std::ostream& os, card c)
 {
   return os << c.pip() << " of " << c.suite();
 }
 class deck
 {
 public:
   // default constructor: construct a default-ordered deck
   deck()
   {
     for (int i = 0; i < 52; ++i)
       cards.push_back(card(i));
   }
   // shuffle the deck
   void shuffle() { std::random_shuffle(cards.begin(), cards.end()); }
   // deal a card from the top
   card deal() { card c = cards.front(); cards.pop_front(); return c; }
   // iterators (only reading access is allowed)
   typedef std::deque<card>::const_iterator const_iterator;
   const_iterator begin() const { return cards.begin(); }
   const_iterator end() const { return cards.end(); }
 private:
   // the cards
   std::deque<card> cards;
 };
 // output the deck
 inline std::ostream& operator<<(std::ostream& os, deck const& d)
 {
   std::copy(d.begin(), d.end(), std::ostream_iterator<card>(os, "\n"));
   return os;
 }

}

  1. endif</lang>

C#

<lang csharp>using System; using System.Linq; using System.Text; using System.Collections.Generic;

class Card {

   string pip;
   string suit;
   public static string[] pips = new string[] { "Two","Three","Four","Five","Six","Seven","Eight",
       "Nine","Ten","Jack","Queen","King","Ace"};
   public static string[] suits = new string[] { "Diamonds", "Spades", "Hearts", "Clubs" };
   public Card(string pip, string suit) {
       this.pip = pip;
       this.suit = suit;
   }
   public override string ToString() {
       return String.Format("{0} of {1}", pip, suit);
   }

}

class Deck {

   public List<Card> deck = new List<Card>();
   public Deck() {
       foreach (string pip in Card.pips) {
           foreach (string suits in Card.suits) {
               deck.Add(new Card(pip, suits));
           }
       }
   }
   public void Shuffle() {
       // HACK: Sort with a custom comparator. (A random number between -1 and 1.)
       Random r = new Random();
       
       try {
           this.deck.Sort(delegate { return r.Next(-1, 1); });
       }
       catch {
           this.Shuffle();
       }       
   }
   public Card Deal() {        
       this.Shuffle();
       
       Card r = this.deck[0];
       this.deck.RemoveAt(0);
       return r;
   }
   public override string ToString() {
       return String.Join("\n", this.deck.Select(x => x.ToString()).ToArray());
   }

}</lang>

Common Lisp

A card is a cons of a suit and a pip. A deck is a list of cards, and so dealing is simply popping off of a deck. Shuffling is naïve, just a sort with a random predicate. Printing is built in.

<lang lisp>(defconstant +suits+

 '(club diamond heart spade)
 "Card suits are the symbols club, diamond, heart, and spade.")

(defconstant +pips+

 '(ace 2 3 4 5 6 7 8 9 10 jack queen king)
 "Card pips are the numbers 2 through 10, and the symbols ace, jack,

queen and king.")

(defun make-deck (&aux (deck '()))

 "Returns a list of cards, where each card is a cons whose car is a

suit and whose cdr is a pip."

 (dolist (suit +suits+ deck)
   (dolist (pip +pips+)
     (push (cons suit pip) deck))))

(defun shuffle (list)

 "Returns a shuffling of list, by sorting it with a random

predicate. List may be modified."

 (sort list #'(lambda (x y)
                (declare (ignore x y))
                (zerop (random 2)))))

</lang>

D

Works with: D version 2.008+

The shuffle algorithm is simplified from Fisher-Yates shuffle The random number generator used is a better generator added at 2.008 release.
Added support for 'extra' card, for example, the Joker, or Major Arcana in Tarot. <lang d>module deck ; import std.random, std.string, std.algorithm, std.stdio ; import std.format : Format = format;

int maxlen(T)(T[] s) { return reduce!(max)(0, map!("a.length")(cast(T[])null,s)) ; }

template DCFG(string s, string p, string x, string c, string d) {

 static const string[] suits = mixin(s) ; 
 static const string[] pips = mixin(p) ;
 static const string[] extras = mixin(x) ;   
 static const string connect = c ;
 static const string dg = d ;
 const int fmtp = maxlen(pips), fmts = maxlen(suits) ;
 const int fmtall = max(fmtp + connect.length + fmts, maxlen(extras)) ;
   
 bool invalid(int p, int s) {
   return (!(p < pips.length && s >= 0 && s < suits.length) && 
     !(s == -1 &&  p - 1 < extras.length)) || p < 0 ;
 }
 string to_s(int p, int s) {
   auto fmt2 = Format("%%%ds", fmtall) ;
   if(s == -1) return Format(fmt2, extras[p - 1]) ;
   auto fmt1 = Format("%%%ds%s%%-%ds",fmtp, connect, fmts) ;
   return Format(fmt2, Format(fmt1, pips[p],suits[s])) ;
 }

}

class Card(alias D : DCFG) {

 const int NSuit = D.suits.length ;
 const int NPip = D.pips.length ;
 const int NExtra = D.extras.length ;
 
 const int pip, suit ; // suit == -1 for extra card
 this(int c) { if(c < 0) this(-c, -1) ;  else this(c % NPip, (c / NPip) % NSuit) ; }
 this(int p, int s) { 
   if(D.invalid(p,s)) throw new Exception("Invalid Card") ;
   pip = p ; suit = s ; 
 }
 string toString() { return D.to_s(pip, suit) ; }
 int order() { mixin(D.dg) ; }
 int opCmp(Card rhs) { return order - rhs.order ; }

}

class Deck(C) {

 alias Deck!(C) DK ;
 private C[] deck ;
 private Mt19937 rnd ; // A MersenneTwisterEngine Random Number Generator
 this(int pack = 1) {
   foreach(p ; 0..pack)
     foreach(int c; -C.NExtra..C.NPip*C.NSuit) addCard(new C(c)) ;
   rnd.seed(unpredictableSeed) ; // default unpredictable seed
 }
 DK addCard(C card) {deck ~= card ; return this ; }
 C peekCard(int deckLoc) { return deck[deckLoc] ; }
 DK dealCard(int deckLoc, Deck toDeck = null) {
   if(!(toDeck is null)) toDeck.addCard(deck[deckLoc]) ;// just discard if no target deck
   foreach(i ; deckLoc..deck.length - 1 ) deck[i] = deck[i+1] ;  // shift 
   deck.length = deck.length - 1 ;
   return this ;
 }
 DK dealTop(Deck toDeck = null) { return dealCard(deck.length - 1, toDeck) ; }
 DK showDeck() { writefln(this.toString) ; return this ; }
 int length() { return deck.length ; }
 string toString() { return Format("%s", deck) ; } 
 DK shuffle() { // Fisher-Yates shuffle algorithm, simplified
   for(int n = length ; n > 1 ; n--) swap(deck[uniform(rnd, 0, n)], deck[n - 1]) ;
   return this ;
 } 
 DK sortDeck() { std.algorithm.sort(deck) ; return this ; }

}

alias DCFG!( // It can be changed to a Tarot config, for example.

 `["Diamond", "Heart", "Club","Spade"]`,
 `["Ace","2","3","4","5","6","7","8","9","Ten","Jack","Queen","King"]`,
 `["*** Joker ***"]`,
 " of ",
 ` if(suit < 0) return suit*pip ;
   int p = pip == 0 ? NPip - 1 : pip - 1 ;
   return p*NSuit + suit ;`) Poker ;

alias Card!(Poker) GameCard ; alias Deck!(GameCard) GameDeck ;

void main() {

 GameDeck[9] guests ; 
 foreach(i,inout g ; guests) g = new GameDeck(0);
 
 GameDeck host = (new GameDeck).addCard(new GameCard(-1)). // add one more Joker
   showDeck.shuffle.showDeck ; // shuffle
 
 while(host.length > 0) 
   foreach(inout g ; guests) if(host.length > 0) host.dealTop(g) ; // deal cards
 foreach(g ; guests) g.sortDeck.showDeck ; // show decks

}</lang>

E

The E language is designed to permit cooperation among multiple mutually suspicious ("untrusted" if you like) programs. Therefore, it is appropriate to design a deck which can be shared without allowing card holders to cheat. In particular, even though the cards are ordinary objects, which can have multiple references to them, nobody should be able to both give away a card and keep it.

Therefore, this implementation adds an extra feature: the take operation on cards, which returns a new reference to a card and invalidates the old one. Therefore, any player or game rule can, when given a card, take sole possession of it.

A "stack" is just a collection of cards, whether a hand or a deck. This implementation does not attempt to simulate the hidden information of a face-down deck, though this would be possible.

<lang e>def makeStack(cardsIn) {

   def cards := cardsIn.diverge()
   def stack {
       to __printOn(out) {
           out.print("<cards: ", cards, ">")
       }
       to shuffle() {
           # Per http://rosettacode.org/wiki/Knuth_shuffle
           for bound in (2..(cards.size())).descending() {
               def i := entropy.nextInt(bound)
               def swapTo := bound - 1
               def t := cards[swapTo]
               cards[swapTo] := cards[i]
               cards[i] := t
           }
       }
       to deal(count :int) {
           def hand := cards.removeRun(0, count)
           return makeStack(hand)
       }
       to size() { return cards.size() }
       to get(index) { return cards.get(index) }
       to take(index :int) {
           def [card] := cards.removeRun(index, index + 1)
           return card
       }
   }
   return stack

}

def makeDeck() {

   interface CardG guards CardS {}
   def Card {
       to coerce(specimen, ejector) {
           def card := CardG.coerce(specimen, ejector)
           if (card.taken()) {
               throw.eject(ejector, `This card has been taken`)
           }
           return card
       }
   }
 
   def makeCard(rank, suit) {
       var taken := false
       def card implements CardS {
           to __printOn(out) {
               out.print(`the $rank of $suit`)
               if (taken) {
                  out.print(" (taken)")
               }
           }
           to take() {
               taken := true
               return makeCard(rank, suit)
           }
           to taken() { return taken }
       }
       return card
   }
   var cards := []
   for suit in ["spades", "hearts", "diamonds", "clubs"] {
       for rank in 1..13 {
           cards with= makeCard(rank, suit)
       }
   }
 
   return [makeStack(cards), Card]

}</lang>

A sample session with a deck, showing dealing and taking:

? def [deck, Card] := makeDeck()
# value: [<cards: [the 1 of spades, the 2 of spades, the 3 of spades, the 4 of spades, the 5 of spades, the 6 of spades, the 7 of spades, the 8 of spades, the 9 of spades, the 10 of spades, the 11 of spades, the 12 of spades, the 13 of spades, the 1 of hearts, the 2 of hearts, the 3 of hearts, the 4 of hearts, the 5 of hearts, the 6 of hearts, the 7 of hearts, the 8 of hearts, the 9 of hearts, the 10 of hearts, the 11 of hearts, the 12 of hearts, the 13 of hearts, the 1 of diamonds, the 2 of diamonds, the 3 of diamonds, the 4 of diamonds, the 5 of diamonds, the 6 of diamonds, the 7 of diamonds, the 8 of diamonds, the 9 of diamonds, the 10 of diamonds, the 11 of diamonds, the 12 of diamonds, the 13 of diamonds, the 1 of clubs, the 2 of clubs, the 3 of clubs, the 4 of clubs, the 5 of clubs, the 6 of clubs, the 7 of clubs, the 8 of clubs, the 9 of clubs, the 10 of clubs, the 11 of clubs, the 12 of clubs, the 13 of clubs].diverge()>, <Card>]

? def hand := deck.deal(5)
# value: <cards: [the 1 of spades, the 2 of spades, the 3 of spades, the 4 of spades, the 5 of spades].diverge()>

? def card := hand.take(0)
# value: the 1 of spades

? hand
# value: <cards: [the 2 of spades, the 3 of spades, the 4 of spades, the 5 of spades].diverge()>

? def card2 := card.take()
# value: the 1 of spades

? card
# value: the 1 of spades (taken)

? card2 :Card
# value: the 1 of spades

? card :Card
# problem: This card has been taken

Forth

Works with: GNU Forth
require random.fs   \ RANDOM ( n -- 0..n-1 ) is called CHOOSE in other Forths

create pips  s" A23456789TJQK" mem,
create suits s" DHCS"          mem, \ diamonds, hearts, clubs, spades
: .card ( c -- )
  13 /mod swap
  pips  + c@ emit
  suits + c@ emit ;

create deck 52 allot
variable dealt

: new-deck
  52 0        do i deck i + c!             loop  0 dealt ! ;
: .deck
  52 dealt @ ?do   deck i + c@ .card space loop  cr ;
: shuffle
  51 0 do
    52 i - random i + ( rand-index ) deck +
    deck i + c@  over c@
    deck i + c!  swap c!
  loop ;
: cards-left ( -- n ) 52 dealt @ - ;
: deal-card ( -- c )
  cards-left 0= abort" Deck empty!"
  deck dealt @ + c@  1 dealt +! ;
: .hand ( n -- )
  0 do deal-card .card space loop cr ;

new-deck shuffle .deck
5 .hand
cards-left .  \ 47

Fortran

Works with: Fortran version 90 and later

<lang fortran> MODULE Cards

IMPLICIT NONE

  TYPE Card
    CHARACTER(5) :: value
    CHARACTER(8) :: suit
  END TYPE Card

  TYPE(Card) :: deck(52), hand(52)
  TYPE(Card) :: temp

  CHARACTER(5) :: pip(13) = (/"Two  ", "Three", "Four ", "Five ", "Six  ", "Seven", "Eight", "Nine ", "Ten  ", &
                              "Jack ", "Queen", "King ", "Ace  "/)
  CHARACTER(8) :: suits(4) = (/"Clubs   ", "Diamonds", "Hearts  ", "Spades  "/)
  INTEGER :: i, j, n, rand, dealt = 0
  REAL :: x

CONTAINS
 
  SUBROUTINE Init_deck
  ! Create deck
    DO i = 1, 4
      DO j = 1, 13
        deck((i-1)*13+j) = Card(pip(j), suits(i))
      END DO
    END DO
  END SUBROUTINE Init_deck
 
  SUBROUTINE Shuffle_deck
  ! Shuffle deck using Fisher-Yates algorithm
    DO i = 52-dealt, 1, -1
      CALL RANDOM_NUMBER(x)
      rand = INT(x * i) + 1
      temp = deck(rand)
      deck(rand) = deck(i)
      deck(i) = temp
    END DO
  END SUBROUTINE Shuffle_deck

  SUBROUTINE Deal_hand(number)
  ! Deal from deck to hand
    INTEGER :: number
    DO i = 1, number
      hand(i) = deck(dealt+1)
      dealt = dealt + 1
    END DO
  END SUBROUTINE

  SUBROUTINE Print_hand
  ! Print cards in hand
    DO i = 1, dealt
      WRITE (*, "(3A)") TRIM(deck(i)%value), " of ", TRIM(deck(i)%suit)
    END DO
    WRITE(*,*)
  END SUBROUTINE Print_hand
 
  SUBROUTINE Print_deck
  ! Print cards in deck
    DO i = dealt+1, 52
      WRITE (*, "(3A)") TRIM(deck(i)%value), " of ", TRIM(deck(i)%suit)
    END DO
    WRITE(*,*)
  END SUBROUTINE Print_deck

END MODULE Cards</lang>

Example use: <lang fortran> PROGRAM Playing_Cards

  USE Cards
 
  CALL Init_deck
  CALL Shuffle_deck
  CALL Deal_hand(5)
  CALL Print_hand
  CALL Print_deck
  
END PROGRAM</lang>

This creates a new deck, shuffles it, deals five cards to hand, prints the cards in hand and then prints the cards remaining in the deck.

Haskell

Straightforward implementation with explicit names for pips and suits. A deck is just a list of cards. Dealing consists of splitting off cards from the beginning of the list by the usual pattern matching (not shown). Printing is automatic. Purely functional shuffling is a bit tricky, so here we just do the naive quadratic version. This also works for other than full decks.

import System.Random

data Pip = Two | Three | Four | Five | Six | Seven | Eight | Nine | Ten | 
           Jack | Queen | King | Ace 
  deriving (Ord, Enum, Bounded, Eq, Show)

data Suit = Diamonds | Spades | Hearts | Clubs
  deriving (Ord, Enum, Bounded, Eq, Show)

type Card = (Pip, Suit)

fullRange :: (Bounded a, Enum a) => [a]
fullRange = [minBound..maxBound]

fullDeck :: [Card]
fullDeck = [(pip, suit) | pip <- fullRange, suit <- fullRange]

insertAt :: Int -> a -> [a] -> [a]
insertAt 0 x ys     = x:ys
insertAt n _ []     = error "insertAt: list too short"
insertAt n x (y:ys) = y : insertAt (n-1) x ys

shuffle :: RandomGen g => g -> [a] -> [a]
shuffle g xs = shuffle' g xs 0 [] where
  shuffle' g []     _ ys = ys
  shuffle' g (x:xs) n ys = shuffle' g' xs (n+1) (insertAt k x ys) where
    (k,g') = randomR (0,n) g

J

Note 'playingcards.ijs'
This is a class script.
Multiple decks may be used, one for each instance of this class.
)

coclass 'rcpc'   NB. Rosetta Code playing cards class

create=: 3 : 0
 N0=: > ;:'Ace Two Three Four Five Six Seven Eight Nine Ten Jack Queen King'
 N1=: > ;:'Spades Hearts Diamonds Clubs'
 DeckPrototype=: |. ,/(i.#N0),."1 0 i.#N1
 sayCards=: ((N0{~{.),' of ',(N1{~{:))"1
 startNewDeck''
)

destroy=: codestroy

startNewDeck=: 3 : 0
 1: TheDeck=: DeckPrototype
)

shuffle=: 3 : 0
 1: TheDeck=: TheDeck {~ ?~ # TheDeck
)

dealCards=: 3 : 0
 {. 1 dealCards y
:
 assert. (# TheDeck) >: ToBeDealt=. x*y
 CardsOffTop=. ToBeDealt {. TheDeck
 TheDeck    =: ToBeDealt }. TheDeck
 (1 0 2)|:(y,x)$ CardsOffTop
)
Note 'dealCards'
Left parameter (x) is number of players, with default to one.
Right parameter (y) is number of cards to be dealt to each player.
Used monadically, the player-axis is omitted from output.
)

pcc=: 3 : 0   NB. "Print" current contents of the deck.
 sayCards TheDeck
)

Example use:

   load 'coutil'
   load 'c:\documents and settings\user_name\j602-user\playingcards.ijs'
   pc=: '' conew 'rcpc'
   $TheDeck__pc
52 2
   shuffle__pc''
1
   sayCards__pc 2 dealCards__pc 5   NB. deal two hands of five cards
Nine  of Hearts  
Three of Clubs   
Seven of Clubs   
Ten   of Hearts  
Three of Diamonds

Seven of Diamonds
Nine  of Spades  
King  of Diamonds
Queen of Hearts  
Six   of Clubs   
   $TheDeck__pc   NB. deck size has been reduced by the ten cards dealt
42 2
   destroy__pc ''
1

Java

Works with: Java version 1.5+

<lang java>public enum Pip { Two, Three, Four, Five, Six, Seven,

   Eight, Nine, Ten, Jack, Queen, King, Ace }</lang>

<lang java>public enum Suit { Diamonds, Spades, Hearts, Clubs }</lang>

The card: <lang java>public class Card {

   private final Suit suit;
   private final Pip value;
   public Card(Suit s, Pip v) {
       suit = s;
       value = v;
   }
   public String toString() {
       return value + " of " + suit;
   }

}</lang> The deck: <lang java>import java.util.Collections; import java.util.LinkedList;

public class Deck {

   private final LinkedList<Card> deck= new LinkedList<Card>();
   public Deck() {
       for (Suit s : Suit.values())
           for (Pip v : Pip.values())
               deck.add(new Card(s, v));
   }
   public Card deal() {
       return deck.poll();
   }
   public void shuffle() {
       Collections.shuffle(deck); // I'm such a cheater
   }
   public String toString(){
       return deck.toString();
   }

}</lang>

JavaScript

<lang javascript> function Card(pip, suit) {

   this.pip = pip;
   this.suit = suit; 
   this.toString = function () {
       return this.pip + ' ' + this.suit;
   };

}

function Deck() {

   var pips = '2 3 4 5 6 7 8 9 10 Jack Queen King Ace'.split(' ');
   var suits = 'Clubs Hearts Spades Diamonds'.split(' ');
   this.deck = [];
   for (var i = 0; i < suits.length; i++)
       for (var j = 0; j < pips.length; j++)
           this.deck.push(new Card(pips[j], suits[i]));
   this.toString = function () {
       return '[' + this.deck.join(', ') + ']';
   };

   this.shuffle = function () {
       for (var i = 0; i < this.deck.length; i++)
           this.deck[i] = this.deck.splice(
               parseInt(this.deck.length * Math.random()), 1, this.deck[i])[0];
   };
   this.deal = function () {
       return this.deck.shift();
   };

} </lang>

Works with: UCB Logo

<lang logo> make "suits {Diamonds Hearts Clubs Spades} make "pips {Ace Two Three Four Five Six Seven Eight Nine Ten Jack Queen King}

to card :n

 output (sentence item 1 + modulo :n 13 :pips  "of  item 1 + int quotient :n 13 :suits)

end

to new.deck

 make "deck listtoarray iseq 0 51
 make "top 1

end

to swap :i :j :a

 localmake "t item :i :a
 setitem :i :a item :j :a
 setitem :j :a :t

end to shuffle.deck

 for [i [count :deck] 2] [swap 1 + random :i :i :deck]

end

to show.deck

 for [i :top [count :deck]] [show card item :i :deck]

end

to deal.card

 show card item :top :deck
 make "top :top + 1

end

new.deck shuffle.deck repeat 5 [deal.card] </lang>

M4

<lang M4> define(`randSeed',141592653)dnl define(`setRand',

  `define(`randSeed',ifelse(eval($1<10000),1,`eval(20000-$1)',`$1'))')dnl

define(`rand_t',`eval(randSeed^(randSeed>>13))')dnl define(`random',

  `define(`randSeed',eval((rand_t^(rand_t<<18))&0x7fffffff))randSeed')dnl

define(`for',

  `ifelse($#,0,``$0,
  `ifelse(eval($2<=$3),1,
  `pushdef(`$1',$2)$4`'popdef(`$1')$0(`$1',incr($2),$3,`$4')')')')dnl

define(`foreach', `pushdef(`$1')_foreach($@)popdef(`$1')')dnl define(`_arg1', `$1')dnl define(`_foreach', `ifelse(`$2', `()', `',

  `define(`$1', _arg1$2)$3`'$0(`$1', (shift$2), `$3')')')dnl

define(`new',`define(`$1[size]',0)')dnl define(`append',

  `define(`$1[size]',incr(defn(`$1[size]')))`'define($1[defn($1[size])],$2)')

define(`deck',

  `new($1)foreach(`x',(Ace,2,3,4,5,6,7,8,9,10,Jack,Queen,King),
     `foreach(`y',(Clubs,Diamonds,Hearts,Spades),
        `append(`$1',`x of y')')')')dnl

define(`show',

  `for(`x',1,defn($1[size]),`defn($1[x])ifelse(x,defn($1[size]),`',`, ')')')dnl

define(`swap',`define($1[$2],defn($1[$4]))define($1[$4],$3)')dnl define(`shuffle',

  `for(`x',1,defn($1[size]),
     `swap($1,x,defn($1[x]),eval(1+random%defn($1[size])))')')dnl

define(`deal',

  `ifelse($#,0,``$0,
  `ifelse(defn($1[size]),0,
     `NULL',
     defn($1[defn($1[size])])define($1[size],decr(defn($1[size]))))')')dnl

dnl deck(`b') show(`b') shuffling shuffle(`b') show(`b') deal deal(`b') deal deal(`b') show(`b') </lang>

OCaml

Straightforward implementation with algebraic types for the pips and suits, and lists of their values. A deck is an array of cards. <lang ocaml>type pip = Two | Three | Four | Five | Six | Seven | Eight | Nine | Ten |

          Jack | Queen | King | Ace 

let pips = [Two; Three; Four; Five; Six; Seven; Eight; Nine; Ten;

           Jack; Queen; King; Ace]

type suit = Diamonds | Spades | Hearts | Clubs let suits = [Diamonds; Spades; Hearts; Clubs]

type card = pip * suit

let full_deck = Array.of_list (List.concat (List.map (fun pip -> List.map (fun suit -> (pip, suit)) suits) pips))

(* Fisher-Yates shuffle *) let shuffle deck =

 for i = Array.length deck - 1 downto 1 do
   let j = Random.int (i+1) in
   (* swap deck.(i) and deck.(j) *)
   let temp = deck.(i) in
   deck.(i) <- deck.(j);
   deck.(j) <- temp
 done</lang>

Perl

<lang perl>package Playing_Card_Deck;

use strict;

@Playing_Card_Deck::suits = qw

  [Diamonds Clubs Hearts Spades];

@Playing_Card_Deck::pips = qw

  [Two Three Four Five Six Seven Eight Nine Ten
   Jack King Queen Ace];
  1. I choose to fully qualify these names rather than declare them
  2. with "our" to keep them from escaping into the scope of other
  3. packages in the same file. Another possible solution is to use
  4. "our" or "my", but to enclose this entire package in a bare block.

sub new

  1. Creates a new deck-object. The cards are initially neatly ordered.
{my $invocant = shift;
 my $class = ref($invocant) || $invocant;
 my @cards = ();
 foreach my $suit (@Playing_Card_Deck::suits)
    {foreach my $pip (@Playing_Card_Deck::pips)
        {push(@cards, {suit => $suit, pip => $pip});}}
 return bless([@cards], $class);}

sub deal

  1. Removes the top card of the given deck and returns it as a hash
  2. with the keys "suit" and "pip".
{return %{ shift( @{shift(@_)} ) };}

sub shuffle

  1. Randomly permutes the cards in the deck. It uses the algorithm
  2. described at:
  3. http://en.wikipedia.org/wiki/Fisher-Yates_shuffle#The_modern_algorithm
{our @deck; local *deck = shift;
   # @deck is now an alias of the invocant's referent.
 for (my $n = $#deck ; $n ; --$n)
    {my $k = int rand($n + 1);
     @deck[$k, $n] = @deck[$n, $k] if $k != $n;}}

sub print_cards

  1. Prints out a description of every card in the deck, in order.
{print "$_->{pip} of $_->{suit}\n" foreach @{shift(@_)};}</lang>

Some examples of use: <lang perl>my $deck = new Playing_Card_Deck; $deck->shuffle; my %card = $deck->deal; print uc("$card{pip} OF $card{suit}\n"); $deck->print_cards;</lang> This creates a new deck, shuffles it, removes the top card, prints out that card's name in all caps, and then prints the rest of the deck.

Python

<lang python>import random

class Card(object):

   suits = ("Clubs","Hearts","Spades","Diamonds")
   pips = ("2","3","4","5","6","7","8","9","10","Jack","Queen","King","Ace")
   def __init__(self, pip,suit):
       self.pip=pip
       self.suit=suit
   def __str__(self):
       return "%s %s"%(self.pip,self.suit)

class Deck(object):

   def __init__(self):
       self.deck = [Card(pip,suit) for suit in Card.suits for pip in Card.pips]
   def __str__(self):
       return "[%s]"%", ".join( (str(card) for card in self.deck))
   def shuffle(self):
       random.shuffle(self.deck)
   def deal(self):
       self.shuffle()  # Can't tell what is next from self.deck
       return self.deck.pop(0)

</lang>

R

<lang R> pips <- c("2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King", "Ace") suit <- c("Clubs", "Diamonds", "Hearts", "Spades")

  1. Create a deck

deck <- data.frame(pips=rep(pips, 4), suit=rep(suit, each=13))

shuffle <- function(deck) {

  n <- nrow(deck)
  ord <- sample(seq_len(n), size=n)
  deck[ord,]

}

deal <- function(deck, fromtop=TRUE) {

  index <- ifelse(fromtop, 1, nrow(deck))
  print(paste("Dealt the", deck[index, "pips"], "of", deck[index, "suit"]))
  deck[-index,]   

}

  1. Usage

deck <- shuffle(deck) deck deck <- deal(deck)

  1. While no-one is looking, sneakily deal a card from the bottom of the pack

deck <- deal(deck, FALSE) </lang>

Ruby

Translation of: Python
Works with: Ruby version 1.8.7+

<lang ruby>class Card

   # class constants
   Suits = ["Clubs","Hearts","Spades","Diamonds"]
   Pips = ["2","3","4","5","6","7","8","9","10","Jack","Queen","King","Ace"]
   
   # class variables (private)
   @@suit_value = Hash[ Suits.each_with_index.to_a ]
   @@pip_value = Hash[ Pips.each_with_index.to_a ]
   
   attr_reader :pip, :suit

   def initialize(pip,suit)
       @pip = pip
       @suit = suit
   end

   def to_s
       "#{@pip} #{@suit}"
   end
   
   # allow sorting an array of Cards: first by suit, then by value
   def <=>(card)
       (@@suit_value[@suit] <=> @@suit_value[card.suit]).nonzero? or \
        @@pip_value[@pip] <=> @@pip_value[card.pip]
   end

end

class Deck

   def initialize
       @deck = []
       for suit in Card::Suits
           for pip in Card::Pips
               @deck << Card.new(pip,suit)
           end
       end
   end

   def to_s
       "[#{@deck.join(", ")}]"
   end

   def shuffle!
       @deck.shuffle!
       self
   end

   def deal(*args)
       @deck.shift(*args)
   end

end

deck = Deck.new.shuffle! puts card = deck.deal hand = deck.deal(5) puts hand.join(", ") puts hand.sort.join(", ")</lang>

10 Clubs
8 Diamonds, Queen Clubs, 10 Hearts, 6 Diamonds, 4 Clubs
4 Clubs, Queen Clubs, 6 Diamonds, 8 Diamonds, 10 Hearts

Smalltalk

Works with: GNU Smalltalk

<lang smalltalk>Object subclass: #Card

 instanceVariableNames: 'thePip theSuit'
 classVariableNames: 'pips suits'
 poolDictionaries: 
 category: nil !

!Card class methods! initialize

 suits ifNil: [ suits := ('clubs,hearts,spades,diamonds' subStrings: $,) ].
 pips ifNil: [ pips := ('2,3,4,5,6,7,8,9,10,jack,queen,king,ace' subStrings: $,) ]

! new

 | o |
 o := super new.
 ^o

! new: card

 | o |
 o := self new.
 o initWithPip: (card at: 1) andSuit: (card at: 2).
 ^o

!!

!Card class methods ! pips

 Card initialize.
 ^pips

! suits

 Card initialize.
 ^suits

!!

!Card methods! initWithPip: aPip andSuit: aSuit

 ( (pips includes: (aPip asLowercase)) &
   (suits includes: (aSuit asLowercase)) )
    ifTrue: [
         thePip := (aPip copy).
         theSuit := (aSuit copy)
    ] ifFalse: [ 'Unknown pip or suit' displayOn: stderr .
                 Character nl displayOn: stderr ].
 ^self

! asString

 ^('(%1,%2)' % { thePip . theSuit })

! display

 (self asString) display

! displayNl

 self display.
 Character nl display

!!


Object subclass: #Deck

 instanceVariableNames: 'deck'
 classVariableNames: 
 poolDictionaries: 
 category: nil !

!Deck class methods ! new

 |d|
 d := super new.
 d init.
 ^d

!!

!Deck methods ! init

  deck := OrderedCollection new.
  (Card suits) do: [ :suit |
    (Card pips) do: [ :pip |
        deck add: (Card new: { pip . suit })
    ]
  ]

! deck

 ^deck

! shuffle

 1 to: (self deck size) do: [ :i |
    |r2 o|
    r2 := (Random between: 1 and: (self deck size)).
    o := (self deck) at: i.
    (self deck) at: i put: ((self deck) at: r2).
    (self deck) at: r2 put: o 
 ].
 ^self

! display

 self deck do: [ :card |
    card displayNl
 ]

! deal

 ^self deck removeFirst

!!

"create a deck, shuffle it, remove the first card and display it" Deck new shuffle deal displayNl.</lang>

Note: there's something odd with the class method for getting pips and suits; it's because I've not understood how to initialize class variables to certain values without the need to explicitly call a method to do so.

Tcl

<lang tcl>package require Tcl 8.5

namespace eval playing_cards {

   variable deck
   #variable suits {C D H S}
   variable suits {\u2663 \u2662 \u2661 \u2660}
   variable pips {2 3 4 5 6 7 8 9 10 J Q K A}
   
   proc new_deck {} {
       variable deck
       set deck [list]
       for {set i 0} {$i < 52} {incr i} {
           lappend deck $i
       }
   }
   
   proc shuffle {} {
       variable deck
       # shuffle in place
       for {set i 51} {$i > 0} {incr i -1} {
           set n [expr {int($i * rand())}]
           set card [lindex $deck $n]
           lset deck $n [lindex $deck $i]
           lset deck $i $card
       }
   }
   
   proc deal Template:Num 1 {
       variable deck
       incr num -1
       set cards [lrange $deck 0 $num]
       set deck [lreplace $deck 0 $num]
       return $cards
   }
   
   proc card2string {card} {
       variable suits
       variable pips
       set suit [expr {$card / 13}]
       set pip [expr {$card % 13}]
       return [format "%2s %s" [lindex $pips $pip] [lindex $suits $suit]]
   }
   
   proc print {cards args} {
       array set opts [concat -sort false $args]
       if {$opts(-sort)} {
           set cards [lsort -integer $cards]
       }
       foreach card $cards {
           puts [card2string $card]
       }
   }
   
   proc print_deck {} {
       variable deck
       print $deck
   }

}

playing_cards::new_deck playing_cards::shuffle set hand [playing_cards::deal 5] puts "my hand:" playing_cards::print $hand -sort true puts "\nthe deck:" playing_cards::print_deck</lang>

Vedit macro language

The deck is created in a free edit buffer, one line for each card. Each users hand is another edit buffer. There is no need for any routines to display the deck or a hand, since each of them is displayed in an edit window. <lang vedit> // Playing Cards, main program

Call("CREATE_DECK") Call("SHUFFLE_DECK")

  1. 21 = Buf_Switch(Buf_Free) // #21 = players hand, 1st player
  2. 1 = 5; Call("DEAL_CARDS") // deal 5 cards to player 1
  3. 22 = Buf_Switch(Buf_Free) // #22 = players hand, 2nd player
  4. 1 = 5; Call("DEAL_CARDS") // deal 5 cards to player 2

Buf_Switch(#10) BOF // display the deck Return

/////////////////////////////////////////////////////////////////////////// // // Create a deck into a new edit buffer. One text line for each card. //

CREATE_DECK:
  1. 10 = Buf_Switch(Buf_Free) // Buffer @(#10) = the deck

RS(1, "Diamonds") RS(2, "Spades") RS(3, "Hearts") RS(4, "Clubs")

RS(11, " Jack") RS(12, "Queen") RS(13, " King") RS(14, " Ace")

for (#1=1; #1<5; #1++) {

   for (#2=2; #2<15; #2++) {
       if (#2 < 11) {
           Num_Ins(#2, NOCR)     // pip (2 to 10) as numeric
       } else {
           IT(@(#2))             // pip (11 to 14) as a word
       }
       IT(" of ")
       IT(@(#1)) IN              // suit
   }

} Return

/////////////////////////////////////////////////////////////////////////// // // Shuffle the deck using Fisher-Yates algorithm //

SHUFFLE_DECK:

Buf_Switch(#10) // the deck

  1. 90 = Time_Tick // seed for random number generator
  2. 91 = 51 // random numbers in range 0 to 50

for (#1=1; #1<52; #1++) {

   Call("RANDOM")
   Goto_Line(Return_Value+1)
   Block_Copy(#1, #1, LINESET+DELETE)
   Reg_Copy(9, 1, DELETE)
   Goto_Line(#1)
   Reg_Ins(9)

} Return

//-------------------------------------------------------------- // Generate random numbers in range 0 <= Return_Value < #91 // #90 = Seed (0 to 0x7fffffff) // #91 = Scaling (0 to 0x10000)

RANDOM:
  1. 92 = 0x7fffffff / 48271
  2. 93 = 0x7fffffff % 48271
  3. 90 = (48271 * (#90 % #92) - #93 * (#90 / #92)) & 0x7fffffff

Return ((#90 & 0xffff) * #91 / 0x10000)


/////////////////////////////////////////////////////////////////////////// // // Deal #1 cards: move the cards from deck to current edit buffer //

DEAL_CARDS:
  1. 11 = Buf_Num // this buffer (players hand)

Buf_Switch(#10) // the deck BOF Reg_Copy(9, #1, DELETE) // pull the first #1 cards from the deck Buf_Switch(#11) // players hand Reg_ins(9) // insert the cards here Return </lang>