Карточная игра: случайным образом выбрать 1 номер из 52 без дубликатов - PullRequest
14 голосов
/ 25 октября 2011

У меня есть простая карточная игра (с использованием 52 карт - без джокеров), в которой я хочу выбрать одну карту за раз до тех пор, пока не будет выбрана выигрышная карта.

У меня есть следующий массив:

$cards = array(
    'diamond' => array(
        'A', 2, 3, 4, 5, 6, 7, 8, 9, 10, 'J', 'Q', 'K'
    ),
    'heart' => array(
        'A', 2, 3, 4, 5, 6, 7, 8, 9, 10, 'J', 'Q', 'K'
    ),
    'club' => array(
        'A', 2, 3, 4, 5, 6, 7, 8, 9, 10, 'J', 'Q', 'K'
    ),
    'spades' => array(
        'A', 2, 3, 4, 5, 6, 7, 8, 9, 10, 'J', 'Q', 'K'
    ),
);

Как видите, этот массив отсортирован. Я хотел бы перемешать их, используя функцию PHP shuffle($cards);, но она не сработала.

Что я могу сделать, чтобы получить это суфле?

Ответы [ 5 ]

39 голосов
/ 25 октября 2011

Я бы сделал классы Deck и Card. Карта будет содержать то, что ей подходит, а также ее «номер».Затем вы можете вызвать метод shuffle на Deck, который является просто массивом карт.Таким образом, все карты сортируются независимо от их масти.


[Обновить] Особенности:

  • Теперь вы можете указать функцию перемешивания. Она будет использовать перемешивание PHP, если вы ее не указали.
  • Реструктурированные __construct и reset. Они теперь используютновая функция createDeck, которая использует createSuit для упрощения процесса создания.
  • Добавлена ​​некоторая проверка типов. Это неполная проверка типов, но она должна помочь с несколькими сумасшедшими ошибкамиэто может произойти.
  • Реализует интерфейсы:
    • JsonSerializable. Вызов jsonSerialize вернет данные для сериализации.В PHP 5.4 и выше вы можете вызывать json_encode для объекта, если он реализует этот интерфейс.До этого вы можете позвонить json_encode($deck->jsonSerialize()).
    • Счетный. Вы можете использовать count($deck), чтобы получить размер колоды.
    • ArrayAccess. Давайте рассмотрим объект как массив.
      1. deck[0]->suit вернет масть первой карты колоды.
      2. Вы можете передать колоду любой функции, которая принимает массив в качестве ввода. Если онииспользуйте проверку типов массива, однако она не будет выполнена.
    • IteratorAggregate. Вы можете использовать колоду в цикле foreach.

<?php

if (!interface_exists('JsonSerializable')) {
    interface JsonSerializable {
        /**
         * @return mixed Return data which should be serialized by json_encode().
         */
        function jsonSerialize();
    }
}

class Card implements JsonSerializable {
    /**
     * @var string The suit for the card
     */
    private $suit;

    /**
     * @var string The 'number' of the card.  A bit of a misnomer, A, J, Q, K can be included.
     */
    private $number;

    /**
     * Creates a new cards of suit $suit with number $number.
     * @param string $suit
     * @param string $number
     * @throws InvalidArgumentException if $suit is not a string.
     * @throws InvalidArgumentException if $number is not a string or an int.
     *
     * @todo More comprehensive checks to make sure each suit as number is valid.
     */
    public function __construct($suit, $number) {
        if (!is_string($suit)) {
            throw new InvalidArgumentException(
                'First parameter to Card::__construct() must be a string.'
            );
        }

        if (!is_string($number) && !filter_var($number, FILTER_VALIDATE_INT)) {
            throw new InvalidArgumentException(
                'Second parameter to Card::__construct() must be a string or an int.'
            );
        }
        $this->suit = $suit;
        $this->number = $number;
    }

    /**
     * @return string The suit for the card;
     */
    public function suit() {
        return $this->suit;
    }

    /**
     * @return string The number for the card;
     */
    public function number() {
        return $this->number;
    }

    /**
     * Returns a string depicting the card. Although it's json_encoded, don't
     * rely on that fact.  PHP 5.4 introduces the JsonSerializeable interface,
     * which should be used to json_encode an object.
     *
     * @return string The Card as a string.
     */
    public function __toString() {
        return json_encode($this->jsonSerialize());
    }

    /**
     * Returns the data that should be encoded  into JSON.
     * @return array Return data which should be serialized by json_encode().
     */
    public function jsonSerialize() {
        return get_object_vars($this);
    }

}

