1.0.6 • Published 4 years ago

@slithy/deck-of-52 v1.0.6

Weekly downloads
-
License
ISC
Repository
-
Last release
4 years ago

Deck of 52

A generic deck of cards, fashioned as a React context, with a hooks-based interface.

The context generates a deck, and keeps track of cards as they move through the course of playing a game. The particulars of game logic or players are of no concern to the deck itself.

On initializing a game, the deck is built, then shuffled to create the draw collection.

Using utility methods, the game may create additional collections to represent hands, piles, stacks, etc., and may move cards between them.

For example, a card may be dealt from the draw pile, into a player's hand. Later, that card may be move from the players hand, into the discard pile. Eventually, the discard pile might be shuffled back into draw to replenish the game. In the abstract, in each case we are moving a card from one collection to another.


Usage

To get started, wrap your application, or just the game logic, in the DeckOfCards context.

import { DeckOfCards } from '@slithy/deck-of-52'

const App = () => (
  <DeckOfCards>
    <Game />
  </DeckOfCards>
)

In the game logic, import the useDeckOfCards hook to access the deck's utility methods. Then initialize the deck in a useEffect.

To kick the game off, interact with the the draw collection.

import React, { useEffect } from 'react'
import { useDeckOfCards } from '@slithy/deck-of-52'

const Game = (props) => {
  const {
    addCollection,
    buildDeck,
    collections,
    deck,
    drawCards,
    moveCard,
    recycleDiscards,
    removeCollection,
    updateCollection,
  } = useDeckOfCards()

  useEffect(() => {
    if (deck.length === 0) {
      buildDeck()
    }
  }, [deck])

  return (
    <div>
      <h1>My Card Game</h1>
      <p>
        Top Card:<br/>
        {collections.draw[0].description}
      </p>
    </div>
  )
}

The State of the Deck

The deck maintains two items in state, deck and collections.

const initialState = {
  deck: [],
  collections: {
    discard: [],
    draw: [],
  },
}

Initially, two collections are predefined, discard and draw. Additional collections may be created to represent hands, piles, stacks, etc. as necessitated by the game.

As one might expect, the draw pile contains unplayed cards. Deal cards from the draw collection into in-play collections, such as player hands, or stacks on the table.

A card, having been played, should be moved into the discard pile. A utility method exists to replenish the draw pile from discard.

Under normal circumstances, the total cards in all collections should be equal to the number of cards in the deck. If cards are somehow lost, however, the deck can be shuffled back into play.


Building the Deck, and the Shape of Cards

The deck is built using the buildDeck method:

buildDeck()

This method optionally accepts an options object, and a callback.

buildDeck({}, deck => deck)

Omitting these, the deck will be built using the standard suits: clubs, diamonds, hearts, spades. In verbose form, this is:

buildDeck({ suits: 'clubs', 'diamonds', 'hearts', 'spades', })

Each suit is built to contain 13 cards, ranging in value from 1 (Ace) to 13 (King). Specifically, this:

{
  1: 'Ace',
  2: 'Two',
  3: 'Three',
  4: 'Four',
  5: 'Five',
  6: 'Six',
  7: 'Seven',
  8: 'Eight',
  9: 'Nine',
  10: 'Ten',
  11: 'Jack',
  12: 'Queen',
  13: 'King',
}

In the resulting deck, each card is an object of the following shape.

{
  description: 'Two of Hearts',
  id: 'hearts-2',
  suit: 'hearts',
  value: 2,
}

As an example, you might wish to create a custom deck for a fantasy card game. Let's use the four elements as suits, limit royalty cards to a value of 10, and add a fourth royalty.

buildDeck({
  suits: ['earth', 'fire', 'water', 'wind'],
}, (deck, options) => {
  // Set all royalty cards' value to 10
  const newDeck = deck.map(card => {
    // Set all royalty cards' value to 10
    if (card.value > 10) {
      card.value = 10
    }
    return card
  })
  // Add a new 'Lord' royalty card for each suit
  const newRoyalty = options.suits.map(suit => {
    return {
      description: `${suit.charAt(0).toUpperCase() + suit.slice(1)} Elemental`,
      id: `${suit}-14`,
      suit,
      value: 11,
    }
  })

  // Return the modified deck + Lord cards
  return newDeck.concat(newRoyalty)
})

And so, we have the potential to draw a "Fire Elemental" with a numeric value of 11, whatever that means for your game. And, with the extra royalty cards added, our deck is 56 cards.


Methods

Listed alphabetically.

addCollection

addCollection( string )

Creates a new collection, using the string as key; accessible as collections string .

The value of the collection is an array, containing cards; on creation, the array is empty.

buildDeck

buildDeck( options, callback )

Used to initialize a new deck for play.

On its own -- buildDeck() -- will create a standard deck of 52 cards, using the suits clubs, diamonds, hearts and spades. Use options to define different or additional suits, and the callback to manipulate the deck or add custom cards.

buildDeck({
  suits: ['clubs', 'diamonds', 'hearts', 'spades'],
  wildcards: ['Red Joker', 'Blue Joker'],
}, (deck, options) => {
  // ... do things with deck ...
  return deck
})

drawCards

drawCards( collection, count = 1 )

Moves a number of cards (count), into the specified collection. Draws a single card by default; the collection name is required.

moveCard

moveCard( card, collection )

Moves a card into the designated collection. To use, pass the entire card object into the card parameter; or, at least an object with a card id.

recycleDiscards

recycleDiscards()

Moves all cards from discard back into draw, then shuffles the draw collection.

removeCollection

removeCollection( collection )

Removes the named collection, and sends any cards therein to discard.

setCollections

setCollections( collections )

Sets collections for the deck. For example, use this to restore collections to a previously saved state.

updateCollection

updateCollection( collection, callback )

Runs the callback on the named collection. For example:

updateCollection(collection, (collection) => {
  return collection.sort((a, b) => a.value - b.value)
})

1.0.6

4 years ago

1.0.5

4 years ago

1.0.4

4 years ago

1.0.3

4 years ago

1.0.2

4 years ago

1.0.1

4 years ago

1.0.0

4 years ago