RosettaCodeData/Task/Playing-cards/PHP/playing-cards-1.php

277 lines
5.8 KiB
PHP

class Card
{
// if unable to save as UTF-8, use other, non-UTF-8, symbols here
protected static $suits = array( '♠', '♥', '♦', '♣' );
protected static $pips = array( '2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A' );
protected $suit;
protected $suitOrder;
protected $pip;
protected $pipOrder;
protected $order;
public function __construct( $suit, $pip )
{
if( !in_array( $suit, self::$suits ) )
{
throw new InvalidArgumentException( 'Invalid suit' );
}
if( !in_array( $pip, self::$pips ) )
{
throw new InvalidArgumentException( 'Invalid pip' );
}
$this->suit = $suit;
$this->pip = $pip;
}
public function getSuit()
{
return $this->suit;
}
public function getPip()
{
return $this->pip;
}
public function getSuitOrder()
{
// lazy evaluate suit order
if( !isset( $this->suitOrder ) )
{
// cache suit order
$this->suitOrder = array_search( $this->suit, self::$suits );
}
return $this->suitOrder;
}
public function getPipOrder()
{
// lazy evaluate pip order
if( !isset( $this->pipOrder ) )
{
// cache pip order
$this->pipOrder = array_search( $this->pip, self::$pips );
}
return $this->pipOrder;
}
public function getOrder()
{
// lazy evaluate order
if( !isset( $this->order ) )
{
$suitOrder = $this->getSuitOrder();
$pipOrder = $this->getPipOrder();
// cache order
$this->order = $pipOrder * count( self::$suits ) + $suitOrder;
}
return $this->order;
}
public function compareSuit( Card $other )
{
return $this->getSuitOrder() - $other->getSuitOrder();
}
public function comparePip( Card $other )
{
return $this->getPipOrder() - $other->getPipOrder();
}
public function compare( Card $other )
{
return $this->getOrder() - $other->getOrder();
}
public function __toString()
{
return $this->suit . $this->pip;
}
public static function getSuits()
{
return self::$suits;
}
public static function getPips()
{
return self::$pips;
}
}
class CardCollection
implements Countable, Iterator
{
protected $cards = array();
protected function __construct( array $cards = array() )
{
foreach( $cards as $card )
{
$this->addCard( $card );
}
}
/**
* Countable::count() implementation
*/
public function count()
{
return count( $this->cards );
}
/**
* Iterator::key() implementation
*/
public function key()
{
return key( $this->cards );
}
/**
* Iterator::valid() implementation
*/
public function valid()
{
return null !== $this->key();
}
/**
* Iterator::next() implementation
*/
public function next()
{
next( $this->cards );
}
/**
* Iterator::current() implementation
*/
public function current()
{
return current( $this->cards );
}
/**
* Iterator::rewind() implementation
*/
public function rewind()
{
reset( $this->cards );
}
public function sort( $comparer = null )
{
$comparer = $comparer ?: function( $a, $b ) {
return $a->compare( $b );
};
if( !is_callable( $comparer ) )
{
throw new InvalidArgumentException( 'Invalid comparer; comparer should be callable' );
}
usort( $this->cards, $comparer );
return $this;
}
public function toString()
{
return implode( ' ', $this->cards );
}
public function __toString()
{
return $this->toString();
}
protected function addCard( Card $card )
{
if( in_array( $card, $this->cards ) )
{
throw new DomainException( 'Card is already present in this collection' );
}
$this->cards[] = $card;
}
}
class Deck
extends CardCollection
{
public function __construct( $shuffled = false )
{
foreach( Card::getSuits() as $suit )
{
foreach( Card::getPips() as $pip )
{
$this->addCard( new Card( $suit, $pip ) );
}
}
if( $shuffled )
{
$this->shuffle();
}
}
public function deal( $amount = 1, CardCollection $cardCollection = null )
{
if( !is_int( $amount ) || $amount < 1 )
{
throw new InvalidArgumentException( 'Invalid amount; amount should be an integer, larger than 0' );
}
if( $amount > count( $this->cards ) )
{
throw new RangeException( 'Invalid amount; requested amount is larger than the amount of available cards' );
}
$cards = array_splice( $this->cards, 0, $amount );
$cardCollection = $cardCollection ?: new CardCollection;
foreach( $cards as $card )
{
$cardCollection->addCard( $card );
}
return $cardCollection;
}
public function shuffle()
{
shuffle( $this->cards );
}
}
class Hand
extends CardCollection
{
// override CardCollection __constructor
// to allow public instantiation
// but disallow instantiation with cards
public function __construct() {}
public function play( $position )
{
if( !isset( $this->cards[ $position ] ) )
{
throw new OutOfBoundsException( 'Invalid position; position is not present in this hand' );
}
$result = array_splice( $this->cards, $position, 1 );
return $result[ 0 ];
}
}