class Deck implements IteratorAggregate, ArrayAccess, Countable, JsonSerializable {

    private $deck;

    /**
     * Creates a new, unshuffled deck of cards, where the suits are in the order
     * of diamonds, hearts, clubs, spades, and each suit is ordered A, 2 .. 10,
     * J, Q, K.
     *
     * @param array $deck [optional] The deck of cards to be used.
     * @throws InvalidArgumentException if the any of the elements in $deck are not type Card.
     */
    public function __construct(array $deck=null) {
        if (isset($deck) && count($deck) > 0) {
            foreach ($deck as $card) {
                if (!($card instanceof Card)) {
                    throw new InvalidArgumentException(
                        'The first parameter to Deck::__construct must be an array'
                            . ' containing only objects of type Card'
                    );
                }
            }
            $this->deck = $deck;
        } else {
            $this->deck = $this->createDeck();
        }
    }

    /**
     * Shuffle an array.  Uses PHP's shuffle if no function is provided. If a
     * function is provided, it must take an array of Cards as its only
     * parameter.
     * @param callable $function If $function isn't callable, shuffle will be used instead
     * @return mixed Returns the result of the shuffle function.
     */
    public function shuffle($function = null) {
        if (is_callable($function, false, $callable_name)) {
            return $callable_name($this->deck);
        } else {
            return shuffle($this->deck);
        }
    }

    /**
     * Used by IteratorAggregate to loop over the object.
     * @return ArrayIterator
     */
    public function getIterator() {
        return new ArrayIterator($this->deck);
    }

    /**
     * @param string $suit The suite to create.
     * @return array The cards for the suit.
     */
    private function createSuit($suit) {
        return array(
            new Card($suit, 'A'),
            new Card($suit, '2'),
            new Card($suit, '3'),
            new Card($suit, '4'),
            new Card($suit, '5'),
            new Card($suit, '6'),
            new Card($suit, '7'),
            new Card($suit, '8'),
            new Card($suit, '9'),
            new Card($suit, '10'),
            new Card($suit, 'J'),
            new Card($suit, 'Q'),
            new Card($suit, 'K')
        );
    }

    /**
     * Returns a new, unshuffled array of cards, where the suits are in the
     * order of diamonds, hearts, clubs, spades, and each suit is ordered:
     * A, 2 .. 10, J, Q, K.
     * @return array An array of type Card.
     */
    private function createDeck() {
        return array_merge(
            $this->createSuit('diamonds'),
            $this->createSuit('hearts'),
            $this->createSuit('clubs'),
            $this->createSuit('spades')
        );
    }

    /**
     * Resets the deck to an unshuffled order, and returns the deck.
     * @return \Deck
     */
    public function reset() {
        $this->deck = $this->createDeck();
        return $this;
    }

    /**
     * Returns the data that should be encoded into JSON. Note that any objects
     * inside must also be jsonSerialized for anything less than PHP 5.4.
     *
     * @return mixed Return data which should be serialized by json_encode().
     */
    public function jsonSerialize() {
        $array = $this->deck;

        foreach($array as &$card) {
            /**
             * @var Card $card
             */
            $card = $card->jsonSerialize();
        }

        return $array;
    }

    /**
     * Used by ArrayAccess.  Determine whether an offset(index) exists.
     * @param int $index The index to test for existence.
     * @return boolean Returns true of the offset exists.
     */
    public function offsetExists($index) {
        return array_key_exists($index, $this->deck);
    }

    /**
     * Used by ArrayAccess.  Returns an item from the index provided.
     * @param int $index The index to get..
     * @return boolean Returns the object at the location.
     * @throws OutOfBoundsException if you specify an index that does not exist.
     */
    public function offsetGet($index) {
        if (!$this->offsetExists($index)) {
            throw new OutOfBoundsException(
                "The index '$index' does not exist."
            );
        }
        return $this->deck[$index];
    }

    /**
     * Used by ArrayAccess. Sets an index with the value, or adds a value if it
     * is null.
     * @param int|null $index The index to set, or null to add.
     * @param Card $value The card to set/add.
     * @return void
     * @throws InvalidArgumentException if the value provided is not a Card.
     * @throws InvalidArgumentException if the index provided is not an integer.
     * @throws OutOfBoundsException if the index provided does not exist.
     */
    public function offsetSet($index, $value) {
        if (!($value instanceof Card))
            throw new InvalidArgumentException('Decks only contain cards.');

        if ($index == null) {
            $this->deck[] = $value;
            return;
        }

        if (!is_numeric($index) || $index != (int) $index) {
            throw new InvalidArgumentException("Index '$index' must be an integer.");
        }

        if (!$this->offsetExists($index)) {
            throw new OutOfBoundsException("Index '$index' does not exist");
        }

        $this->deck[$index] = $value;
    }

