You’ll find the [fphp]shuffle[/fphp] function useful.
Using numbers 1 through 52 for the cards you can use math to determine face and suit. Let $c be the number of any given card.
ceil($c / 13) returns 1 to 4, suites in alphabetical order (club, diamond, heart, spade)
($c % 13) + 1 returns face value.
This way you don’t need to try to encode the card information. You still need an array to track who has which card. To help with that I’ll give you a foundational class to work with, ReadOnlyArray.
ReadOnlyArray implements iteration, array access, countable and so, as an object it can act like an array in many ways. By extending it you can add behaviors specific to your planned deck and player classes.
Note, unlike PHP’s internal ArrayObject, ReadOnlyArray only protects its storage, it doesn’t declare it as private. As a result your extending classes can modify the storage as needed for your methods. Here’s the class.
<?php
namespace Gazelle;
/**
* ReadOnlyArray
*
* What it says on the tin - An array that cannot be written to.
* Extended by children which change themselves in special ways.
*
* Why not use ArrayObject? Well, most noticably is that in order
* to enforce non-writability you'll end up overriding more methods
* than this implements. Second, this class' storage is merely
* protected instead of being private as it is with ArrayObject.
* This gives you a bit more flexibility when extending.
*
* All methods of this class are required by its interfaces. See
* PHP.net for more information on them and their precise purpose.
*
* @author Michael
* @package Gazelle Core
*
*/
class ReadOnlyArray implements \\Iterator, \\ArrayAccess, \\Countable, \\Serializable {
/**
* Current Index of storage.
* @var mixed
*/
protected $index = '';
/**
* The array of data that we shield to make it ReadOnly by the
* rest of the API except our children.
* @var array
*/
protected $storage = array();
/**
* CONSTRUCT - take an array and bind to storage. This is the
* only time this class can be written to from the outside.
* @param $array
*/
public function __construct(array $array ) {
$this->storage = $array;
reset($this->storage);
$this->index = key($this->storage);
}
/**
* ITERATOR implementation. Sets index to first element.
*/
public function rewind() {
reset($this->storage);
}
/**
* ITERATOR implementation. Returns current value.
*/
public function current() {
return $this->storage[ $this->index ];
}
/**
* ITERATOR implementation. Returns current key.
*/
public function key() {
return $this->index;
}
/**
* ITERATOR implementation. Advance index to next element.
*/
public function next() {
next($this->storage);
$this->index = key($this->storage);
}
/**
* ITERATOR implementation. Detects end of array.
*/
public function valid() {
return isset($this->storage[$this->index]);
}
/**
* ARRAY ACCESS implementation. Set a value - disabled.
* @param string $offset
* @param mixed $value
* @throws Exception
*/
public function offsetSet($offset, $value) {
throw new Exception('You cannot write values to a Read Only Array after it is created.');
}
/**
* ARRAY ACCESS implementation. Detect if an element is set.
* @param $offset
*/
public function offsetExists($offset) {
return isset( $this->storage[$offset] );
}
/**
* ARRAY ACCESS implementation. Unset a value - disabled.
* @param string $offset
* @throws Exception
*/
public function offsetUnset($offset) {
throw new Exception('You cannot delete values from a Read Only Array after it is created.');
}
/**
* ARRAY ACCESS implementation. Get a value.
* @param $offset
* @throws Exception
*/
public function offsetGet($offset) {
if ( isset($this->storage[$offset] )) {
return $this->storage[$offset];
} else {
throw new Exception("$offset does not exist");
}
}
/**
* COUNTABLE implementation
*/
public function count() {
return count($this->storage);
}
/**
* SERIALIZABLE implementation
*/
public function serialize() {
return serialize($this->storage);
}
/**
* SERIALIZABLE implementation
* @param $data
*/
public function unserialize( $data ) {
$this->storage = unserialize($data);
}
/**
* Return the stored array. Method name matches it's equivalent in ArrayObject.
*/
public function getArrayCopy() {
return $this->storage;
}
}
Finally, when manipulating that storage you can use array_shift to “draw” off the top of the array.
I would begin from here with a “stack” class representing a stack of cards. A deck is one such stack, and so is a player’s hand. Methods common to both (receiving cards, giving cards) go to this class before doing the either the deck or player.