    /**
     * Unsets the index location.
     * @param int $index
     * @return void
     * @throws InvalidArgumentException if the index provided does not exist.
     */
    public function offsetUnset($index) {
        if (!$this->offsetExists($index)) {
            throw new InvalidArgumentException("Index '$index' Does not exist.");
        }

        array_splice($this->deck, $index, 1);
    }

    /**
     * Returns a string depicting the card. Although it's json_encoded, don't
     * rely on that fact.  PHP 5.4 introduces the JsonSerializeable interface,
     * which should be used to json_encode an object.
     *
     * @return string The Card as a string.
     */
    public function __toString() {
        return json_encode($this->jsonSerialize());
    }

    /**
     * Used by interface Count.
     * @return int The size of the deck.
     */
    function count() {
        return count($this->deck);
    }

}

header('Content-type:text/plain');

$deck = new Deck();

echo "Original Deck:\n";


foreach ($deck as $card) {
    echo $card . "\n";
}

$deck->shuffle();

echo "After Shuffle:\n";

foreach ($deck as $card) {
    echo $card . "\n";
}
/**
 * Shuffles the array using the Fisher-Yates algorithm.
 */
function fisherYatesShuffle(array &$items) {
    for ($i = count($items) - 1; $i > 0; $i--) {
        $j = @mt_rand(0, $i);
        $tmp = $items[$i];
        $items[$i] = $items[$j];
        $items[$j] = $tmp;
    }
}

$deck->shuffle('fisherYatesShuffle');


echo "Reset, then custom shuffle:\n";

foreach ($deck as $card) {
    echo $card . "\n";
}

echo "First card in the deck:";
echo $deck['0'] . "\n";

echo "Deck reset. __toString() on \$deck: ".$deck->reset()."\n";
0 голосов
/ 03 августа 2015
<?php
$a = rand(0 ,3);
suits = array('diamonds', 'hearts', 'clubs', 'spades');
$suit = $suits[$a];
$b = rand(0 ,12);
$v = array('Ace', '2', '3', '4', '5', '6', '7', '8', '9','10','Jack',  'Queen', 'King');
$value = $v[$b];
echo "You have selected the " . $value . " of " . $suit;
?>
0 голосов
/ 08 апреля 2015

Вы можете использовать многомерные ассоциативные массивы и заполнить второй слой 52 картами, а затем перетасовать массив колод следующим образом.Я сделал это только таким образом, чтобы я мог использовать значения, чтобы сравнить две руки блэкджека как числа и показать, кто имеет более высокие карты.

$deck = array(
  $a = array(
            'face'    => 'Ace',
            'value'   => 11,
            'suit'    => 'Spades'
  ),
  $b = array(
            'face'    => 'King',
            'value'   => 10,
            'suit'    => 'Spades'
  ),
  $c = array(
            'face'    => 'Queen',
            'value'   => 10,
            'suit'    => 'Spades'
  ),
  $d = array(
            'face'    => 'Jack',
            'value'   => 10,
            'suit'    => 'Spades'
  ),
  $e = array(
            'face'    => 'Ten',
            'value'   => 10,
            'suit'    => 'Spades'
  ),
  $f = array(
            'face'    => 'Nine',
            'value'   => 9,
            'suit'    => 'Spades'
  ),
  $g = array(
            'face'    => 'Eight',
            'value'   => 8,
            'suit'    => 'Spades'
  ),
  $h = array(
            'face'    => 'Seven',
            'value'   => 7,
            'suit'    => 'Spades'
  ),
  $i = array(
            'face'    => 'Six',
            'value'   => 6,
            'suit'    => 'Spades'
  ),
  $j = array(
            'face'    => 'Five',
            'value'   => 5,
            'suit'    => 'Spades'
  ),
  $k = array(
            'face'    => 'Four',
            'value'   => 4,
            'suit'    => 'Spades'
  ),
  $l = array(
            'face'    => 'Three',
            'value'   => 3,
            'suit'    => 'Spades'
  ),
  $m = array(
            'face'    => 'Two',
            'value'   => 2,
            'suit'    => 'Spades'
  ),
  $n = array(
            'face'    => 'Ace',
            'value'   => 11,
            'suit'    => 'Clubs'
  ),
  $o = array(
            'face'    => 'King',
            'value'   => 10,
            'suit'    => 'Clubs'
  ),
  $p = array(
            'face'    => 'Queen',
            'value'   => 10,
            'suit'    => 'Clubs'
  ),
  $q = array(
            'face'    => 'Jack',
            'value'   => 10,
            'suit'    => 'Clubs'
  ),
  $r = array(
            'face'    => 'Ten',
            'value'   => 10,
            'suit'    => 'Clubs'
  ),
  $s = array(
            'face'    => 'Nine',
            'value'   => 9,
            'suit'    => 'Clubs'
  ),
  $t = array(
            'face'    => 'Eight',
            'value'   => 8,
            'suit'    => 'Clubs'
  ),
  $u = array(
            'face'    => 'Seven',
            'value'   => 7,
            'suit'    => 'Clubs'
  ),
  $v = array(
            'face'    => 'Six',
            'value'   => 6,
            'suit'    => 'Clubs'
  ),
  $w = array(
            'face'    => 'Five',
            'value'   => 5,
            'suit'    => 'Clubs'
  ),
  $x = array(
            'face'    => 'Four',
            'value'   => 4,
            'suit'    => 'Clubs'
  ),
  $y = array(
            'face'    => 'Three',
            'value'   => 3,
            'suit'    => 'Clubs'
  ),
  $z = array(
            'face'    => 'Two',
            'value'   => 2,
            'suit'    => 'Clubs'
  ),
  $aa = array(
            'face'    => 'Ace',
            'value'   => 11,
            'suit'    => 'Diamonds'
  ),
  $ab = array(
            'face'    => 'King',
            'value'   => 10,
            'suit'    => 'Diamonds'
  ),
  $ac = array(
            'face'    => 'Queen',
            'value'   => 10,
            'suit'    => 'Diamonds'
  ),
  $ad = array(
            'face'    => 'Jack',
            'value'   => 10,
            'suit'    => 'Diamonds'
  ),
  $ae = array(
            'face'    => 'Ten',
            'value'   => 10,
            'suit'    => 'Diamonds'
  ),
  $af = array(
            'face'    => 'Nine',
            'value'   => 9,
            'suit'    => 'Diamonds'
  ),
  $ag = array(
            'face'    => 'Eight',
            'value'   => 8,
            'suit'    => 'Diamonds'
  ),
  $ah = array(
            'face'    => 'Seven',
            'value'   => 7,
            'suit'    => 'Diamonds'
  ),
  $ai = array(
            'face'    => 'Six',
            'value'   => 6,
            'suit'    => 'Diamonds'
  ),
  $aj = array(
            'face'    => 'Five',
            'value'   => 5,
            'suit'    => 'Diamonds'
  ),
  $ak = array(
            'face'    => 'Four',
            'value'   => 4,
            'suit'    => 'Diamonds'
  ),
  $al = array(
            'face'    => 'Three',
            'value'   => 3,
            'suit'    => 'Diamonds'
  ),
  $am = array(
            'face'    => 'Two',
            'value'   => 2,
            'suit'    => 'Diamonds'
  ),
  $an = array(
            'face'    => 'Ace',
            'value'   => 11,
            'suit'    => 'Hearts'
  ),
  $ao = array(
            'face'    => 'King',
            'value'   => 10,
            'suit'    => 'Hearts'
  ),
  $ap = array(
            'face'    => 'Queen',
            'value'   => 10,
            'suit'    => 'Hearts'
  ),
  $aq = array(
            'face'    => 'Jack',
            'value'   => 10,
            'suit'    => 'Hearts'
  ),
  $ar = array(
            'face'    => 'Ten',
            'value'   => 10,
            'suit'    => 'Hearts'
  ),
  $as = array(
            'face'    => 'Nine',
            'value'   => 9,
            'suit'    => 'Hearts'
  ),
  $at = array(
            'face'    => 'Eight',
            'value'   => 8,
            'suit'    => 'Hearts'
  ),
  $au = array(
            'face'    => 'Seven',
            'value'   => 7,
            'suit'    => 'Hearts'
  ),
  $av = array(
            'face'    => 'Six',
            'value'   => 6,
            'suit'    => 'Hearts'
  ),
  $aw = array(
            'face'    => 'Five',
            'value'   => 5,
            'suit'    => 'Hearts'
  ),
  $ax = array(
            'face'    => 'Four',
            'value'   => 4,
            'suit'    => 'Hearts'
  ),
  $ay = array(
            'face'    => 'Three',
            'value'   => 3,
            'suit'    => 'Hearts'
  ),
  $az = array(
            'face'    => 'Two',
            'value'   => 2,
            'suit'    => 'Hearts'
  ),
);
shuffle ($deck);
echo $deck[0]['face'] . ' of ' . $deck[0]['suit']
0 голосов
/ 21 октября 2013

Вот мой пример. Тянет случайную карту, затем есть кнопка Draw Again, которая вытягивает другую случайную карту.

//Matt's Deck - Random Card'
<?php
$cards = array("ah", "ac", "ad", "as",
               "2h", "2c", "2d", "2s",
               "3h", "3c", "3d", "3s",
               "4h", "4c", "4d", "4s",
               "5h", "5c", "5d", "5s",
               "6h", "6c", "6d", "6s",
               "7h", "7c", "7d", "7s",
               "8h", "8c", "8d", "8s",
               "9h", "9c", "9d", "9s",
               "th", "tc", "td", "ts",
               "jh", "jc", "jd", "js",
               "qh", "qc", "qd", "qs",
               "kh", "kc", "kd", "ks");
$deck = array_rand($cards);
switch ($deck){
    case '0': echo 'Ace of Hearts';
      break;
    case '1': echo 'Ace of Clubs';
      break;
    case '2': echo 'Ace of Diamonds';
      break;
    case '3': echo 'Ace of Spades';
      break;
    case '4': echo 'Two of Hearts';
      break;
    case '5': echo 'Two of Clubs';
      break;
    case '6': echo 'Two of Diamonds';
      break;
    case '7': echo 'Two of Spades';
      break;
    case '8': echo 'Three of Hearts';
      break;
    case '9': echo 'Three of Clubs';
      break;
    case '10': echo 'Three of Diamonds';
      break;
    case '11': echo 'Three of Spades';
      break;
    case '12': echo 'Four of Hearts';
      break;
    case '13': echo 'Four of Clubs';
      break;
    case '14': echo 'Four of Diamonds';
      break;
    case '15': echo 'Four of Spades';
      break;
    case '16': echo 'Five of Hearts';
      break;
    case '17': echo 'Five of Clubs';
      break;
    case '18': echo 'Five of Diamonds';
      break;
    case '19': echo 'Five of Spades';
      break;
    case '20': echo 'Six of Hearts';
      break;
    case '21': echo 'Six of Clubs';
      break;
    case '22': echo 'Six of Diamonds';
      break;
    case '23': echo 'Six of Spades';
      break;
    case '24': echo 'Seven of Hearts';
      break;
    case '25': echo 'Seven of Clubs';
      break;
    case '26': echo 'Seven of Diamonds';
      break;
    case '27': echo 'Seven of Spades';
      break;
    case '28': echo 'Eight of Hearts';
      break;
    case '29': echo 'Eight of Clubs';
      break;
    case '30': echo 'Eight of Diamonds';
      break;
    case '31': echo 'Eight of Spades';
      break;
    case '32': echo 'Nine of Hearts';
      break;
    case '33': echo 'Nine of Clubs';
      break;
    case '34': echo 'Nine of Diamonds';
      break;
    case '35': echo 'Nine of Spades';
      break;
    case '36': echo 'Ten of Hearts';
      break;
    case '37': echo 'Ten of Clubs';
      break;
    case '38': echo 'Ten of Diamonds';
      break;
    case '39': echo 'Ten of Spades';
      break;
    case '40': echo 'Jack of Hearts';
      break;
    case '41': echo 'Jack of Clubs';
      break;
    case '42': echo 'Jack of Diamonds';
      break;
    case '43': echo 'Jack of Spades';
      break;
    case '44': echo 'Queen of Hearts';
      break;
    case '45': echo 'Queen of Clubs';
      break;
    case '46': echo 'Queen of Diamonds';
      break;
    case '47': echo 'Queen of Spades';
      break;
    case '48': echo 'King of Hearts';
      break;
    case '49': echo 'King of Clubs';
      break;
    case '50': echo 'King of Diamonds';
      break;
    case '51': echo 'King of Spades';
}
?>
<form><input type=button value="Draw Again" onClick="window.location.reload()"></form>

// End Matt's Deck - Random Card
0 голосов
/ 25 октября 2011

Сначала определите количество карточек:

$numberOfCards = array_sum(array_map('count', $cards));

Затем создайте и перемешайте массив индексов:

$indexes = range(0, $numberOfCards);
shuffle($indexes);

Наконец, возьмите числа из индексов и используйте связанную карту:

foreach ($indexes as $idx) {
   foreach ($cards as $name=>$color) {
     if ($idx < count($color)) {
        $card = $color[$idx];
        echo 'Draw: ' . $card . ' of ' . $color . "\n";
        break;
     }
     $idx -= count($color);
   }
}
...